diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..0fbd99b79 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,25 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module', + }, + plugins: ['@typescript-eslint/eslint-plugin'], + extends: [ + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + 'prettier/@typescript-eslint', + ], + root: true, + env: { + node: true, + jest: true, + }, + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, +}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..61c651ea1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..21890acf9 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,12 @@ +config: + - ./* +tooling: + - tooling/**/*.* +assets: + - static/**/*.* +tests: + - any: ["src/**/*.spec.js", "cypress/**/*"] +package: + - any: ["package.json", "package-lock.json"] +source: + - src/**/* diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 000000000..705bb1f48 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,35 @@ +name: Merge PRs +on: + pull_request: + types: + - labeled + - synchronize + - opened + - edited + - ready_for_review + - reopened + - unlocked + pull_request_review: + types: + - submitted +jobs: + automerge: + runs-on: ubuntu-latest + steps: + - name: Automerge + uses: pascalgn/automerge-action@v0.12.0 + env: + GITHUB_TOKEN: "${{ secrets.GH_PAT }}" + MERGE_LABELS: "merge,!work in progress,!wip" + MERGE_REMOVE_LABELS: "merge" + MERGE_METHOD: "merge" + MERGE_COMMIT_MESSAGE: ":twisted_rightwards_arrows: Merge #{pullRequest.number} ({pullRequest.title})" + MERGE_FORKS: false + UPDATE_LABELS: "merge" + UPDATE_METHOD: "merge" + - name: Delete merged branch + uses: koj-co/delete-merged-action@master + with: + branches: "!master, !production, *" + env: + GITHUB_TOKEN: "${{ secrets.GH_PAT }}" diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000..8d10a0ea7 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,18 @@ +name: Pull Request Labeler +on: + - pull_request + - pull_request_review +jobs: + triage: + runs-on: ubuntu-latest + steps: + - name: Label all PRs + uses: actions/labeler@master + with: + repo-token: "${{ secrets.GH_PAT }}" + - name: Label approved PRs + uses: koj-co/label-approved-action@master + with: + labels: "merge" + env: + GITHUB_TOKEN: "${{ secrets.GH_PAT }}" diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml new file mode 100644 index 000000000..028809b0d --- /dev/null +++ b/.github/workflows/node.yml @@ -0,0 +1,60 @@ +name: Node CI +on: + push: + branches: + - master +jobs: + release: + name: Build, test, and release + runs-on: ubuntu-18.04 + if: "!contains(github.event.head_commit.message, '[skip ci]')" + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + - name: Setup Node.js + uses: actions/setup-node@v2.1.2 + with: + node-version: 14 + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: javascript + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Install dependencies + run: npm ci + - name: Build TypeScript + run: npm run build + - name: Run tests + run: npm run test + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + - name: Release + run: npx semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_AUTHOR_NAME: 'FindingAnand' + GIT_AUTHOR_EMAIL: 'bot@anandchowdhary.com' + GIT_COMMITTER_NAME: 'FindingAnand' + GIT_COMMITTER_EMAIL: 'bot@anandchowdhary.com' + - name: Add PR comment + uses: actions/github-script@v3 + if: always() && steps.licensed.outputs.pr_number + with: + github-token: ${{ secrets.GH_PAT }} + script: | + github.issues.createComment({ + ...context.repo, + issue_number: ${{ steps.licensed.outputs.pr_number }} + body: "I've checked the license of your new dependency and it looks good!" + }) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 000000000..997d0173c --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,74 @@ +name: PR Generator CI +on: + push: + branches-ignore: + - master + - production +jobs: + auto-pull-request: + name: PullRequestAction + runs-on: ubuntu-latest + steps: + - name: Generate branch name + uses: actions/github-script@v3 + id: set-branch-name + with: + script: | + const capitalize = (name) => name.charAt(0).toUpperCase() + name.slice(1); + const emoji = context.payload.ref.startsWith("refs/heads/feature") + ? "✨ " + : context.payload.ref.startsWith("refs/heads/hotfix") + ? "🚑 " + : context.payload.ref.startsWith("refs/heads/bug") + ? "🐛 " + : ""; + return `${emoji}${capitalize( + context.payload.ref + .replace("refs/heads/", "") + .replace(/-/g, " ") + .replace("feature ", "") + .replace("bug ", "") + .replace("hotfix ", "") + )}`; + result-encoding: string + - name: Set branch name + run: echo "PULL_REQUEST_TITLE=${{steps.set-branch-name.outputs.result}}" >> $GITHUB_ENV + - name: Generate PR body + uses: actions/github-script@v3 + id: set-pr-body + with: + script: | + return `I'm opening this pull request for this branch, pushed by @${ + context.payload.head_commit.author.username + } with ${context.payload.commits.length} commit${ + context.payload.commits.length === 1 ? "" : "s" + }.`; + result-encoding: string + - name: Set PR body + run: echo "PULL_REQUEST_BODY=${{steps.set-pr-body.outputs.result}}" >> $GITHUB_ENV + - name: Generate PR draft + uses: actions/github-script@v3 + id: set-pr-draft + with: + script: | + return !context.payload.ref.startsWith("refs/heads/hotfix"); + - name: Set PR draft + run: echo "PULL_REQUEST_DRAFT=${{steps.set-pr-draft.outputs.result}}" >> $GITHUB_ENV + - name: Determine whether to merge + uses: actions/github-script@v3 + id: should-pr + with: + github-token: ${{ secrets.GH_PAT }} + script: | + console.log(context.payload.ref); + return + context.payload.ref.startsWith("refs/heads/feature") || + context.payload.ref.startsWith("refs/heads/hotfix") || + context.payload.ref.startsWith("refs/heads/bug"); + - name: pull-request-action + uses: vsoch/pull-request-action@1.0.11 + if: always() && steps.should-pr.outputs.result + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + PULL_REQUEST_BRANCH: 'master' + PULL_REQUEST_REVIEWERS: 'AnandChowdhary' diff --git a/.github/workflows/release-scheduler.yml b/.github/workflows/release-scheduler.yml new file mode 100644 index 000000000..466e0219a --- /dev/null +++ b/.github/workflows/release-scheduler.yml @@ -0,0 +1,13 @@ +name: Release Scheduler CI +on: + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: +jobs: + releaseScheduler: + runs-on: ubuntu-latest + steps: + - name: Run release-scheduler + uses: koj-co/release-scheduler@master + env: + GH_PAT: ${{ secrets.GH_PAT }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..dcd6e8b9e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: "Stale Issues CI" +on: + schedule: + - cron: "0 0 * * *" +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GH_PAT }} + stale-issue-message: "⚠️ This issue has not seen any activity in the past 2 months so I'm marking it as stale. I'll close it if it doesn't see any activity in the coming week." + stale-pr-message: "⚠️ This PR has not seen any activity in the past 2 months so I'm marking it as stale. I'll close it if it doesn't see any activity in the coming week." + days-before-stale: 60 + days-before-close: 7 + stale-issue-label: "wontfix" + exempt-issue-labels: "wip" + stale-pr-label: "wontfix" + exempt-pr-labels: "wip" diff --git a/.github/workflows/branch.yml b/.github/workflows/test.yml similarity index 59% rename from .github/workflows/branch.yml rename to .github/workflows/test.yml index 3bcc3618c..4304a0aba 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,8 @@ -name: Node CI -on: [push] +name: Test CI +on: + push: + branches-ignore: + - master jobs: release: name: Build and test @@ -7,14 +10,14 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2.3.4 - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v2.1.2 with: - node-version: 12 + node-version: 14 - name: Install dependencies run: npm ci - - name: Generate Prisma schema - run: npx prisma generate - name: Build TypeScript run: npm run build + - name: Run tests + run: npm run test diff --git a/.gitignore b/.gitignore index 7ab142976..9def7e12c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,7 @@ -# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig +# compiled output +/dist +/node_modules -# Created by https://www.gitignore.io/api/macos,visualstudiocode,node -# Edit at https://www.gitignore.io/?templates=macos,visualstudiocode,node - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Node ### # Logs logs *.log @@ -40,104 +10,28 @@ yarn-debug.log* yarn-error.log* lerna-debug.log* -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ +# OS +.DS_Store -# FuseBox cache -.fusebox/ +# Tests +/coverage +/.nyc_output -# DynamoDB Local files -.dynamodb/ +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace -### VisualStudioCode ### +# IDE - VSCode .vscode/* +!.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -# End of https://www.gitignore.io/api/macos,visualstudiocode,node - -# Custom rules (everything added below won't be overridden by 'Generate .gitignore File' if you use 'Update' option) - -# Built files -dist/ -src/app.ts -.staart/ - -# Environment variables -*.env - -# Redis dump -dump.rdb +# Dotenv +.env diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..dcb72794f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/.staartrc.json b/.staartrc.json deleted file mode 100644 index e8042467a..000000000 --- a/.staartrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "controllerPrefix": "v1", - "frontendUrl": "https://staart-ui.netlify.app", - "registerGenderPrediction": true, - "registerLocationDetection": true, - "enableStripePayments": true, - "trackAuditLogData:": true, - "trackRequestData:": true, - "newUserRegistrations": true, - "testEmail": "staart@mailinator.com", - "allowDisposableEmails": false, - "jwtIssuer": "staart", - "tokenExpiryApproveLocation": "15m", - "tokenExpiryEmailVerification": "30d", - "tokenExpiryLogin": "1h", - "tokenExpiryPasswordReset": "15m", - "tokenExpiryRefresh": "30d" -} diff --git a/.templaterc.json b/.templaterc.json deleted file mode 100644 index 8de59c041..000000000 --- a/.templaterc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files": [".github/**/*", "src/**/*"], - "npmDependencies": true, - "npmScripts": true -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index dea5fb3ea..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,104 +0,0 @@ -# Contributing - -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. - -Please note we have a code of conduct, please follow it in all your interactions with the project. - -## Pull Request Process - -1. When making commits, make sure you are using [Gitmoji](https://github.com/carloscuesta/gitmoji). -2. Ensure any install or build dependencies are removed before the end of the layer when doing a - build. -3. Update the README.md with details of changes to the interface, this includes new environment - variables, exposed ports, useful file locations and container parameters. -4. Increase the version numbers in any examples files and the README.md to the new version that this - Pull Request would represent. We increase the patch version in every commit to ensure people - using Staart are always on the most recent version using our internal update system. -5. You may merge the Pull Request in once you have the review sign-off of Anand Chowdhary, or if you - do not have permission to do that, you may request a reviewer to merge it for you. - -## Code of Conduct - -### Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -### Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -### Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -### Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -### Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at `staart@o15y.com`. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -### Support - -This is not an official product from [Oswald Labs][oswald-labs] or [O15Y][o15y] -and therefore is not under any of their Service Level Agreements (SLA) or support -agreements. You are free to open an issue for support from the community. - -### Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version]. These contributing -guidelines are adapted from [@PurpleBooth's template][gct]. - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ -[gct]: https://gist.github.com/PurpleBooth/b24679402957c63ec426 -[oswald-labs]: https://oswaldlabs.com -[o15y]: https://o15y.com diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 210afb285..000000000 --- a/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:14.9.0-alpine3.12 -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app -COPY package*.json /usr/src/app/ -COPY ./ /usr/src/app -RUN npm install -ENV NODE_ENV production -ENV PORT 80 -EXPOSE 80 -RUN ["npm", "run", "build"] -RUN ["npx", "prisma", "generate"] -CMD ["npm", "run", "launch"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index b5afa4aa5..000000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Anand Chowdhary - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 3fddd5114..270d3bcf3 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ Staart API is a Node.js backend starter for SaaS startups written in TypeScript. Staart API is build to work with [Staart UI](https://github.com/staart/ui), the frontend PWA starter for SaaS startups. -**⚠️ v2 BETA WARNING:** The `master` branch and all 2.x releases are currently in beta. For production, use v1.x instead. +**⚠️ v3 BETA WARNING:** The `master` branch and all 3.x releases are currently in beta. For production, use v1.x instead. ## ⭐ Features -### 🆕 New in beta +### 🆕 New in v2 - Casbin-powered permission management - JWT-powered single-use coupon codes diff --git a/captain-definition b/captain-definition deleted file mode 100644 index 0e14f8239..000000000 --- a/captain-definition +++ /dev/null @@ -1,4 +0,0 @@ -{ - "schemaVersion": 2, - "dockerfilePath": "./Dockerfile" -} diff --git a/casbin-model.conf b/casbin-model.conf deleted file mode 100644 index cee256616..000000000 --- a/casbin-model.conf +++ /dev/null @@ -1,11 +0,0 @@ -[request_definition] -r = sub, obj, act - -[policy_definition] -p = sub, obj, act - -[policy_effect] -e = some(where (p.eft == allow)) - -[matchers] -m = r.sub == p.sub && r.obj == p.obj && r.act == p.act diff --git a/docs/3-config.md b/docs/3-config.md deleted file mode 100644 index 41a837d17..000000000 --- a/docs/3-config.md +++ /dev/null @@ -1,9 +0,0 @@ -controllerPrefix -frontendUrl -registerGenderPrediction -registerLocationDetection -enableStripePayments -trackAuditLogData -trackRequestData -newUserRegistrations -newUserRegistrationDomains diff --git a/docs/authentication.md b/docs/authentication.md new file mode 100644 index 000000000..5d3bbd658 --- /dev/null +++ b/docs/authentication.md @@ -0,0 +1,34 @@ +# Authentication + +To authenticate users, an email/password combination is used. Alternate options include passwordless login, two-factor authentication, and custom SAML-based login. On successful login, an access token and refresh token is provided. The access token is a JWT with a default expiration period of 1 hour, and the refresh token is a UUID stored in the database that never expires (but can be deleted by the user). + +## Public routes + +By default, all endpoints required authentication. The `@Public()` decorator can be used on a controller or specific route to skip authentication. By default, all auth routes (for example, logging in and registration) don't require authentication: + +```ts +@Controller('auth') +@Public() +export class AuthController { + constructor() {} +} +``` + +You can also make a single route public: + +```ts +@Controller('example') +export class ExampleController { + constructor() {} + + @Get('public') + @Public() // The route /example/public is public + async example(): Promise { + return true; + } +} +``` + +## Under the hood + +The `Public()` decorator was proposed in [nestjs/nest/#5598](https://github.com/nestjs/nest/issues/5598) as a solution to the lack of reorderability of Guards in Nest. diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 000000000..3fe9d37ba --- /dev/null +++ b/docs/database.md @@ -0,0 +1,35 @@ +# Database + +Staart uses [prisma/prisma](https://github.com/prisma/prisma) under the hood, which is a modern ORM alternative. You can ues any of the databases supported by Prisma: PostgreSQL, MySQL, or SQLite. Support for Microsoft SQL Server is also in beta. Your database should already be created before setting up the connection. + +## Database connection + +To get started, add the required required environment variables in your `.env` file. The `DATABASE_URL` variable is usually set with [dotenv-expand](https://github.com/motdotla/dotenv-expand) variables: + +```env title=".env" +DATABASE_URL = "${DB_PROVIDER}://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_POST}/${DB_NAME}" +``` + +Then, you can set the individual environment variables: + +| Environment variable | Description | +| -------------------- | -------------------------------- | +| `DB_PROVIDER` | Database provider, e.g., "mysql" | +| `DB_USER` | Username | +| `DB_PASSWORD` | Password | +| `DB_HOST` | Hostname | +| `DB_POST` | Database port, e.g., 3306 | +| `DB_NAME` | Databse name to use | + +Alternately, you can also set the `DATABASE_URL` variable directly. For more information about this connection, you can visit the article on the Prisma website: [Using environment variables](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema#using-environment-variables). + +## Setting up + +When you're setting your database for the first time, you should use the `prisma migrate` command: + +``` +npx prisma migrate save --experimental +npx prisma migrate up --experimental +``` + +You can learn more about the `migrate` command on the documentatino page: [Prisma Migrate](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-migrate). diff --git a/docs/2-environment-variables.md b/docs/environment-variables.md similarity index 99% rename from docs/2-environment-variables.md rename to docs/environment-variables.md index f7522753c..3db327b0e 100644 --- a/docs/2-environment-variables.md +++ b/docs/environment-variables.md @@ -1,4 +1,4 @@ -# Setting up environment variables +# Eenvironment variables All environment variables are stored in a `.env` file locally. All environment variables are optional. diff --git a/docs/1-getting-started.md b/docs/get-started.md similarity index 100% rename from docs/1-getting-started.md rename to docs/get-started.md diff --git a/docs/scopes.md b/docs/scopes.md new file mode 100644 index 000000000..d4d1dad2f --- /dev/null +++ b/docs/scopes.md @@ -0,0 +1,64 @@ +# Authorization with scopes + +The `@Scopes()` decorator is used on routes to ensure scope-based authorization. To better understand how Staart works with scopes in routes, let's look at the controller for a user's emails: + +```ts +@Controller('users/:userId/emails') +export class EmailController { + constructor(private emailsService: EmailsService) {} + @Get(':id') + @Scopes('user-{userId}:read-email-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.emailsService.getEmail(userId, Number(id)); + } +} +``` + +In line 5 of the above code snippet, the scope for this endpoints is `@Scopes('user-{userId}:read-email-{id}')`. The route parameters `userId` and `id` will be replaced with their values. For example, for a user with ID 123 to get an email with ID 456, the scope required is `user-123:read-email-456`. + +## Glob matching + +The scope provided to a user (with ID 123, for example) when logging in to their account is `user-123:*`. Staart uses glob-based matching to ensure their have access to authorized routes. + +In the above example, the user can access this resource because `user-123:*` matches `user-123:read-email-456`. + +When creating personal access tokens using the interface or API, users can control which scopes they want access to. The above example scope `user-123:read-email-456` will be successfully matched by any of these values: + +| Scope | Access to | +| ------------------------- | --------------------------------------------- | +| `user-123:read-email-456` | Read only this particular email | +| `user-123:read-email-*` | Read all emails for this user | +| `user-123:read-*` | Read all resources for this user | +| `user-123:*` | Read/write/delete all resources for this user | + +There are also superuser scopes that are not available as personal access token scopes, but can be manually granted. These will, for example, also match this scope: + +| Scope | Access to | +| --------------------- | --------------------------------------------- | +| `user-*:read-email-*` | Read all emails for all users | +| `user-*:read-*` | Read all resources for all users | +| `user-*:*` | Read/write/delete all resources for all users | +| `*` | Read/write/delete all resources | + +## `@Scopes()` decorator + +The decorator can be used to which scopes a route requires. + +Like mentioned above, the scopes decorator automatically replaces any route params in curly braces (`{}`): + +```ts +@Scopes('user-{userId}:read-email-{id}') // user-123:read-email-456 +``` + +Multiple scopes can also be specified, and permission will be granted if at least one of these scopes are matched: + +```ts +@Scopes('user-{userId}:read-email-{id}', 'another-scope') +``` + +## Under the hood + +The [`scope.guard.ts`](/src/modules/auth/scope.guard.ts) file contains the source code for this Guard. The matching utility [minimatch](https://github.com/isaacs/minimatch) is used to compare scopes, which in turn works by converting glob expressions into regular expressions. diff --git a/http/create-access-token.http b/http/create-access-token.http new file mode 100644 index 000000000..73bac4c0f --- /dev/null +++ b/http/create-access-token.http @@ -0,0 +1,10 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +POST {{baseUrl}}/users/{{userId}}/access-tokens +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} + +{ + "scopes": ["user-1:read-info"] +} diff --git a/http/create-api-key.http b/http/create-api-key.http new file mode 100644 index 000000000..2567e2495 --- /dev/null +++ b/http/create-api-key.http @@ -0,0 +1,10 @@ +@baseUrl = http://localhost:3000/v1 +@groupId = 1 + +POST {{baseUrl}}/groups/{{groupId}}/api-keys +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} + +{ + "scopes": ["group-1:*"] +} diff --git a/http/create-group.http b/http/create-group.http new file mode 100644 index 000000000..9c95ab5b8 --- /dev/null +++ b/http/create-group.http @@ -0,0 +1,10 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +POST {{baseUrl}}/users/{{userId}}/memberships +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} + +{ + "name": "Koj" +} diff --git a/http/get-access-token-scopes.http b/http/get-access-token-scopes.http new file mode 100644 index 000000000..9d617d7df --- /dev/null +++ b/http/get-access-token-scopes.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +GET {{baseUrl}}/users/{{userId}}/access-tokens/scopes +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} diff --git a/http/get-access-tokens.http b/http/get-access-tokens.http new file mode 100644 index 000000000..b1eae9e0a --- /dev/null +++ b/http/get-access-tokens.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +GET {{baseUrl}}/users/{{userId}}/access-tokens +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} diff --git a/http/get-group-with-api-key.http b/http/get-group-with-api-key.http new file mode 100644 index 000000000..4cca35822 --- /dev/null +++ b/http/get-group-with-api-key.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@groupId = 1 + +GET {{baseUrl}}/groups/{{groupId}} +content-type: application/json +X-Api-Key: {{$dotenv HTTP_TEST_API_KEY}} diff --git a/http/get-group.http b/http/get-group.http new file mode 100644 index 000000000..6dde193bf --- /dev/null +++ b/http/get-group.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@groupId = 1 + +GET {{baseUrl}}/groups/{{groupId}} +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} diff --git a/http/get-user-with-access-token.http b/http/get-user-with-access-token.http new file mode 100644 index 000000000..287e12f29 --- /dev/null +++ b/http/get-user-with-access-token.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +GET {{baseUrl}}/users/{{userId}} +content-type: application/json +X-Access-Token: {{$dotenv HTTP_TEST_USER_ACCESS_TOKEN}} diff --git a/http/get-user.http b/http/get-user.http new file mode 100644 index 000000000..a4e5d31a0 --- /dev/null +++ b/http/get-user.http @@ -0,0 +1,6 @@ +@baseUrl = http://localhost:3000/v1 +@userId = 1 + +GET {{baseUrl}}/users/{{userId}} +content-type: application/json +Authorization: Bearer {{$dotenv HTTP_TEST_ACCESS_TOKEN}} diff --git a/http/login.http b/http/login.http new file mode 100644 index 000000000..ab9c9936d --- /dev/null +++ b/http/login.http @@ -0,0 +1,9 @@ +@baseUrl = http://localhost:3000/v1 + +POST {{baseUrl}}/auth/login +content-type: application/json + +{ + "email": "staart@anandchowdhary.com", + "password": "{{$dotenv HTTP_TEST_PASSWORD}}" +} diff --git a/http/refresh.http b/http/refresh.http new file mode 100644 index 000000000..83d5d8a34 --- /dev/null +++ b/http/refresh.http @@ -0,0 +1,8 @@ +@baseUrl = http://localhost:3000/v1 + +POST {{baseUrl}}/auth/refresh +content-type: application/json + +{ + "token": "{{$dotenv HTTP_TEST_REFRESH_TOKEN}}" +} diff --git a/http/register.http b/http/register.http new file mode 100644 index 000000000..208526fa8 --- /dev/null +++ b/http/register.http @@ -0,0 +1,10 @@ +@baseUrl = http://localhost:3000/v1 + +POST {{baseUrl}}/auth/register +content-type: application/json + +{ + "name": "Anand Chowdhary", + "email": "staart@anandchowdhary.com", + "password": "{{$dotenv HTTP_TEST_PASSWORD}}" +} diff --git a/http/verify-email.http b/http/verify-email.http new file mode 100644 index 000000000..bd008a970 --- /dev/null +++ b/http/verify-email.http @@ -0,0 +1,8 @@ +@baseUrl = http://localhost:3000/v1 + +POST {{baseUrl}}/auth/verify-email +content-type: application/json + +{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjA0NDA1NTc5LCJleHAiOjE2MDUwMTAzNzksInN1YiI6IkVNQUlMX1ZFUklGWV9UT0tFTiJ9.XHKCmXt142YH-rDnUFrzcvxGfHWA6njVfixZ-cQuoSo" +} diff --git a/nest-cli.json b/nest-cli.json new file mode 100644 index 000000000..2e1000f0d --- /dev/null +++ b/nest-cli.json @@ -0,0 +1,7 @@ +{ + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "plugins": ["@nestjs/swagger/plugin"] + } +} diff --git a/package-lock.json b/package-lock.json index ccf1cb1f1..121f55fc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,162 @@ { - "name": "@staart/api", + "name": "api", "version": "2.21.0", "lockfileVersion": 1, "requires": true, "dependencies": { - "@anandchowdhary/cosmic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@anandchowdhary/cosmic/-/cosmic-1.0.1.tgz", - "integrity": "sha512-faM5jhW9Ta2cvZMKaxFuuL+ZMrq9dnXylaj6VEFrHax/zCukkGO5eqbEJK5TjdtV/ZuCst/0OF22ZtP7GLEKDg==", + "@angular-devkit/core": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.2.0.tgz", + "integrity": "sha512-XAszFhSF3mZw1VjoOsYGbArr5NJLcStjOvcCGjBPl1UBM2AKpuCQXHxI9XJGYKL3B93Vp5G58d8qkHvamT53OA==", + "dev": true, "requires": { - "cosmiconfig": "^6.0.0", - "dotenv": "^8.2.0", - "lodash.camelcase": "^4.3.0" + "ajv": "6.12.4", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.2", + "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", + "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, - "@babel/cli": { - "version": "7.11.6", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.11.6.tgz", - "integrity": "sha512-+w7BZCvkewSmaRM6H4L2QM3RL90teqEIHDIFXAmrW33+0jhlymnDAEdqVeCZATvxhQuio1ifoGVlJJbIiH9Ffg==", + "@angular-devkit/schematics": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.2.0.tgz", + "integrity": "sha512-TQI5NnE6iM3ChF5gZQ9qb+lZgMWa7aLoF5ksOyT3zrmOuICiQYJhA6SsjV95q7J4M55qYymwBib8KTqU/xuQww==", + "dev": true, "requires": { - "chokidar": "^2.1.8", - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "lodash": "^4.17.19", - "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" + "@angular-devkit/core": "10.2.0", + "ora": "5.0.0", + "rxjs": "6.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ora": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.0.0.tgz", + "integrity": "sha512-s26qdWqke2kjN/wC4dy+IQPBIMWBJlSU/0JZhk30ZDBLelW25rv66yutUWARMigpGPzcXHb+Nac5pNhN/WsARw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.4.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "rxjs": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", + "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics-cli": { + "version": "0.1002.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-0.1002.0.tgz", + "integrity": "sha512-wV5YPdcolPAXo5oyMu9vM3fm3grb3ZT9amrTMC9oc3OWQUVFySPCIzvguHf8bVGMQ/AHfel2TaYxIQv/LurBrQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "10.2.0", + "@angular-devkit/schematics": "10.2.0", + "@schematics/schematics": "0.1002.0", + "inquirer": "7.3.3", + "minimist": "1.2.5", + "rxjs": "6.6.2", + "symbol-observable": "1.2.0" + }, + "dependencies": { + "rxjs": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", + "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@babel/code-frame": { @@ -38,16 +167,6 @@ "@babel/highlight": "^7.10.4" } }, - "@babel/compat-data": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", - "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", - "requires": { - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "semver": "^5.5.0" - } - }, "@babel/core": { "version": "7.12.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", @@ -72,204 +191,68 @@ "source-map": "^0.5.0" }, "dependencies": { - "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", - "dev": true, - "requires": { - "@babel/types": "^7.12.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", - "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", - "dev": true, - "requires": { - "@babel/types": "^7.12.1" - } - }, - "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.5" - } - }, - "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" - } - }, - "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" - } - }, - "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "ms": "2.1.2" } }, - "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "minimist": "^1.2.5" } }, - "@babel/parser": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", - "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "@babel/traverse": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", - "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.5", - "@babel/types": "^7.12.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, - "@babel/types": { - "version": "7.12.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", - "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true } } }, "@babel/generator": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", - "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "dev": true, "requires": { - "@babel/types": "^7.11.0", + "@babel/types": "^7.12.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", - "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", - "requires": { - "@babel/compat-data": "^7.10.4", - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "levenary": "^1.1.1", - "semver": "^5.5.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", - "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.10.5", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", - "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.0" - } - }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.11.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz", - "integrity": "sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==", - "requires": { - "@babel/types": "^7.10.4" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helper-function-name": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.10.4", "@babel/template": "^7.10.4", @@ -280,45 +263,43 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", - "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", + "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", + "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.1" } }, "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", - "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.5" } }, "@babel/helper-module-transforms": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", - "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "dev": true, "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", "@babel/template": "^7.10.4", - "@babel/types": "^7.11.0", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", "lodash": "^4.17.19" } }, @@ -326,6 +307,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -333,59 +315,35 @@ "@babel/helper-plugin-utils": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", - "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", - "requires": { - "lodash": "^4.17.19" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.11.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz", - "integrity": "sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true }, "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", - "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.12.1", "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", - "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", - "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.1" } }, "@babel/helper-split-export-declaration": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, "requires": { "@babel/types": "^7.11.0" } @@ -395,25 +353,15 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, - "@babel/helper-wrap-function": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", - "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, "@babel/helpers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", - "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, "requires": { "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "@babel/highlight": { @@ -427,202 +375,52 @@ } }, "@babel/parser": { - "version": "7.11.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz", - "integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==" + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", + "dev": true }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", - "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-proposal-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", - "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-proposal-decorators": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz", - "integrity": "sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ==", + "@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-decorators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.10.4" } }, - "@babel/plugin-proposal-dynamic-import": { + "@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", - "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" + "@babel/helper-plugin-utils": "^7.10.4" } }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", - "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", - "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", - "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", - "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", - "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", - "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.10.4" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", - "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", - "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", - "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", - "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", - "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz", - "integrity": "sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -631,6 +429,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -639,6 +438,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -647,6 +447,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -655,6 +456,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -663,6 +465,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -671,632 +474,199 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", - "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz", - "integrity": "sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", - "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", - "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoped-functions": { + "@babel/template": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", - "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz", - "integrity": "sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" } }, - "@babel/plugin-transform-classes": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", - "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "@babel/traverse": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", + "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "globals": "^11.1.0" + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.5", + "@babel/types": "^7.12.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "@babel/plugin-transform-computed-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", - "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" } }, - "@babel/plugin-transform-destructuring": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", - "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", - "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" } }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", - "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "@eslint/eslintrc": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", + "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", + "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", - "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } } }, - "@babel/plugin-transform-for-of": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", - "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", - "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", - "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", - "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", - "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", - "requires": { - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", - "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", - "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", - "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", - "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", - "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", - "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", - "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", - "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", - "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", - "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", - "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.5.tgz", - "integrity": "sha512-9aIoee+EhjySZ6vY5hnLjigHzunBlscx9ANKutkeWTJTx6m5Rbq6Ic01tLvO54lSusR+BxV7u4UDdCmXv5aagg==", - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", - "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", - "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", - "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-regex": "^7.10.4" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", - "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", - "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz", - "integrity": "sha512-edJsNzTtvb3MaXQwj8403B7mZoGu9ElDJQZOKjGUnvilquxBA3IQoEIOvkX/1O8xfAsnHS/oQhe2w/IXrr+w0w==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-typescript": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", - "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", - "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/polyfill": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz", - "integrity": "sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g==", - "requires": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/preset-env": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz", - "integrity": "sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==", - "requires": { - "@babel/compat-data": "^7.11.0", - "@babel/helper-compilation-targets": "^7.10.4", - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-proposal-async-generator-functions": "^7.10.4", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-dynamic-import": "^7.10.4", - "@babel/plugin-proposal-export-namespace-from": "^7.10.4", - "@babel/plugin-proposal-json-strings": "^7.10.4", - "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", - "@babel/plugin-proposal-numeric-separator": "^7.10.4", - "@babel/plugin-proposal-object-rest-spread": "^7.11.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", - "@babel/plugin-proposal-optional-chaining": "^7.11.0", - "@babel/plugin-proposal-private-methods": "^7.10.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.10.4", - "@babel/plugin-transform-arrow-functions": "^7.10.4", - "@babel/plugin-transform-async-to-generator": "^7.10.4", - "@babel/plugin-transform-block-scoped-functions": "^7.10.4", - "@babel/plugin-transform-block-scoping": "^7.10.4", - "@babel/plugin-transform-classes": "^7.10.4", - "@babel/plugin-transform-computed-properties": "^7.10.4", - "@babel/plugin-transform-destructuring": "^7.10.4", - "@babel/plugin-transform-dotall-regex": "^7.10.4", - "@babel/plugin-transform-duplicate-keys": "^7.10.4", - "@babel/plugin-transform-exponentiation-operator": "^7.10.4", - "@babel/plugin-transform-for-of": "^7.10.4", - "@babel/plugin-transform-function-name": "^7.10.4", - "@babel/plugin-transform-literals": "^7.10.4", - "@babel/plugin-transform-member-expression-literals": "^7.10.4", - "@babel/plugin-transform-modules-amd": "^7.10.4", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "@babel/plugin-transform-modules-systemjs": "^7.10.4", - "@babel/plugin-transform-modules-umd": "^7.10.4", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", - "@babel/plugin-transform-new-target": "^7.10.4", - "@babel/plugin-transform-object-super": "^7.10.4", - "@babel/plugin-transform-parameters": "^7.10.4", - "@babel/plugin-transform-property-literals": "^7.10.4", - "@babel/plugin-transform-regenerator": "^7.10.4", - "@babel/plugin-transform-reserved-words": "^7.10.4", - "@babel/plugin-transform-shorthand-properties": "^7.10.4", - "@babel/plugin-transform-spread": "^7.11.0", - "@babel/plugin-transform-sticky-regex": "^7.10.4", - "@babel/plugin-transform-template-literals": "^7.10.4", - "@babel/plugin-transform-typeof-symbol": "^7.10.4", - "@babel/plugin-transform-unicode-escapes": "^7.10.4", - "@babel/plugin-transform-unicode-regex": "^7.10.4", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.11.5", - "browserslist": "^4.12.0", - "core-js-compat": "^3.6.2", - "invariant": "^2.2.2", - "levenary": "^1.1.1", - "semver": "^5.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", - "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-typescript": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz", - "integrity": "sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-transform-typescript": "^7.10.4" - } - }, - "@babel/runtime": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", - "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", - "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.0", - "@babel/types": "^7.11.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@blakeembrey/deque": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@blakeembrey/deque/-/deque-1.0.5.tgz", - "integrity": "sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==" - }, - "@blakeembrey/template": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@blakeembrey/template/-/template-1.0.0.tgz", - "integrity": "sha512-J6WGZqCLdRMHUkyRG6fBSIFJ0rL60/nsQNh5rQvsYZ5u0PsKw6XQcJcA3DWvd9cN3j/IQx5yB1fexhCafwwUUw==" - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@elastic/elasticsearch": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.9.0.tgz", - "integrity": "sha512-iSLQvQafspN03YayzccShkKgJeRsUbncbtIhIL2SeiH01xwdnOZcp0nCvSNaMsH28A3YQ4ogTs9K8eXe42UaUA==", - "requires": { - "debug": "^4.1.1", - "decompress-response": "^4.2.0", - "ms": "^2.1.1", - "pump": "^3.0.0", - "secure-json-parse": "^2.1.0" - } - }, - "@hapi/address": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.1.0.tgz", - "integrity": "sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@hapi/formula": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-2.0.0.tgz", - "integrity": "sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A==" - }, - "@hapi/hoek": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz", - "integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw==" - }, - "@hapi/joi": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-17.1.1.tgz", - "integrity": "sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==", - "requires": { - "@hapi/address": "^4.0.1", - "@hapi/formula": "^2.0.0", - "@hapi/hoek": "^9.0.0", - "@hapi/pinpoint": "^2.0.0", - "@hapi/topo": "^5.0.0" - } - }, - "@hapi/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw==" - }, - "@hapi/topo": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", - "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true }, "@jest/console": { "version": "26.6.2", @@ -1334,15 +704,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1368,27 +729,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -1403,22 +749,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1427,15 +757,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -1497,15 +818,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1528,17 +840,8 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "has-flag": { "version": "4.0.0", @@ -1546,12 +849,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -1566,22 +863,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1590,15 +871,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -1720,15 +992,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1754,27 +1017,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -1789,16 +1037,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1807,15 +1045,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -1949,15 +1178,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1983,27 +1203,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -2018,22 +1223,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2048,15 +1237,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -2213,15 +1393,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -2247,27 +1418,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -2282,22 +1438,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2312,22 +1452,13 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "@jest/types": { - "version": "26.6.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.0.tgz", - "integrity": "sha512-8pDeq/JVyAYw7jBGU83v8RMYAkdrRxLG3BGnAJuqaQAUd6GWBmND2uyl+awI88+hit48suLoLjNFtR+ZXxWaYg==", + "version": "26.6.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.1.tgz", + "integrity": "sha512-ywHavIKNpAVrStiRY5wiyehvcktpijpItvGiK72RAn5ctqmzvPk8OvKnvHeBqa1XdQr959CTWAJMqxI8BTibyg==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -2376,15 +1507,262 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@koj/config": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@koj/config/-/config-1.2.8.tgz", + "integrity": "sha512-OW+GVPb0fEfiNtTx5I9ze/RO6W3mDntMzEavppsA2N1MmZnuFH6zg1aAjjsuePRoAkvtRu95hfmVL2MmRWYHqQ==", + "requires": { + "@semantic-release/changelog": "^5.0.1", + "@semantic-release/git": "^9.0.0", + "@semantic-release/github": "^7.1.1", + "@semantic-release/npm": "^7.0.6", + "dateformat": "^3.0.3", + "semantic-release": "^17.1.1", + "semantic-release-gitmoji": "^1.3.4" + } + }, + "@nestjs/cli": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-7.5.2.tgz", + "integrity": "sha512-qxh5aqQbxzQe8Tuc3CF8nLb1KsWCjLabSAZm+hlxrWYSJzbffbn947MPmsIwZdXgAXZ6AprmJV5KeB2U6DoM+w==", + "dev": true, + "requires": { + "@angular-devkit/core": "10.2.0", + "@angular-devkit/schematics": "10.2.0", + "@angular-devkit/schematics-cli": "0.1002.0", + "@nestjs/schematics": "^7.1.0", + "@types/webpack": "4.41.24", + "chalk": "3.0.0", + "chokidar": "3.4.3", + "cli-table3": "0.5.1", + "commander": "4.1.1", + "fork-ts-checker-webpack-plugin": "5.2.1", + "inquirer": "7.3.3", + "node-emoji": "1.10.0", + "ora": "5.1.0", + "os-name": "4.0.0", + "rimraf": "3.0.2", + "shelljs": "0.8.4", + "tree-kill": "1.2.2", + "tsconfig-paths": "3.9.0", + "tsconfig-paths-webpack-plugin": "3.3.0", + "typescript": "4.0.5", + "webpack": "5.4.0", + "webpack-node-externals": "2.5.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@nestjs/common": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.5.1.tgz", + "integrity": "sha512-UKTWa/MFTryRm4L9b+lsKFg+m/B4zDCsx/pQAMZVCYMW4FRg6QH4BIaq5fMz5G2hL5IFlFVoOC/eXJwhGDOrYA==", + "requires": { + "axios": "0.21.0", + "iterare": "1.2.1", + "tslib": "2.0.3", + "uuid": "8.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@nestjs/config": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-0.5.0.tgz", + "integrity": "sha512-8vgakV722qNt3YBHbvhfwcNRLlwOv37pr5/1RUn5mYMmUh7JKobVNqHgTRWEuJK4BK3dCrhnjxPMPvHOCaA4LQ==", + "requires": { + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "lodash.get": "4.4.2", + "lodash.set": "4.3.2", + "uuid": "8.1.0" + }, + "dependencies": { + "uuid": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz", + "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==" + } + } + }, + "@nestjs/core": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.5.1.tgz", + "integrity": "sha512-aJ1w5tQPkVEmH5QRe1echV5NFWAcHAVQJX/jvfCSK4M5VSkIBN9zreZg8UnYf8sbW5YEaizPts07veeTPsG3FQ==", + "requires": { + "@nuxtjs/opencollective": "0.2.2", + "fast-safe-stringify": "2.0.7", + "iterare": "1.2.1", + "object-hash": "2.0.3", + "path-to-regexp": "3.2.0", + "tslib": "2.0.3", + "uuid": "8.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@nestjs/jwt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-7.2.0.tgz", + "integrity": "sha512-uOTqYmWNpu+oS/MrdYjrWXtKGV4HkCYmAEVEFPP/KfiP/7K6fNy+boLllE6cnqESAXh9u0CLa1noAAavs+LHEQ==", + "requires": { + "@types/jsonwebtoken": "8.5.0", + "jsonwebtoken": "8.5.1" + } + }, + "@nestjs/mapped-types": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-0.1.1.tgz", + "integrity": "sha512-FROYmmZ2F+tLJP/aHasPMX40iUHQPtEAzOAcfAp21baebN5iLUrdyTuphoXjIqubfPFSwtnAGpVm9kLJjQ//ig==" + }, + "@nestjs/passport": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-7.1.0.tgz", + "integrity": "sha512-TdXqEwQ9PWWdpZsWp6jnora+zN+jg7h9Om9CAxXDMCqnmB+IJknkY0OyyplxbMjRyep1zvsc3IptuPHIXb27tA==" + }, + "@nestjs/platform-express": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-7.5.1.tgz", + "integrity": "sha512-sJG9KSIsnPCsfk4uvEBDu8vE78Yjm1kT1b4HLjawH34DJoV16FAlIJQcXwKn0Lq4QWPafQvWr7e1KP5jzOdNEQ==", + "requires": { + "body-parser": "1.19.0", + "cors": "2.8.5", + "express": "4.17.1", + "multer": "1.4.2", + "tslib": "2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@nestjs/schedule": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-0.4.1.tgz", + "integrity": "sha512-pj+zo3DJnoyGQKGguyLn9Nv1KEHZO2vNNGhtrZCIn74GsJL+CkDnd+fpgV85mypaJzjjGRogbMvXUW2UFnJAfg==", + "requires": { + "cron": "1.7.2", + "uuid": "8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + } + } + }, + "@nestjs/schematics": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-7.2.1.tgz", + "integrity": "sha512-yTIwiclX65HYIeemJ/ih3SVlj3BhUHS5eeGy/6uFy1EiIujNadsgi/RZxFSwlCIDkSrGUykqoZdvzfdnsD1Itw==", + "dev": true, + "requires": { + "@angular-devkit/core": "10.2.0", + "@angular-devkit/schematics": "10.2.0", + "fs-extra": "9.0.1", + "pluralize": "8.0.0" + } + }, + "@nestjs/swagger": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-4.7.0.tgz", + "integrity": "sha512-R9OkUIc/2x/a3k5n/ASJkm9tP0VbGxPV/gMAAyqgeWAS2fu7fl7mGmm9wPGu0rN10jzQdi6LOhfcLKFdw+W/Zg==", + "requires": { + "@nestjs/mapped-types": "0.1.1", + "lodash": "4.17.20", + "path-to-regexp": "3.2.0" + } + }, + "@nestjs/testing": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-7.5.1.tgz", + "integrity": "sha512-ISuDhySnD+pjEEFGhRhtN/R/yWRvlWGsMHz7VQ8Q43feSoVPNzKeJr9Jz2lukSH1pSQHsFliHbs7mKOaDP7pSQ==", + "dev": true, + "requires": { + "optional": "0.1.4", + "tslib": "2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true } } }, @@ -2411,136 +1789,20 @@ "fastq": "^1.6.0" } }, - "@oclif/command": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.0.tgz", - "integrity": "sha512-5vwpq6kbvwkQwKqAoOU3L72GZ3Ta8RRrewKj9OJRolx28KLJJ8Dg9Rf7obRwt5jQA9bkYd8gqzMTrI7H3xLfaw==", - "requires": { - "@oclif/config": "^1.15.1", - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.3", - "@oclif/plugin-help": "^3", - "debug": "^4.1.1", - "semver": "^7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - } - } - }, - "@oclif/config": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.17.0.tgz", - "integrity": "sha512-Lmfuf6ubjQ4ifC/9bz1fSCHc6F6E653oyaRXxg+lgT4+bYf9bk+nqrUpAbrXyABkCqgIBiFr3J4zR/kiFdE1PA==", - "requires": { - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-wsl": "^2.1.1", - "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.2.tgz", - "integrity": "sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg==" - } - } - }, - "@oclif/errors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.3.tgz", - "integrity": "sha512-EJR6AIOEkt/NnARNIVAskPDVtdhtO5TTNXmhDrGqMoWVsr0R6DkkLrMyq95BmHvlVWM1nduoq4fQPuCyuF2jaA==", - "requires": { - "clean-stack": "^3.0.0", - "fs-extra": "^9.0.1", - "indent-string": "^4.0.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "@oclif/linewrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz", - "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==" - }, - "@oclif/parser": { - "version": "3.8.5", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.5.tgz", - "integrity": "sha512-yojzeEfmSxjjkAvMRj0KzspXlMjCfBzNRPkWw8ZwOSoNWoJn+OCS/m/S+yfV6BvAM4u2lTzX9Y5rCbrFIgkJLg==", - "requires": { - "@oclif/errors": "^1.2.2", - "@oclif/linewrap": "^1.0.0", - "chalk": "^2.4.2", - "tslib": "^1.9.3" - } - }, - "@oclif/plugin-help": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.2.0.tgz", - "integrity": "sha512-7jxtpwVWAVbp1r46ZnTK/uF+FeZc6y4p1XcGaIUuPAp7wx6NJhIRN/iMT9UfNFX/Cz7mq+OyJz+E+i0zrik86g==", + "@nuxtjs/opencollective": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.2.2.tgz", + "integrity": "sha512-69gFVDs7mJfNjv9Zs5DFVD+pvBW+k1TaHSOqUWqAyTTfLcKI/EMYQgvEvziRd+zAFtUOoye6MfWh0qvinGISPw==", "requires": { - "@oclif/command": "^1.5.20", - "@oclif/config": "^1.15.1", "chalk": "^2.4.1", - "indent-string": "^4.0.0", - "lodash.template": "^4.4.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "wrap-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-4.0.0.tgz", - "integrity": "sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - } + "consola": "^2.3.0", + "node-fetch": "^2.3.0" } }, "@octokit/auth-token": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.2.tgz", - "integrity": "sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ==", - "dev": true, + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.3.tgz", + "integrity": "sha512-fdGoOQ3kQJh+hrilc0Plg50xSfaCKOeYN9t6dpJKXN9BxhhfquL0OzoQXg3spLYymL5rm29uPeI3KEXRaZQ9zg==", "requires": { "@octokit/types": "^5.0.0" } @@ -2549,7 +1811,6 @@ "version": "2.5.4", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.4.tgz", "integrity": "sha512-HCp8yKQfTITYK+Nd09MHzAlP1v3Ii/oCohv0/TW9rhSLvzb98BOVs2QmVYuloE6a3l6LsfyGIwb6Pc4ycgWlIQ==", - "dev": true, "requires": { "@octokit/auth-token": "^2.4.0", "@octokit/graphql": "^4.3.1", @@ -2560,10 +1821,9 @@ } }, "@octokit/endpoint": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.8.tgz", - "integrity": "sha512-MuRrgv+bM4Q+e9uEvxAB/Kf+Sj0O2JAOBA131uo1o6lgdq1iS8ejKwtqHgdfY91V3rN9R/hdGKFiQYMzVzVBEQ==", - "dev": true, + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.9.tgz", + "integrity": "sha512-3VPLbcCuqji4IFTclNUtGdp9v7g+nspWdiCUbK3+iPMjJCZ6LEhn1ts626bWLOn0GiDb6j+uqGvPpqLnY7pBgw==", "requires": { "@octokit/types": "^5.0.0", "is-plain-object": "^5.0.0", @@ -2573,22 +1833,19 @@ "is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" } } }, "@octokit/graphql": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.6.tgz", - "integrity": "sha512-Rry+unqKTa3svswT2ZAuqenpLrzJd+JTv89LTeVa5UM/5OX8o4KTkPL7/1ABq4f/ZkELb0XEK/2IEoYwykcLXg==", - "dev": true, + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.7.tgz", + "integrity": "sha512-Gk0AR+DcwIK/lK/GX+OQ99UqtenQhcbrhHHfOYlrCQe17ADnX3EKAOKRsAZ9qZvpi5MuwWm/Nm+9aO2kTDSdyA==", "requires": { "@octokit/request": "^5.3.0", "@octokit/types": "^5.0.0", @@ -2598,16 +1855,14 @@ "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" } } }, "@octokit/plugin-paginate-rest": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.4.0.tgz", - "integrity": "sha512-YT6Klz3LLH6/nNgi0pheJnUmTFW4kVnxGft+v8Itc41IIcjl7y1C8TatmKQBbCSuTSNFXO5pCENnqg6sjwpJhg==", - "dev": true, + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.0.tgz", + "integrity": "sha512-o+O8c1PqsC5++BHXfMZabRRsBIVb34tXPWyQLyp2IXq5MmkxdipS7TXM4Y9ldL1PzY9CTrCsn/lzFFJGM3oRRA==", "requires": { "@octokit/types": "^5.5.0" } @@ -2615,14 +1870,12 @@ "@octokit/plugin-request-log": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", - "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", - "dev": true + "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==" }, "@octokit/plugin-rest-endpoint-methods": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.17.0.tgz", "integrity": "sha512-NFV3vq7GgoO2TrkyBRUOwflkfTYkFKS0tLAPym7RNpkwLCttqShaEGjthOsPEEL+7LFcYv3mU24+F2yVd3npmg==", - "dev": true, "requires": { "@octokit/types": "^4.1.6", "deprecation": "^2.3.1" @@ -2632,7 +1885,6 @@ "version": "4.1.10", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.1.10.tgz", "integrity": "sha512-/wbFy1cUIE5eICcg0wTKGXMlKSbaAxEr00qaBXzscLXpqhcwgXeS6P8O0pkysBhRfyjkKjJaYrvR1ExMO5eOXQ==", - "dev": true, "requires": { "@types/node": ">= 8" } @@ -2640,10 +1892,9 @@ } }, "@octokit/request": { - "version": "5.4.9", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.9.tgz", - "integrity": "sha512-CzwVvRyimIM1h2n9pLVYfTDmX9m+KHSgCpqPsY8F1NdEK8IaWqXhSBXsdjOBFZSpEcxNEeg4p0UO9cQ8EnOCLA==", - "dev": true, + "version": "5.4.10", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.10.tgz", + "integrity": "sha512-egA49HkqEORVGDZGav1mh+VD+7uLgOxtn5oODj6guJk0HCy+YBSYapFkSLFgeYj3Fr18ZULKGURkjyhkAChylw==", "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", @@ -2658,22 +1909,19 @@ "is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" } } }, "@octokit/request-error": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz", - "integrity": "sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==", - "dev": true, + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.3.tgz", + "integrity": "sha512-GgD5z8Btm301i2zfvJLk/mkhvGCdjQ7wT8xF9ov5noQY8WbKZDH9cOBqXzoeKd1mLr1xH2FwbtGso135zGBgTA==", "requires": { "@octokit/types": "^5.0.1", "deprecation": "^2.0.0", @@ -2684,7 +1932,6 @@ "version": "17.11.2", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-17.11.2.tgz", "integrity": "sha512-4jTmn8WossTUaLfNDfXk4fVJgbz5JgZE8eCs4BvIb52lvIH8rpVMD1fgRCrHbSd6LRPE5JFZSfAEtszrOq3ZFQ==", - "dev": true, "requires": { "@octokit/core": "^2.4.3", "@octokit/plugin-paginate-rest": "^2.2.0", @@ -2696,7 +1943,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", - "dev": true, "requires": { "@types/node": ">= 8" } @@ -2743,23 +1989,6 @@ "@otplib/plugin-thirty-two": "^12.0.1" } }, - "@overnightjs/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@overnightjs/core/-/core-1.7.4.tgz", - "integrity": "sha512-xC1rn84b2FnqgXYM88L8R46dTqYtev8jiq0qBTGWGIOm1N3r8ZDYCud5FMuizLjL4Cl4DvErKaSYx5pzxG8tMw==", - "requires": { - "express": "^4.16.3", - "reflect-metadata": "^0.1.13", - "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", - "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" - } - } - }, "@prisma/bar": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/@prisma/bar/-/bar-0.0.0.tgz", @@ -2780,6 +2009,7 @@ "version": "2.10.2", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-2.10.2.tgz", "integrity": "sha512-55YKXgm5IQP/roKZCTn8ySFjgNwMSS/x3kOcUuDzpDtHXGpSXUkpeH6eqwnj6iq17DLxYqqw8gDGb4+WnIlohw==", + "dev": true, "requires": { "@prisma/engines-version": "2.10.1-6-7d0087eadc7265e12d4b8d8c3516b02c4c965111" } @@ -2793,13 +2023,34 @@ "@prisma/engines-version": { "version": "2.10.1-6-7d0087eadc7265e12d4b8d8c3516b02c4c965111", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-2.10.1-6-7d0087eadc7265e12d4b8d8c3516b02c4c965111.tgz", - "integrity": "sha512-OuOSTvEzXJwCJzNqZ9N/+J3lO64HgX9uGiVOuvlTrRSXoLZk0Q2IiLAx8qhY1U7jPpHJ7LTlZuGNScimqonpJg==" + "integrity": "sha512-OuOSTvEzXJwCJzNqZ9N/+J3lO64HgX9uGiVOuvlTrRSXoLZk0Q2IiLAx8qhY1U7jPpHJ7LTlZuGNScimqonpJg==", + "dev": true + }, + "@schematics/schematics": { + "version": "0.1002.0", + "resolved": "https://registry.npmjs.org/@schematics/schematics/-/schematics-0.1002.0.tgz", + "integrity": "sha512-A6z0j+GCgj3NPAJ3+OZPgU/8KYLHcVWN+ZELuQTFXZgN6mpgbxCmM3yymfo7+riaF0xx1mXlt8G+tO7xDsLVvQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "10.2.0", + "@angular-devkit/schematics": "10.2.0" + } + }, + "@semantic-release/changelog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-5.0.1.tgz", + "integrity": "sha512-unvqHo5jk4dvAf2nZ3aw4imrlwQ2I50eVVvq9D47Qc3R+keNqepx1vDYwkjF8guFXnOYaYcR28yrZWno1hFbiw==", + "requires": { + "@semantic-release/error": "^2.1.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^9.0.0", + "lodash": "^4.17.4" + } }, "@semantic-release/commit-analyzer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", - "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-commits-filter": "^2.0.0", @@ -2810,62 +2061,30 @@ "micromatch": "^4.0.2" }, "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "ms": "2.1.2" } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, "@semantic-release/error": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", - "dev": true + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==" }, "@semantic-release/git": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-9.0.0.tgz", "integrity": "sha512-AZ4Zha5NAPAciIJH3ipzw/WU9qLAn8ENaoVAhD6srRPxTpTzuV3NhNh14rcAo8Paj9dO+5u4rTKcpetOBluYVw==", - "dev": true, "requires": { "@semantic-release/error": "^2.1.0", "aggregate-error": "^3.0.0", @@ -2877,104 +2096,18 @@ "p-reduce": "^2.0.0" }, "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "execa": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz", - "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "mimic-fn": "^2.1.0" + "ms": "2.1.2" } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -2982,7 +2115,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.1.1.tgz", "integrity": "sha512-w8CLCvGVKNe2FPOYQ68OFxFVNNha7YRzptnwTZYdjXYtgTDKw0XVfnMSd9NlJeQPYGfQmIhIVPNBU/cA6zUY0A==", - "dev": true, "requires": { "@octokit/rest": "^17.0.0", "@semantic-release/error": "^2.2.0", @@ -3002,11 +2134,23 @@ "url-join": "^4.0.0" }, "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, "mime": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "dev": true + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -3014,7 +2158,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.6.tgz", "integrity": "sha512-F4judxdeLe8f7+vDva1TkqNc5Tb2tcltZYW0tLtvP2Xt7CD/gGiz7UxAWEOPsXBvIqAP+uTidvGLPl9U3/uRoQ==", - "dev": true, "requires": { "@semantic-release/error": "^2.2.0", "aggregate-error": "^3.0.0", @@ -3026,63 +2169,20 @@ "npm": "^6.13.0", "rc": "^1.2.8", "read-pkg": "^5.0.0", - "registry-auth-token": "^4.0.0", - "semver": "^7.1.2", - "tempy": "^0.5.0" - }, - "dependencies": { - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, + "registry-auth-token": "^4.0.0", + "semver": "^7.1.2", + "tempy": "^0.5.0" + }, + "dependencies": { "normalize-url": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.0.tgz", - "integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } + "integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==" }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, "requires": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -3090,17 +2190,10 @@ "type-fest": "^0.6.0" } }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" } } }, @@ -3108,7 +2201,6 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz", "integrity": "sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ==", - "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-changelog-writer": "^4.0.0", @@ -3122,837 +2214,937 @@ "read-pkg-up": "^7.0.0" }, "dependencies": { - "get-stream": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "read-pkg": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "requires": { - "pump": "^3.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" } } }, - "@sentry/core": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.27.3.tgz", - "integrity": "sha512-yqepQO88jSt5hy0awpk61AxI4oHB09LjVbUEk4nJDg+1YXuND23cuZvH+Sp2jCZX2vrsw2tefwflToYfA8/U2w==", - "requires": { - "@sentry/hub": "5.27.3", - "@sentry/minimal": "5.27.3", - "@sentry/types": "5.27.3", - "@sentry/utils": "5.27.3", - "tslib": "^1.9.3" - } + "@sindresorhus/is": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz", + "integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==" }, - "@sentry/hub": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.27.3.tgz", - "integrity": "sha512-icEH3hr6NVQkpowXZcPOs9IgJZP5lMKtvud4mVioSpkd+NxtRdKrGEX4eF2TCviOJc9Md0mV4K+aL5Au7hxggQ==", + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, "requires": { - "@sentry/types": "5.27.3", - "@sentry/utils": "5.27.3", - "tslib": "^1.9.3" + "type-detect": "4.0.8" } }, - "@sentry/minimal": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.27.3.tgz", - "integrity": "sha512-ng01cM0rsE1RMjqVTpPLN0ZVkTo0I675usM1krkpQe8ddW6tfQ6EJWpt02/BrpQZRQzTtfWp6/RyB1KFXg6icg==", + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, "requires": { - "@sentry/hub": "5.27.3", - "@sentry/types": "5.27.3", - "tslib": "^1.9.3" + "@sinonjs/commons": "^1.7.0" } }, - "@sentry/node": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.27.3.tgz", - "integrity": "sha512-IZ/TkYRY+P/E5C+RF6Rcb6tpY59fyk0040Q3akzbDjb/hrw5TRKnK8fJ6/0gXCAOvlDPIlpRHFJgJ1p2QgWy+g==", + "@staart/mustache-markdown": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@staart/mustache-markdown/-/mustache-markdown-3.0.3.tgz", + "integrity": "sha512-Mugu0ei0xR7EH0Af8UHkfWa/HQUfZZX5jOAHIIGY442Yh3QyXsChSrdB+wYMyLoipbww9Mdw0GlAZQy7FnSZ1A==", "requires": { - "@sentry/core": "5.27.3", - "@sentry/hub": "5.27.3", - "@sentry/tracing": "5.27.3", - "@sentry/types": "5.27.3", - "@sentry/utils": "5.27.3", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" + "@types/marked": "^1.1.0", + "@types/mustache": "^4.0.1", + "marked": "^1.1.1", + "mustache": "^4.0.1" } }, - "@sentry/tracing": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.27.3.tgz", - "integrity": "sha512-UWrHMdGxPfx1u558CWm1tptc2z0BuqCHVe2+BNN7POahq5BkpbGqaotyPQTBHbfmcs6QGfsMG57ou8HQFrBxyA==", + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", "requires": { - "@sentry/hub": "5.27.3", - "@sentry/minimal": "5.27.3", - "@sentry/types": "5.27.3", - "@sentry/utils": "5.27.3", - "tslib": "^1.9.3" + "defer-to-connect": "^2.0.0" } }, - "@sentry/types": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.27.3.tgz", - "integrity": "sha512-PkWhMArFMxBb1g3HtMEL8Ea9PYae2MU0z9CMIWiqzerFy2ZpKG98IU3pt8ic4JkmKQdwB8hDiZpRPMHhW0WYwQ==" + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true }, - "@sentry/utils": { - "version": "5.27.3", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.27.3.tgz", - "integrity": "sha512-R9WvFrRBALZvCzu/9BsuXBCfkNxz4MwdBNSXaBsJo4afQw1ljkjIc9DpHzlL9S9goIwXo81Buwmr5gGDO6aH+Q==", + "@types/babel__core": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "dev": true, "requires": { - "@sentry/types": "5.27.3", - "tslib": "^1.9.3" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "@servie/events": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", - "integrity": "sha512-sBSO19KzdrJCM3gdx6eIxV8M9Gxfgg6iDQmH5TIAGaUu+X9VDdsINXJOnoiZ1Kx3TrHdH4bt5UVglkjsEGBcvw==" - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } }, - "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "@types/babel__template": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.3.tgz", + "integrity": "sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q==", "dev": true, "requires": { - "type-detect": "4.0.8" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "@types/babel__traverse": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz", + "integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@babel/types": "^7.3.0" } }, - "@staart/config": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@staart/config/-/config-1.0.1.tgz", - "integrity": "sha512-J4kyyZY7PTnC4Plbm95/ckrcgOMjH5jxzhMWOiU4e2lu10TkTT9Qw/mhGcakW6eZix6VmYIDyF/HNAbhxt2K9A==" + "@types/bcrypt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-3.0.0.tgz", + "integrity": "sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ==", + "dev": true }, - "@staart/disposable-email": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@staart/disposable-email/-/disposable-email-2.0.3.tgz", - "integrity": "sha512-qlz+z4f2Nq/vlZgvzagnDmDZSEaU0aHtrrkmXdzt2Vw0MVmcAVUDxLECvaf395w2RYNotqtGDn5Lp4oaQYoTaA==", + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", "requires": { - "disposable-email-domains": "^1.0.57", - "matcher": "^3.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "requires": { - "escape-string-regexp": "^4.0.0" - } - } + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" } }, - "@staart/elasticsearch": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@staart/elasticsearch/-/elasticsearch-2.2.4.tgz", - "integrity": "sha512-e1VbgDEYpYsTJ/4YUA+g3bWOcEkEGzzDY8w+yjVE4U6gtsXMCNPWcXCaY5CxHSpVWDxMzYtsguzDjbtNtL03Uw==", + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", "requires": { - "@elastic/elasticsearch": "^7.9.0", - "aws-elasticsearch-connector": "^9.0.0", - "aws-sdk": "^2.748.0" + "@types/node": "*" } }, - "@staart/errors": { + "@types/cookiejar": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@staart/errors/-/errors-2.1.2.tgz", - "integrity": "sha512-hINXT223R6awujhI82nj1bkK+PslsruJywt+iyFMP6n07qXJ25bdPYXeOL05Xa09SXAmNLFej50KM4vdmP+E7Q==", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, + "@types/eslint": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.4.tgz", + "integrity": "sha512-YCY4kzHMsHoyKspQH+nwSe+70Kep7Vjt2X+dZe5Vs2vkRudqtoFoUIv1RlJmZB8Hbp7McneupoZij4PadxsK5Q==", + "dev": true, "requires": { - "@types/signale": "^1.4.1", - "http-status-codes": "^2.1.2", - "signale": "^1.4.0" - }, - "dependencies": { - "http-status-codes": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.1.2.tgz", - "integrity": "sha512-zpZ1nBcoR0j1FLQ7xbXXBy1z/yUfAi+0a5IZBoZnmOseYkaljdzQ17ZeVXFlK23IbLxMJn6aWI0uU92DQQrG0g==" - } + "@types/estree": "*", + "@types/json-schema": "*" } }, - "@staart/mail": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@staart/mail/-/mail-2.3.0.tgz", - "integrity": "sha512-gIqtb6oF0VXLsi83UJUHlqR98/Rarz6rztPMIgilF5hosEPqWkhmVs2hUgV9UApnEgWtptiVpGNgJ8LyrG+zkA==", + "@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, "requires": { - "@types/nodemailer": "^6.4.0", - "aws-sdk": "^2.742.0", - "nodemailer": "^6.4.11" - }, - "dependencies": { - "aws-sdk": { - "version": "2.744.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.744.0.tgz", - "integrity": "sha512-yS+VIm5ZgdGXWjJBW/HmCoTkbzGv6vddJitbmpjQFKBnRkY2JbOGu/xr9BBhmxskgbUJGgmYE8GPaGfsaMh3cw==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - } - } + "@types/eslint": "*", + "@types/estree": "*" } }, - "@staart/messages": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@staart/messages/-/messages-2.1.3.tgz", - "integrity": "sha512-NTIxzQ3/Npj+gyl5pIUKQZ6YjV6mSovypSbPcWX1OJMwWO/O/jKSIlx4q54JEt72G38cR7Rr2IV/ljuf87KV+A==", + "@types/estree": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "dev": true + }, + "@types/express": { + "version": "4.17.8", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", + "integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==", "requires": { - "http-status-codes": "^2.1.2" - }, - "dependencies": { - "http-status-codes": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.1.2.tgz", - "integrity": "sha512-zpZ1nBcoR0j1FLQ7xbXXBy1z/yUfAi+0a5IZBoZnmOseYkaljdzQ17ZeVXFlK23IbLxMJn6aWI0uU92DQQrG0g==" - } + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" } }, - "@staart/mustache-markdown": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@staart/mustache-markdown/-/mustache-markdown-3.0.3.tgz", - "integrity": "sha512-Mugu0ei0xR7EH0Af8UHkfWa/HQUfZZX5jOAHIIGY442Yh3QyXsChSrdB+wYMyLoipbww9Mdw0GlAZQy7FnSZ1A==", + "@types/express-serve-static-core": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz", + "integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==", "requires": { - "@types/marked": "^1.1.0", - "@types/mustache": "^4.0.1", - "marked": "^1.1.1", - "mustache": "^4.0.1" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" } }, - "@staart/payments": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@staart/payments/-/payments-4.0.1.tgz", - "integrity": "sha512-gBdhmlC33A7gCWNVcRgWXY8aYILRu3YKAUWSjW8+Ob2Vo9C5eQpS4tnsZQAS0ZhNIJw60v+1PT5N184oxTqd7Q==", + "@types/graceful-fs": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "dev": true, "requires": { - "stripe": "^8.90.0" + "@types/node": "*" } }, - "@staart/redis": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@staart/redis/-/redis-2.3.1.tgz", - "integrity": "sha512-ens6Lf2gTv1nFrTECFRFLRnEdA9EbXRjmwUdZd9qcCyKaEgmZvM1C+XjvN7IfmnJIwABBdI6ACT0ggCgRx3Nvg==", - "requires": { - "handy-redis": "^1.8.3", - "rsmq": "^0.12.2" - } - }, - "@staart/scripts": { - "version": "1.18.4", - "resolved": "https://registry.npmjs.org/@staart/scripts/-/scripts-1.18.4.tgz", - "integrity": "sha512-yL7wERr+6DBVnpff9MiMq4fZK6wdbAg8rKWcd5FfByIhzZ6/U/QlTivFVw9U5zvvdK2qUtW1IUYQZi+ht8QDVg==", - "requires": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.4", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-decorators": "^7.10.5", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "@babel/preset-typescript": "^7.10.4", - "@oclif/command": "^1.8.0", - "@oclif/config": "^1.17.0", - "@oclif/plugin-help": "^3.2.0", - "@staart/errors": "^2.1.1", - "axios": "^0.20.0", - "concurrently": "^5.3.0", - "dotenv": "^8.2.0", - "eject-dependencies": "^1.2.0", - "fs-extra": "^9.0.1", - "node-watch": "^0.6.4", - "nodemon": "^2.0.4", - "onchange": "^7.0.2", - "recursive-readdir": "^2.2.2", - "regenerator-runtime": "^0.13.7", - "shelljs": "^0.8.4", - "tree-kill": "^1.2.2", - "tslib": "^2.0.1", - "typedoc": "^0.19.0", - "yaml": "^1.10.0" - }, - "dependencies": { - "@babel/core": { - "version": "7.11.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", - "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.6", - "@babel/helper-module-transforms": "^7.11.0", - "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.11.5", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.11.5", - "@babel/types": "^7.11.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.11.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", - "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", - "requires": { - "@babel/types": "^7.11.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/parser": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", - "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==" - }, - "@babel/traverse": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", - "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.5", - "@babel/types": "^7.11.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", - "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "axios": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", - "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "tslib": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.2.tgz", - "integrity": "sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg==" - } + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" } }, - "@staart/server": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@staart/server/-/server-2.7.1.tgz", - "integrity": "sha512-BHjJhEvO6xBkqKK6kT4ceHLPP32+iYJzq+1ikBNuNSePiAB8UJ1YB2/rpUUQIiKK/eZXQmhpIG3bY688RHki5g==", + "@types/istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "dev": true, "requires": { - "@overnightjs/core": "^1.7.4", - "@types/body-parser": "^1.19.0", - "@types/cors": "^2.8.7", - "@types/express": "^4.17.7", - "@types/express-rate-limit": "^5.1.0", - "@types/express-slow-down": "^1.3.0", - "@types/helmet": "^0.0.48", - "@types/node-cleanup": "^2.1.1", - "@types/response-time": "^2.3.4", - "body-parser": "^1.19.0", - "cors": "^2.8.5", - "express": "^4.17.1", - "express-rate-limit": "^5.1.3", - "express-slow-down": "^1.3.1", - "helmet": "^4.1.0", - "node-cleanup": "^2.1.2", - "response-time": "^2.3.2" - } - }, - "@staart/text": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@staart/text/-/text-2.3.1.tgz", - "integrity": "sha512-Qti14ZRf9A9SKFDod41OxSsuUI7yTobLI3i4y8g5YKKtWMDuTa6CSYcV1zWVxT1wszjXI0rFzhsfxz4qnTf/TA==", - "requires": { - "@types/bcryptjs": "^2.4.2", - "@types/ms": "^0.7.31", - "bcryptjs": "^2.4.3", - "change-case": "^4.1.1", - "crypto-random-string": "^3.2.0", - "hashids": "^2.2.1", - "ip-anonymize": "^0.1.0", - "ip-range-check": "^0.2.0", - "matcher": "^3.0.0", - "ms": "^2.1.2", - "slugify": "^1.4.5" - }, - "dependencies": { - "crypto-random-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-3.2.0.tgz", - "integrity": "sha512-8vPu5bsKaq2uKRy3OL7h1Oo7RayAWB8sYexLKAqvCXVib8SxgbmoF1IN4QMKjBv8uI8mp5gPPMbiRah25GMrVQ==", - "requires": { - "type-fest": "^0.8.1" - } - } + "@types/istanbul-lib-report": "*" } }, - "@staart/validate": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@staart/validate/-/validate-3.0.2.tgz", - "integrity": "sha512-dlbmRw2neGcYq2h+42fgX870Za/YK92Am8iMpJAVA09pk/mB+cV8Rw9GXca58OR5Dcymxn6hWENSfY2lW24bWg==", + "@types/jest": { + "version": "26.0.15", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.15.tgz", + "integrity": "sha512-s2VMReFXRg9XXxV+CW9e5Nz8fH2K1aEhwgjUqPPbQd7g95T0laAcvLv032EhFHIa5GHsZ8W7iJEQVaJq6k3Gog==", + "dev": true, "requires": { - "@hapi/joi": "^17.1.1" + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" } }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/jsonwebtoken": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", + "integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==", "requires": { - "defer-to-connect": "^1.0.1" + "@types/node": "*" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "requires": { + "@types/node": "*" + } + }, + "@types/marked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.1.0.tgz", + "integrity": "sha512-j8XXj6/l9kFvCwMyVqozznqpd/nk80krrW+QiIJN60Uu9gX5Pvn4/qPJ2YngQrR3QREPwmrE1f9/EWKVTFzoEw==" + }, + "@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, - "@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=" + }, + "@types/mustache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.0.1.tgz", + "integrity": "sha512-wH6Tu9mbiOt0n5EvdoWy0VGQaJMHfLIxY/6wS0xLC7CV1taM6gESEzcYy0ZlWvxxiiljYvfDIvz4hHbUUDRlhw==" + }, + "@types/node": { + "version": "14.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", + "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==" + }, + "@types/nodemailer": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz", + "integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@types/node": "*" } }, - "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/passport": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.4.tgz", + "integrity": "sha512-h5OfAbfBBYSzjeU0GTuuqYEk9McTgWeGQql9g3gUw2/NNCfD7VgExVRYJVVeU13Twn202Mvk9BT0bUrl30sEgA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@types/express": "*" } }, - "@types/babel__template": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.3.tgz", - "integrity": "sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q==", + "@types/passport-local": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.33.tgz", + "integrity": "sha512-+rn6ZIxje0jZ2+DAiWFI8vGG7ZFKB0hXx2cUdMmudSWsigSq6ES7Emso46r4HJk0qCgrZVfI8sJiM7HIYf4SbA==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" } }, - "@types/babel__traverse": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz", - "integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==", + "@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", "dev": true, "requires": { - "@babel/types": "^7.3.0" + "@types/express": "*", + "@types/passport": "*" } }, - "@types/bcryptjs": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", - "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==" + "@types/prettier": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", + "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", + "dev": true }, - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "@types/qrcode": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.3.5.tgz", + "integrity": "sha512-92QMnMb9m0ErBU20za5Eqtf4lzUcSkk5w/Cz30q5qod0lWHm2loztmFs2EnCY06yT51GY1+m/oFq2D8qVK2Bjg==", + "dev": true, "requires": { - "@types/connect": "*", "@types/node": "*" } }, - "@types/caseless": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==" + }, + "@types/randomcolor": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.5.tgz", + "integrity": "sha512-PywdYff3F8lGO3BggkCXaPFH0Ue/2Y7xliihoQNkxCGPJ4w7VTMfgcmSMIE6gOVAEu9Wx42JRSuRREVG3AUrtg==", "dev": true }, - "@types/connect": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", - "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", - "requires": { - "@types/node": "*" - } + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, - "@types/cors": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.7.tgz", - "integrity": "sha512-sOdDRU3oRS7LBNTIqwDkPJyq0lpHYcbMTt0TrjzsXbk/e37hcLTH6eZX7CdbDeN0yJJvzw9hFBZkbtCSbk/jAQ==", + "@types/request-ip": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@types/request-ip/-/request-ip-0.0.35.tgz", + "integrity": "sha512-FtI7lv1EDaZnWmaCU7ZTwfOpW76EioocaWyiSeWdfW1cDPZYzzij781A5O/UeHQUN9yjtjEcD3StTzZjKG0XEA==", + "dev": true, "requires": { - "@types/express": "*" + "@types/node": "*" } }, - "@types/cron": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@types/cron/-/cron-1.7.2.tgz", - "integrity": "sha512-AEpNLRcsVSc5AdseJKNHpz0d4e8+ow+abTaC0fKDbAU86rF1evoFF0oC2fV9FdqtfVXkG2LKshpLTJCFOpyvTg==", + "@types/response-time": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.4.tgz", + "integrity": "sha512-+MuxeMIzmXDy/CTw/mPlZO1SWBKbpz9QFo4+KYNXc2iiY0OGH3Ny9DPKT4eSamyDbhWJPfvMMPB4Kh7DapwJhA==", "dev": true, "requires": { - "@types/node": "*", - "moment": ">=2.14.0" + "@types/express": "*", + "@types/node": "*" } }, - "@types/express": { - "version": "4.17.8", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", - "integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==", + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/qs": "*", - "@types/serve-static": "*" + "@types/node": "*" } }, - "@types/express-rate-limit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-rate-limit/-/express-rate-limit-5.1.0.tgz", - "integrity": "sha512-vmg7S3hUnfFmp06V01DrTB41mbQYXMV/F4aF5KKnfCIeSlnizatXaqO9UgR6LvNEEd3eMpuUTLxR6nv3d4hZ6g==", + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/serve-static": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.6.tgz", + "integrity": "sha512-nuRJmv7jW7VmCVTn+IgYDkkbbDGyIINOeu/G0d74X3lm6E5KfMeQPJhxIt1ayQeQB3cSxvYs1RA/wipYoFB4EA==", "requires": { - "@types/express": "*" + "@types/mime": "*", + "@types/node": "*" } }, - "@types/express-serve-static-core": { - "version": "4.17.12", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.12.tgz", - "integrity": "sha512-EaEdY+Dty1jEU7U6J4CUWwxL+hyEGMkO5jan5gplfegUgCUsIUWqXxqw47uGjimeT4Qgkz/XUfwoau08+fgvKA==", + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "dev": true + }, + "@types/superagent": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.10.tgz", + "integrity": "sha512-xAgkb2CMWUMCyVc/3+7iQfOEBE75NvuZeezvmixbUw3nmENf2tCnQkW5yQLTYqvXUQ+R6EXxdqKKbal2zM5V/g==", + "dev": true, "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" + "@types/cookiejar": "*", + "@types/node": "*" } }, - "@types/express-slow-down": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/express-slow-down/-/express-slow-down-1.3.0.tgz", - "integrity": "sha512-Z2dsjjAy6ARRJrL7RZdtE5/32lGaP9su487yi69OG31LZ2WRCYQk9Muy9Gu+b9Paju8gkEVabkMLvfyMKykSQA==", + "@types/supertest": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.10.tgz", + "integrity": "sha512-Xt8TbEyZTnD5Xulw95GLMOkmjGICrOQyJ2jqgkSjAUR3mm7pAIzSR0NFBaMcwlzVvlpCjNwbATcWWwjNiZiFrQ==", + "dev": true, "requires": { - "@types/express": "*" + "@types/superagent": "*" } }, - "@types/fs-extra": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.3.tgz", - "integrity": "sha512-NKdGoXLTFTRED3ENcfCsH8+ekV4gbsysanx2OPbstXVV6fZMgUCqTxubs6I9r7pbOJbFgVq1rpFtLURjKCZWUw==", + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "@types/ua-parser-js": { + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", + "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", "dev": true, "requires": { - "@types/node": "*" + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "@types/geolite2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/geolite2/-/geolite2-2.0.0.tgz", - "integrity": "sha512-/ADzCQbkeiuu1FGPvh02pxdVhTzMjNOqM8hnOaga+m9nO2BB9puC+qGuGqmFedEmyPSl1pq1pQfgkgxFIE28cg==", + "@types/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", "dev": true }, - "@types/graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "@types/validator": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.0.0.tgz", + "integrity": "sha512-WAy5txG7aFX8Vw3sloEKp5p/t/Xt8jD3GRD9DacnFv6Vo8ubudAsRTXgxpQwU0mpzY/H8U4db3roDuCMjShBmw==" + }, + "@types/webpack": { + "version": "4.41.24", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.24.tgz", + "integrity": "sha512-1A0MXPwZiMOD3DPMuOKUKcpkdPo8Lq33UGggZ7xio6wJ/jV1dAu5cXDrOfGDnldUroPIRLsr/DT43/GqOA4RFQ==", "dev": true, "requires": { - "@types/node": "*" + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "@types/hapi__joi": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/@types/hapi__joi/-/hapi__joi-17.1.6.tgz", - "integrity": "sha512-y3A1MzNC0FmzD5+ys59RziE1WqKrL13nxtJgrSzjoO7boue5B7zZD2nZLPwrSuUviFjpKFQtgHYSvhDGfIE4jA==", - "dev": true + "@types/webpack-sources": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.0.0.tgz", + "integrity": "sha512-a5kPx98CNFRKQ+wqawroFunvFqv7GHm/3KOI52NY9xWADgc8smu4R6prt4EU/M4QfVjvgBkMqU4fBhw3QfMVkg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } }, - "@types/helmet": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.48.tgz", - "integrity": "sha512-C7MpnvSDrunS1q2Oy1VWCY7CDWHozqSnM8P4tFeRTuzwqni+PYOjEredwcqWG+kLpYcgLsgcY3orHB54gbx2Jw==", + "@types/yargs": { + "version": "15.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz", + "integrity": "sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g==", + "dev": true, "requires": { - "@types/express": "*" + "@types/yargs-parser": "*" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "@typescript-eslint/eslint-plugin": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.6.1.tgz", + "integrity": "sha512-SNZyflefTMK2JyrPfFFzzoy2asLmZvZJ6+/L5cIqg4HfKGiW2Gr1Go1OyEVqne/U4QwmoasuMwppoBHWBWF2nA==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "*" + "@typescript-eslint/experimental-utils": "4.6.1", + "@typescript-eslint/scope-manager": "4.6.1", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "@typescript-eslint/experimental-utils": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.1.tgz", + "integrity": "sha512-qyPqCFWlHZXkEBoV56UxHSoXW2qnTr4JrWVXOh3soBP3q0o7p4pUEMfInDwIa0dB/ypdtm7gLOS0hg0a73ijfg==", "dev": true, "requires": { - "@types/istanbul-lib-report": "*" + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.6.1", + "@typescript-eslint/types": "4.6.1", + "@typescript-eslint/typescript-estree": "4.6.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" } }, - "@types/jest": { - "version": "26.0.15", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.15.tgz", - "integrity": "sha512-s2VMReFXRg9XXxV+CW9e5Nz8fH2K1aEhwgjUqPPbQd7g95T0laAcvLv032EhFHIa5GHsZ8W7iJEQVaJq6k3Gog==", + "@typescript-eslint/parser": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.6.1.tgz", + "integrity": "sha512-lScKRPt1wM9UwyKkGKyQDqf0bh6jm8DQ5iN37urRIXDm16GEv+HGEmum2Fc423xlk5NUOkOpfTnKZc/tqKZkDQ==", "dev": true, "requires": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "@typescript-eslint/scope-manager": "4.6.1", + "@typescript-eslint/types": "4.6.1", + "@typescript-eslint/typescript-estree": "4.6.1", + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "@types/jsonwebtoken": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", - "integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==", + "@typescript-eslint/scope-manager": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.6.1.tgz", + "integrity": "sha512-f95+80r6VdINYscJY1KDUEDcxZ3prAWHulL4qRDfNVD0I5QAVSGqFkwHERDoLYJJWmEAkUMdQVvx7/c2Hp+Bjg==", "dev": true, "requires": { - "@types/node": "*" + "@typescript-eslint/types": "4.6.1", + "@typescript-eslint/visitor-keys": "4.6.1" } }, - "@types/marked": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.1.0.tgz", - "integrity": "sha512-j8XXj6/l9kFvCwMyVqozznqpd/nk80krrW+QiIJN60Uu9gX5Pvn4/qPJ2YngQrR3QREPwmrE1f9/EWKVTFzoEw==" - }, - "@types/mime": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" - }, - "@types/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", + "@typescript-eslint/types": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.6.1.tgz", + "integrity": "sha512-k2ZCHhJ96YZyPIsykickez+OMHkz06xppVLfJ+DY90i532/Cx2Z+HiRMH8YZQo7a4zVd/TwNBuRCdXlGK4yo8w==", "dev": true }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "@typescript-eslint/typescript-estree": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.1.tgz", + "integrity": "sha512-/J/kxiyjQQKqEr5kuKLNQ1Finpfb8gf/NpbwqFFYEBjxOsZ621r9AqwS9UDRA1Rrr/eneX/YsbPAIhU2rFLjXQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.6.1", + "@typescript-eslint/visitor-keys": "4.6.1", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } }, - "@types/mustache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.0.1.tgz", - "integrity": "sha512-wH6Tu9mbiOt0n5EvdoWy0VGQaJMHfLIxY/6wS0xLC7CV1taM6gESEzcYy0ZlWvxxiiljYvfDIvz4hHbUUDRlhw==" + "@typescript-eslint/visitor-keys": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.1.tgz", + "integrity": "sha512-owABze4toX7QXwOLT3/D5a8NecZEjEWU1srqxENTfqsY3bwVnl3YYbOh6s1rp2wQKO9RTHFGjKes08FgE7SVMw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.6.1", + "eslint-visitor-keys": "^2.0.0" + } }, - "@types/mysql": { - "version": "2.15.15", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.15.tgz", - "integrity": "sha512-1GJnq7RwuFPRicMHdT53vza5v39nep9OKIbozxNUpFXP04CydcdWrqpZQ+MlVdlLFCisWnnt09xughajjWpFsw==", + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", "dev": true, "requires": { - "@types/node": "*" + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" } }, - "@types/node": { - "version": "14.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", - "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==" + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true }, - "@types/node-cleanup": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/node-cleanup/-/node-cleanup-2.1.1.tgz", - "integrity": "sha512-Q1s5Sszz6YfhaGr1pbaZihr9IYaiQT0aOK/3c2qb9lOUbEBhcAb9ZEU7RBTtopnHSIJF80adLRcOGTay2W5QVQ==" + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true }, - "@types/node-emoji": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@types/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha512-0fRfA90FWm6KJfw6P9QGyo0HDTCmthZ7cWaBQndITlaWLTZ6njRyKwrwpzpg+n6kBXBIGKeUHEQuBx7bphGJkA==", + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", "dev": true }, - "@types/nodemailer": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz", - "integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==", + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, "requires": { - "@types/node": "*" + "@webassemblyjs/wast-printer": "1.9.0" } }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "@types/prettier": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", - "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", "dev": true }, - "@types/qrcode": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.3.5.tgz", - "integrity": "sha512-92QMnMb9m0ErBU20za5Eqtf4lzUcSkk5w/Cz30q5qod0lWHm2loztmFs2EnCY06yT51GY1+m/oFq2D8qVK2Bjg==", + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", "dev": true, "requires": { - "@types/node": "*" + "@webassemblyjs/ast": "1.9.0" } }, - "@types/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" - }, - "@types/randomcolor": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.5.tgz", - "integrity": "sha512-PywdYff3F8lGO3BggkCXaPFH0Ue/2Y7xliihoQNkxCGPJ4w7VTMfgcmSMIE6gOVAEu9Wx42JRSuRREVG3AUrtg==", + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", "dev": true }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" - }, - "@types/redis": { - "version": "2.8.27", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.27.tgz", - "integrity": "sha512-RRHarqPp3mgqHz+qzLVuQCJAIVaB3JBaczoj24QVVYu08wiCmB8vbOeNeK9lIH+pyT7+R/bbEPghAZZuhbZm0g==", + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, "requires": { - "@types/node": "*" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" } }, - "@types/request": { - "version": "2.48.5", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", - "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "dev": true, "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" + "@xtuc/ieee754": "^1.2.0" } }, - "@types/response-time": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.4.tgz", - "integrity": "sha512-+MuxeMIzmXDy/CTw/mPlZO1SWBKbpz9QFo4+KYNXc2iiY0OGH3Ny9DPKT4eSamyDbhWJPfvMMPB4Kh7DapwJhA==", + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, "requires": { - "@types/express": "*", - "@types/node": "*" + "@xtuc/long": "4.2.2" } }, - "@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", "dev": true }, - "@types/serve-static": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz", - "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==", + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" } }, - "@types/signale": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@types/signale/-/signale-1.4.1.tgz", - "integrity": "sha512-05d9fUDqRnt36rizLgo38SbPTrkMzdhXpvSHSAhxzokgIUPGNUoXHV0zYjPpTd4IryDADJ0mGHpfJ/Yhjyh9JQ==", + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, "requires": { - "@types/node": "*" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" } }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "@types/tough-cookie": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.7.tgz", - "integrity": "sha512-rMQbgMGxnLsdn8e9aPVyuN+zMQLrZ2QW8xlv7eWS1mydfGXN+tsTKffcIzd8rGCcLdmi3xvQw2MDaZI1bBNTaw==" + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } }, - "@types/validator": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.1.0.tgz", - "integrity": "sha512-gHUHI6pJaANIO2r6WcbT7+WMgbL9GZooR4tWpuBOETpDIqFNxwaJluE+6rj6VGYe8k6OkfhbHz2Fkm8kl06Igw==", - "dev": true + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } }, - "@types/yaml": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", - "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", "dev": true, "requires": { - "yaml": "*" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" } }, - "@types/yargs": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", - "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" } }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" @@ -3979,9 +3171,9 @@ } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", + "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", "dev": true }, "acorn-globals": { @@ -3992,8 +3184,22 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -4001,35 +3207,41 @@ "dev": true }, "agent-base": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", - "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" - }, - "dependencies": { - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - } } }, "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -4038,70 +3250,30 @@ "uri-js": "^4.2.2" } }, - "ansi-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", - "requires": { - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true }, "ansi-escapes": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "requires": { + "type-fest": "^0.11.0" } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -4114,24 +3286,62 @@ "ansicolors": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" }, "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" }, "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "remove-trailing-separator": "^1.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" } } } @@ -4139,7 +3349,8 @@ "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true }, "argparse": { "version": "1.0.10", @@ -4153,23 +3364,25 @@ "argv-formatter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", - "dev": true + "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=" }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true }, "array-flatten": { "version": "1.1.1", @@ -4179,8 +3392,18 @@ "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=" + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } }, "array-union": { "version": "2.1.0", @@ -4190,13 +3413,28 @@ "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { "version": "0.2.4", @@ -4216,13 +3454,14 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "optional": true + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true }, "asynckit": { "version": "0.4.0", @@ -4238,36 +3477,8 @@ "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "await-lock": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.1.0.tgz", - "integrity": "sha512-t7Zm5YGgEEc/3eYAicF32m/TNvL+XOeYZy9CvBUeJY/szM7frLolFylhrlZNWV/ohWhcUXygrBGjYmoQdxF4CQ==" - }, - "aws-elasticsearch-connector": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/aws-elasticsearch-connector/-/aws-elasticsearch-connector-9.0.0.tgz", - "integrity": "sha512-O+A9HEa14gOiKTAp6U6Ha1RRJvQjc046wIn9CJ69wc+c1c5CfPE4xl4Av6Zyv6dgzs+RVGxdetjm8RpSlTUmhQ==", - "requires": { - "aws4": "^1.10.0" - } - }, - "aws-sdk": { - "version": "2.748.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.748.0.tgz", - "integrity": "sha512-H+DCioQ4AChoBxGMtagcJ3a0mM0lOh3ta/dWIrfPTECAlRIuxlrBDp78cRhPgvdYYUxW54kB/IaHGR2xPP8JXw==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - } + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true }, "aws-sign2": { "version": "0.7.0", @@ -4276,9 +3487,10 @@ "dev": true }, "aws4": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", - "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true }, "axios": { "version": "0.21.0", @@ -4357,12 +3569,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4374,14 +3580,6 @@ } } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-istanbul": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", @@ -4446,6 +3644,7 @@ "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -4460,6 +3659,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -4468,6 +3668,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -4476,6 +3677,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -4484,6 +3686,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -4497,6 +3700,15 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, + "bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==", + "requires": { + "node-addon-api": "^3.0.0", + "node-pre-gyp": "0.15.0" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -4506,36 +3718,22 @@ "tweetnacl": "^0.14.3" } }, - "bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" - }, "before-after-hook": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", - "dev": true + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==" }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "optional": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true }, "body-parser": { "version": "1.19.0", @@ -4552,93 +3750,12 @@ "qs": "6.7.0", "raw-body": "2.4.0", "type-is": "~1.6.17" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - } } }, "bottleneck": { "version": "2.19.5", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true - }, - "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" }, "brace-expansion": { "version": "1.1.11", @@ -4650,30 +3767,11 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "fill-range": "^7.0.1" } }, "browser-process-hrtime": { @@ -4683,14 +3781,15 @@ "dev": true }, "browserslist": { - "version": "4.14.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.5.tgz", - "integrity": "sha512-Z+vsCZIvCBvqLoYkBFTwEYH3v5MCQbsAjp50ERycpOjnPmolg1Gjy4+KaWWpm8QOJt9GHkhdqAl14NpCX73CWA==", + "version": "4.14.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.6.tgz", + "integrity": "sha512-zeFYcUo85ENhc/zxHbiIp0LGzzTrE2Pv2JhxvS7kpUb9Q9D38kUX6Bie7pGutJ/5iF5rOxE7CepAuWD56xJ33A==", + "dev": true, "requires": { - "caniuse-lite": "^1.0.30001135", - "electron-to-chromium": "^1.3.571", - "escalade": "^3.1.0", - "node-releases": "^1.1.61" + "caniuse-lite": "^1.0.30001154", + "electron-to-chromium": "^1.3.585", + "escalade": "^3.1.1", + "node-releases": "^1.1.65" } }, "bs-logger": { @@ -4711,16 +3810,6 @@ "node-int64": "^0.4.0" } }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", @@ -4750,10 +3839,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", - "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==" + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + } }, "bytes": { "version": "3.1.0", @@ -4764,6 +3857,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -4776,18 +3870,23 @@ "unset-value": "^1.0.0" } }, + "cacheable-lookup": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz", + "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==" + }, "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", "requires": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", + "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^4.1.0", - "responselike": "^1.0.2" + "responselike": "^2.0.0" }, "dependencies": { "get-stream": { @@ -4797,11 +3896,6 @@ "requires": { "pump": "^3.0.0" } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" } } }, @@ -4810,15 +3904,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "camel-case": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", - "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", - "requires": { - "pascal-case": "^3.1.1", - "tslib": "^1.10.0" - } - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -4828,98 +3913,43 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, "requires": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", "quick-lru": "^4.0.1" - } - }, - "caniuse-lite": { - "version": "1.0.30001144", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001144.tgz", - "integrity": "sha512-4GQTEWNMnVZVOFG3BK0xvGeaDAtiPAbG2N8yuMXuXzx/c2Vd4XoMPO8+E918zeXn5IF0FRVtGShBfkfQea2wHQ==" - }, - "capital-case": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.3.tgz", - "integrity": "sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0", - "upper-case-first": "^2.0.1" - } - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", - "dev": true, - "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - } - }, - "casbin": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/casbin/-/casbin-5.2.0.tgz", - "integrity": "sha512-9qqcTAx0ysgF6xz1Mq83B7yD9inG4iEZ85tMZBmkXCIsECD9yAE8XhaONn7GhlnTave10k3ktGJ+9qNItXe30A==", - "requires": { - "await-lock": "^2.0.1", - "expression-eval": "^2.0.0", - "ip": "^1.1.5", - "micromatch": "^4.0.2" }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } + "dependencies": { + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" } } }, + "caniuse-lite": { + "version": "1.0.30001156", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001156.tgz", + "integrity": "sha512-z7qztybA2eFZTB6Z3yvaQBIoJpQtsewRD74adw2UbRWwsRq3jIPvgrQGawBMbfafekQaD21FWuXNcywtTDGGCw==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -4936,60 +3966,61 @@ "supports-color": "^5.3.0" } }, - "change-case": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.1.tgz", - "integrity": "sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==", - "requires": { - "camel-case": "^4.1.1", - "capital-case": "^1.0.3", - "constant-case": "^3.0.3", - "dot-case": "^3.0.3", - "header-case": "^2.0.3", - "no-case": "^3.0.3", - "param-case": "^3.0.3", - "pascal-case": "^3.1.1", - "path-case": "^3.0.3", - "sentence-case": "^3.0.3", - "snake-case": "^3.0.3", - "tslib": "^1.10.0" - } - }, "char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "optional": true, + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" } }, "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true }, "cjs-module-lexer": { "version": "0.6.0", @@ -4997,10 +4028,16 @@ "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", "dev": true }, + "class-transformer": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz", + "integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==" + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -5012,116 +4049,124 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } } } }, + "class-validator": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.12.2.tgz", + "integrity": "sha512-TDzPzp8BmpsbPhQpccB3jMUE/3pK0TyqamrK0kcx+ZeFytMA+O6q87JZZGObHHnoo9GM8vl/JppIyKWeEA/EVw==", + "requires": { + "@types/validator": "13.0.0", + "google-libphonenumber": "^3.2.8", + "tslib": ">=1.9.0", + "validator": "13.0.0" + } + }, "clean-stack": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.0.tgz", - "integrity": "sha512-RHxtgFvXsRQ+1AM7dlozLDY7ssmvUUh0XEnfnyhYgJTO6beNZHBogiaCwGM9Q3rFrUkYxOtsZRC0zAturg5bjg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "requires": { - "escape-string-regexp": "4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - } + "restore-cursor": "^3.1.0" } }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + "cli-spinners": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz", + "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==", + "dev": true }, "cli-table": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "dev": true, "requires": { "colors": "1.0.3" - } - }, - "client-oauth2": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/client-oauth2/-/client-oauth2-4.3.3.tgz", - "integrity": "sha512-k8AvUYJon0vv75ufoVo4nALYb/qwFFicO3I0+39C6xEdflqVtr+f9cy+0ZxAduoVSTfhP5DX2tY2XICAd5hy6Q==", - "requires": { - "popsicle": "^12.0.5", - "safe-buffer": "^5.2.0" }, "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" } } }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { - "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "strip-ansi": "^4.0.0" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-regex": "^3.0.0" } } } }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true }, "clone-response": { "version": "1.0.2", @@ -5129,13 +4174,6 @@ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", "requires": { "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - } } }, "co": { @@ -5144,6 +4182,11 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -5154,6 +4197,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -5173,10 +4217,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "optional": true }, "combined-stream": { "version": "1.0.8", @@ -5190,13 +4235,13 @@ "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true }, "compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, "requires": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" @@ -5205,76 +4250,69 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "concurrently": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.3.0.tgz", - "integrity": "sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==", + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { - "chalk": "^2.4.2", - "date-fns": "^2.0.1", - "lodash": "^4.17.15", - "read-pkg": "^4.0.1", - "rxjs": "^6.5.2", - "spawn-command": "^0.0.2-1", - "supports-color": "^6.1.0", - "tree-kill": "^1.2.2", - "yargs": "^13.3.0" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "has-flag": "^3.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } - } - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "semver": "^6.0.0" + "safe-buffer": "~5.1.0" } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, - "constant-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.3.tgz", - "integrity": "sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0", - "upper-case": "^2.0.1" - } + "consola": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", + "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true }, "content-disposition": { "version": "0.5.3", @@ -5290,63 +4328,65 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "conventional-changelog-angular": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.11.tgz", - "integrity": "sha512-nSLypht/1yEflhuTogC03i7DX7sOrXGsRn14g131Potqi6cbGbGEE9PSDEHKldabB6N76HiSyw9Ph+kLmC04Qw==", - "dev": true, + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", + "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", "requires": { "compare-func": "^2.0.0", "q": "^1.5.1" + }, + "dependencies": { + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + } } }, "conventional-changelog-writer": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.17.tgz", - "integrity": "sha512-IKQuK3bib/n032KWaSb8YlBFds+aLmzENtnKtxJy3+HqDq5kohu3g/UdNbIHeJWygfnEbZjnCKFxAW0y7ArZAw==", - "dev": true, + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.18.tgz", + "integrity": "sha512-mAQDCKyB9HsE8Ko5cCM1Jn1AWxXPYV0v8dFPabZRkvsiWUul2YyAqbIaoMKF88Zf2ffnOPSvKhboLf3fnjo5/A==", "requires": { "compare-func": "^2.0.0", - "conventional-commits-filter": "^2.0.6", + "conventional-commits-filter": "^2.0.7", "dateformat": "^3.0.0", "handlebars": "^4.7.6", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.15", - "meow": "^7.0.0", + "meow": "^8.0.0", "semver": "^6.0.0", "split": "^1.0.0", - "through2": "^3.0.0" + "through2": "^4.0.0" }, "dependencies": { "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "conventional-commits-filter": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", - "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", - "dev": true, + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", "requires": { "lodash.ismatch": "^4.4.0", "modify-values": "^1.0.0" } }, "conventional-commits-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz", - "integrity": "sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA==", - "dev": true, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.0.tgz", + "integrity": "sha512-XmJiXPxsF0JhAKyfA2Nn+rZwYKJ60nanlbSWwwkGwLQFbugsc0gv1rzc7VbbUWAzJfR1qR87/pNgv9NgmxtBMQ==", "requires": { "JSONStream": "^1.0.4", "is-text-path": "^1.0.1", "lodash": "^4.17.15", - "meow": "^7.0.0", + "meow": "^8.0.0", "split2": "^2.0.0", - "through2": "^3.0.0", + "through2": "^4.0.0", "trim-off-newlines": "^1.0.0" } }, @@ -5354,45 +4394,32 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, "requires": { "safe-buffer": "~5.1.1" } }, "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - }, - "core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", - "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", - "requires": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5421,9 +4448,9 @@ } }, "cron": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/cron/-/cron-1.8.2.tgz", - "integrity": "sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/cron/-/cron-1.7.2.tgz", + "integrity": "sha512-+SaJ2OfeRvfQqwXQ2kgr0Y5pzBR/lijf5OpnnaruwWnmI799JfWr2jN2ItOV9s3A/+TFOt6mxvKzQq5F0Jp6VQ==", "requires": { "moment-timezone": "^0.5.x" } @@ -5486,23 +4513,22 @@ "whatwg-url": "^8.0.0" } }, - "date-fns": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", - "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==" - }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" + }, + "dayjs": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.5.tgz", + "integrity": "sha512-WULIw7UpW/E0y6VywewpbXAMH3d5cZijEhoHLwM+OMVbk/NtchKS/W+57H/0P1rqU7gHrAArjiRLHCUhgMQl6w==" }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, "decamelize": { @@ -5514,7 +4540,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, "requires": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" @@ -5523,8 +4548,7 @@ "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" } } }, @@ -5537,14 +4561,22 @@ "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true }, "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { - "mimic-response": "^2.0.0" + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } } }, "deep-extend": { @@ -5568,19 +4600,21 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, "requires": { "clone": "^1.0.2" } }, "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==" }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -5589,6 +4623,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -5598,6 +4633,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5606,6 +4642,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5614,6 +4651,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -5628,10 +4666,10 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "depd": { "version": "1.1.2", @@ -5641,20 +4679,39 @@ "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "diff-sequences": { "version": "26.5.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.5.0.tgz", @@ -5674,10 +4731,14 @@ "path-type": "^4.0.0" } }, - "disposable-email-domains": { - "version": "1.0.57", - "resolved": "https://registry.npmjs.org/disposable-email-domains/-/disposable-email-domains-1.0.57.tgz", - "integrity": "sha512-fBOPBW5aeZJndQaYz/TX3NG9hbfKG3XHhE5lwHAKI+iLYaGsne1HQjPuu4ruDUaapZtEqcDtzog/AQo91PxoWA==" + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } }, "domexception": { "version": "2.0.1", @@ -5696,19 +4757,10 @@ } } }, - "dot-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", - "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0" - } - }, "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "requires": { "is-obj": "^2.0.0" } @@ -5718,20 +4770,48 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, "requires": { "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -5755,19 +4835,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, - "eject-dependencies": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eject-dependencies/-/eject-dependencies-1.2.0.tgz", - "integrity": "sha512-xSUDYbQ5sGWldwHGqRzmt6N8ndREmcXyA4ivHnIGMyNAP1sYGjbe4FqUGSZjtFyye2UQYSE0Wtz5bj3/Mfy3TA==", - "requires": { - "fast-glob": "^3.2.2", - "fs-extra": "^9.0.0" - } - }, "electron-to-chromium": { - "version": "1.3.577", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.577.tgz", - "integrity": "sha512-dSb64JQSFif/pD8mpVAgSFkbVi6YHbK6JeEziwNNmXlr/Ne2rZtseFK5SM7JoWSLf6gP0gVvRGi4/2ZRhSX/rA==" + "version": "1.3.591", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.591.tgz", + "integrity": "sha512-ol/0WzjL4NS4Kqy9VD6xXQON91xIihDT36sYCew/G/bnd1v0/4D+kahp26JauQhgFUjrdva3kRSo7URcUmQ+qw==", + "dev": true }, "emittery": { "version": "0.7.2", @@ -5780,6 +4852,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -5793,143 +4871,494 @@ "once": "^1.4.0" } }, + "enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "env-ci": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.2.tgz", "integrity": "sha512-Xc41mKvjouTXD3Oy9AqySz1IeyvJvHZ20Twf5ZLYbNpPPIuCnL/qHCmNlD01LoNy0JTunw9HPYVptD19Ac7Mbw==", - "dev": true, "requires": { "execa": "^4.0.0", "java-properties": "^1.0.0" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "dependencies": { - "execa": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.13.0.tgz", + "integrity": "sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "pump": "^3.0.0" + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "path-key": "^3.0.0" + "find-up": "^2.1.0" } } } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } } }, - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, - "escalade": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz", - "integrity": "sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig==" - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", "dev": true, "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true } } }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } }, "estraverse": { "version": "4.3.0", @@ -5940,17 +5369,24 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true }, "exec-sh": { "version": "0.3.4", @@ -5959,63 +5395,19 @@ "dev": true }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" } }, "exit": { @@ -6028,6 +5420,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -6038,18 +5431,11 @@ "to-regex": "^3.0.1" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -6058,14 +5444,10 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -6184,52 +5566,13 @@ "vary": "~1.1.2" }, "dependencies": { - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" } } }, - "express-rate-limit": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz", - "integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA==" - }, - "express-slow-down": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/express-slow-down/-/express-slow-down-1.3.1.tgz", - "integrity": "sha512-mkxVJt3z2e0/LIVp144xpaPw8Ku2f6XS9ftjgwMsUtp+4a84hk6NI6/KTEPkq1kjCsJuXeG6SA/izCWxaErBdg==", - "requires": { - "defaults": "^1.0.3" - } - }, - "expression-eval": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/expression-eval/-/expression-eval-2.1.0.tgz", - "integrity": "sha512-FUJO/Akvl/JOWkvlqZaqbkhsEWlCJWDeZG4tzX96UH68D9FeRgYgtb55C2qtqbORC0Q6x5419EDjWu4IT9kQfg==", - "requires": { - "jsep": "^0.3.0" - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -6240,6 +5583,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -6249,16 +5593,29 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, "requires": { "is-plain-object": "^2.0.4" } } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -6274,6 +5631,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -6282,6 +5640,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -6290,6 +5649,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -6298,6 +5658,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -6306,6 +5667,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -6337,54 +5699,6 @@ "merge2": "^1.3.0", "micromatch": "^4.0.2", "picomatch": "^2.2.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - } } }, "fast-json-stable-stringify": { @@ -6399,10 +5713,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", + "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", "requires": { "reusify": "^1.0.4" } @@ -6417,38 +5736,28 @@ } }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "requires": { "escape-string-regexp": "^1.0.5" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "to-regex-range": "^5.0.1" } }, "finalhandler": { @@ -6463,21 +5772,6 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "find-up": { @@ -6492,11 +5786,38 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", - "dev": true, "requires": { "semver-regex": "^2.0.0" } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -6505,7 +5826,8 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true }, "forever-agent": { "version": "0.6.1", @@ -6513,10 +5835,80 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, + "fork-ts-checker-webpack-plugin": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", + "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -6524,6 +5916,12 @@ "mime-types": "^2.1.12" } }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "dev": true + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -6533,6 +5931,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, "requires": { "map-cache": "^0.2.2" } @@ -6546,10 +5945,38 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "fs-extra": { @@ -6564,17 +5991,18 @@ } }, "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "requires": { - "minipass": "^3.0.0" + "minipass": "^2.6.0" } }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" + "fs-monkey": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.1.tgz", + "integrity": "sha512-fcSa+wyTqZa46iWweI7/ZiUfegOZl0SG8+dltIwFXo7+zYU9J9kpS3NB6pZcSlJdhvIwp81Adx2XhZorncxiaA==", + "dev": true }, "fs.realpath": { "version": "1.0.0", @@ -6582,24 +6010,71 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true }, "geolite2-redist": { "version": "1.0.7", @@ -6608,6 +6083,61 @@ "requires": { "rimraf": "^3.0.2", "tar": "^6.0.2" + }, + "dependencies": { + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "tar": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", + "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } } }, "get-caller-file": { @@ -6621,10 +6151,16 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "requires": { "pump": "^3.0.0" } @@ -6632,7 +6168,8 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true }, "getpass": { "version": "0.1.7", @@ -6647,7 +6184,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", - "dev": true, "requires": { "argv-formatter": "~1.0.0", "spawn-error-forwarder": "~1.0.0", @@ -6657,20 +6193,45 @@ "traverse": "~0.6.6" }, "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "split2": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", - "dev": true, "requires": { "through2": "~2.0.0" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -6682,17 +6243,15 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.2.tgz", "integrity": "sha512-kbuvus1dWQB2sSW4cbfTeGpCMd8ge9jx9RKnhXhuJ7tnvT+NIrTVfYZxjtflZddQYcmdOTlkAcjmx7bor+15AQ==", - "dev": true, "requires": { "is-ssh": "^1.3.0", "parse-url": "^5.0.0" } }, "git-url-parse": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.3.tgz", - "integrity": "sha512-GPsfwticcu52WQ+eHp0IYkAyaOASgYdtsQDIt4rUp6GbiNt1P9ddrh3O0kQB0eD4UJZszVqNT3+9Zwcg40fywA==", - "dev": true, + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.0.tgz", + "integrity": "sha512-KlIa5jvMYLjXMQXkqpFzobsyD/V2K5DRHl5OAf+6oDFPlPLxrGDVQlIdI63c4/Kt6kai4kALENSALlzTGST3GQ==", "requires": { "git-up": "^4.0.0" } @@ -6711,38 +6270,35 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "optional": true, + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "is-glob": "^4.0.1" } }, - "global-dirs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", - "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", - "requires": { - "ini": "^1.3.5" - } + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } }, "globby": { "version": "11.0.1", @@ -6752,49 +6308,32 @@ "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - } - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - } + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "google-libphonenumber": { + "version": "3.2.14", + "resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.14.tgz", + "integrity": "sha512-4r7mQRbk7EUYV1gyfP1SInYuQsjuDtRXCGLSotxeYDJaj/aF1xFO5PV/GSQeIxXWhIw050DujROICvWpZ1XYRw==" + }, + "got": { + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz", + "integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" } }, "graceful-fs": { @@ -6828,15 +6367,6 @@ } } }, - "handy-redis": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/handy-redis/-/handy-redis-1.8.3.tgz", - "integrity": "sha512-TMC47NAaKuUC5jDMlCLNvNDIiNhyUO/ONEM7Xsbv3kiTwR9E1hsx7zctPH4fEoSKvro2gPs8bBb4+Nwscigz2A==", - "requires": { - "@types/redis": "^2.8.14", - "redis": "^3.0.2" - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -6856,8 +6386,7 @@ "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==" }, "has": { "version": "1.0.3", @@ -6875,12 +6404,19 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -6891,55 +6427,61 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" }, "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" - }, - "hashids": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/hashids/-/hashids-2.2.1.tgz", - "integrity": "sha512-+hQeKWwpSDiWFeu/3jKUvwboE4Z035gR6FnpscbHPOEEjCbgv2px9/Mlb3O0nOTRyZOw4MMFRYfVL3zctOV6OQ==" + "helmet": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.2.0.tgz", + "integrity": "sha512-aoiSxXMd0ks1ojYpSCFoCRzgv4rY/uB9jKStaw8PkXwsdLYa/Gq+Nc5l0soH0cwBIsLAlujPnx4HLQs+LaXCrQ==" }, - "header-case": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz", - "integrity": "sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==", + "hibp": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hibp/-/hibp-9.0.0.tgz", + "integrity": "sha512-uzVIdQrDT5xIioWwy6tkUcUnlyia9Y0vPnilJ+L39F770Fa70KYyoEJp/NFYBjRS3Txkp8L69MPjordm9rTaXQ==", "requires": { - "capital-case": "^1.0.3", - "tslib": "^1.10.0" + "isomorphic-unfetch": "^3.0.0", + "jssha": "^2.3.1" } }, - "helmet": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.1.0.tgz", - "integrity": "sha512-KWy75fYN8hOG2Rhl8e5B3WhOzb0by1boQum85TiddIE9iu6gV+TXbUjVC17wfej0o/ZUpqB9kxM0NFCZRMzf+Q==" - }, - "highlight.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.1.tgz", - "integrity": "sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g==" - }, "hook-std": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", - "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", - "dev": true + "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==" }, "hosted-git-info": { "version": "2.8.8", @@ -6976,24 +6518,31 @@ "setprototypeof": "1.1.1", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } } }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, "requires": { "@tootallnate/once": "1", "agent-base": "6", "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "http-signature": { @@ -7007,6 +6556,15 @@ "sshpk": "^1.7.0" } }, + "http2-wrapper": { + "version": "1.0.0-beta.5.2", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz", + "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -7014,13 +6572,27 @@ "requires": { "agent-base": "6", "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" }, "iconv-lite": { "version": "0.4.24", @@ -7040,15 +6612,18 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "requires": { + "minimatch": "^3.0.4" + } }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7058,7 +6633,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, "requires": { "resolve-from": "^5.0.0" }, @@ -7066,16 +6640,10 @@ "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" } } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" - }, "import-local": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", @@ -7089,7 +6657,8 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indent-string": { "version": "4.0.0", @@ -7106,43 +6675,102 @@ } }, "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true }, "into-stream": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", - "dev": true, "requires": { "from2": "^2.3.0", "p-is-promise": "^3.0.0" } }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, "ip-anonymize": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ip-anonymize/-/ip-anonymize-0.1.0.tgz", @@ -7159,7 +6787,8 @@ "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true }, "ipaddr.js": { "version": "1.9.1", @@ -7170,6 +6799,7 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -7178,6 +6808,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7190,37 +6821,39 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "optional": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, "requires": { "ci-info": "^2.0.0" } }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", + "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", "requires": { "has": "^1.0.3" } @@ -7229,6 +6862,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -7237,6 +6871,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7246,12 +6881,14 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -7261,19 +6898,23 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, "is-docker": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==" + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true, + "optional": true }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true }, "is-extglob": { "version": "2.1.1", @@ -7299,63 +6940,38 @@ "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - } + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true }, "is-negative-zero": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, - "is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, - "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==" - }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, "requires": { "isobject": "^3.0.1" } @@ -7370,6 +6986,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -7378,21 +6995,26 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", - "dev": true, "requires": { "protocols": "^1.1.0" } }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", "dev": true }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -7401,7 +7023,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, "requires": { "text-extensions": "^1.0.0" } @@ -7409,30 +7030,34 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "optional": true, "requires": { "is-docker": "^2.0.0" } }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + "is_js": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz", + "integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=" }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "isexe": { "version": "2.0.0", @@ -7442,7 +7067,17 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "requires": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } }, "isstream": { "version": "0.1.2", @@ -7454,7 +7089,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", - "dev": true, "requires": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", @@ -7466,8 +7100,7 @@ "issue-regex": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/issue-regex/-/issue-regex-3.1.0.tgz", - "integrity": "sha512-0RHjbtw9QXeSYnIEY5Yrp2QZrdtz21xBDV9C/GIlY2POmgoS6a7qjkYS5siRKXScnuAj5/SPv1C3YForNCHTJA==", - "dev": true + "integrity": "sha512-0RHjbtw9QXeSYnIEY5Yrp2QZrdtz21xBDV9C/GIlY2POmgoS6a7qjkYS5siRKXScnuAj5/SPv1C3YForNCHTJA==" }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -7512,21 +7145,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7549,6 +7167,21 @@ "source-map": "^0.6.1" }, "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7567,11 +7200,15 @@ "istanbul-lib-report": "^3.0.0" } }, + "iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" + }, "java-properties": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", - "dev": true + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==" }, "jest": { "version": "26.6.3", @@ -7600,19 +7237,10 @@ "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "color-convert": "^2.0.1" } }, "chalk": { @@ -7625,17 +7253,6 @@ "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7651,37 +7268,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-cli": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", @@ -7717,40 +7309,6 @@ "micromatch": "^4.0.2" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7759,55 +7317,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -7869,53 +7378,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7966,6 +7434,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7975,15 +7449,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8009,27 +7474,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -8044,16 +7494,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -8066,12 +7506,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8080,28 +7514,19 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "jest-diff": { - "version": "26.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.0.tgz", - "integrity": "sha512-IH09rKsdWY8YEY7ii2BHlSq59oXyF2pK3GoK+hOK9eD/x6009eNB5Jv1shLMKgxekodPzLlV7eZP1jPFQYds8w==", + "version": "26.6.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.1.tgz", + "integrity": "sha512-BBNy/zin2m4kG5In126O8chOBxLLS/XMTuuM2+YhgyHk87ewPzKTuTJcqj3lOWOi03NNgrl+DkMeV/exdvG9gg==", "dev": true, "requires": { "chalk": "^4.0.0", "diff-sequences": "^26.5.0", "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.0" + "pretty-format": "^26.6.1" }, "dependencies": { "ansi-styles": { @@ -8190,6 +7615,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8199,15 +7630,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8233,27 +7655,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -8268,16 +7675,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -8290,12 +7687,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8304,15 +7695,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -8353,15 +7735,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8387,27 +7760,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -8422,16 +7780,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8440,15 +7788,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -8488,15 +7827,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8522,49 +7852,24 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" } }, "supports-color": { @@ -8575,15 +7880,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -8637,25 +7933,6 @@ "color-convert": "^2.0.1" } }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8681,34 +7958,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.2.0.tgz", - "integrity": "sha512-pKnaUh2TNvk+/egJdBw1h46LwyLx8BzEq+MGCf/RMCVfEHHsGOCWG00dqk91kUPPArIIwMBg9T/virxwzP03cA==", - "dev": true, - "optional": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -8723,16 +7978,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8741,15 +7986,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -8792,6 +8028,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8801,15 +8043,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -8835,27 +8068,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -8870,16 +8088,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -8892,12 +8100,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8906,15 +8108,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -8941,6 +8134,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8993,12 +8192,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9035,6 +8228,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9105,12 +8304,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9152,6 +8345,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9161,15 +8360,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -9195,37 +8385,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -9238,18 +8403,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9258,15 +8411,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -9394,15 +8538,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -9428,13 +8563,14 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "to-regex-range": "^5.0.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "has-flag": { @@ -9443,12 +8579,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -9463,32 +8593,61 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "p-locate": "^4.1.0" } }, - "resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" + "p-limit": "^2.2.0" } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9498,14 +8657,11 @@ "has-flag": "^4.0.0" } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true } } }, @@ -9634,15 +8790,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -9668,27 +8815,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -9703,16 +8835,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9721,15 +8843,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -9783,20 +8896,11 @@ }, "ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "color-convert": "^2.0.1" } }, "chalk": { @@ -9809,17 +8913,6 @@ "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -9835,37 +8928,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -9880,46 +8948,6 @@ "micromatch": "^4.0.2" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -9934,55 +8962,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -10033,6 +9012,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -10103,18 +9088,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10140,19 +9113,6 @@ "micromatch": "^4.0.2" }, "dependencies": { - "@jest/types": { - "version": "26.6.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.1.tgz", - "integrity": "sha512-ywHavIKNpAVrStiRY5wiyehvcktpijpItvGiK72RAn5ctqmzvPk8OvKnvHeBqa1XdQr959CTWAJMqxI8BTibyg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -10162,15 +9122,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -10196,27 +9147,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -10235,15 +9171,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -10274,6 +9201,12 @@ "chalk": "^4.0.0" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -10332,12 +9265,6 @@ "react-is": "^17.0.1" } }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10386,15 +9313,6 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -10420,27 +9338,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "jest-util": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", @@ -10455,16 +9358,6 @@ "micromatch": "^4.0.2" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10473,15 +9366,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -10513,11 +9397,6 @@ } } }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10571,28 +9450,37 @@ "whatwg-url": "^8.0.0", "ws": "^7.2.3", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, - "jsep": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-0.3.5.tgz", - "integrity": "sha512-AoRLBDc6JNnKjNcmonituEABS5bcfqDhQAWWXNTFrqu6nVXBpBAGfcoTGZMFlIrh9FjmE1CQyX9CTNwZrXMMDA==" - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true }, "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -10605,34 +9493,46 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.0" } }, "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "requires": { "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } } }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" }, "jsonwebtoken": { "version": "8.5.1", @@ -10649,6 +9549,18 @@ "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "jsprim": { @@ -10663,6 +9575,11 @@ "verror": "1.10.0" } }, + "jssha": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.4.2.tgz", + "integrity": "sha512-/jsi/9C0S70zfkT/4UlKQa5E1xKurDnXcQizcww9JSR/Fv+uIbWM2btG+bFcL3iNoK9jIGS0ls9HWLr1iw0kFg==" + }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -10683,11 +9600,11 @@ } }, "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz", + "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==", "requires": { - "json-buffer": "3.0.0" + "json-buffer": "3.0.1" } }, "kind-of": { @@ -10701,35 +9618,20 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "requires": { - "package-json": "^6.3.0" - } - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", - "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", - "requires": { - "leven": "^3.1.0" - } + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "lines-and-columns": { @@ -10738,27 +9640,51 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", + "parse-json": "^2.2.0", + "pify": "^2.0.0", "strip-bom": "^3.0.0" }, "dependencies": { "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "^1.2.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, + "loader-runner": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz", + "integrity": "sha512-oR4lB4WvwFoC70ocraKhn5nkKSs23t57h9udUgw8o0iH8hMXeEoRuUgfcvgUwAJ1ZpRqBvcou4N2SMvM1DwMrA==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -10773,33 +9699,25 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, "lodash.capitalize": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", - "dev": true + "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=" }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, "lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", - "dev": true + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, "lodash.includes": { "version": "4.3.0", @@ -10819,8 +9737,7 @@ "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", - "dev": true + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=" }, "lodash.isnumber": { "version": "3.0.3", @@ -10846,37 +9763,24 @@ "lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "dev": true + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -10885,89 +9789,129 @@ "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", - "dev": true + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=" }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", - "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, "requires": { - "tslib": "^1.10.0" + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } } }, - "lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" - }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" - }, "macos-release": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz", - "integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==", - "dev": true + "integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==" + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } }, "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "semver": "^6.0.0" }, "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "make-error-cause": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-2.3.0.tgz", - "integrity": "sha512-etgt+n4LlOkGSJbBTV9VROHA5R7ekIPS4vfh+bCAoJgRrJWdqJCBbpS3osRJ/HrT7R68MzMiY3L3sDJ/Fd8aBg==", - "requires": { - "make-error": "^1.3.5" - } + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true }, "makeerror": { "version": "1.0.11", @@ -10978,35 +9922,43 @@ "tmpl": "1.0.x" } }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "requires": { + "p-defer": "^1.0.0" + } + }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true }, "map-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", - "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", - "dev": true + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==" }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, "requires": { "object-visit": "^1.0.0" } }, "marked": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz", - "integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.2.tgz", + "integrity": "sha512-5jjKHVl/FPo0Z6ocP3zYhKiJLzkwJAw4CZoLjv57FkvbUuwOX4LIBBGGcXjAY6ATcd1q9B8UTj5T9Umauj0QYQ==" }, "marked-terminal": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.0.tgz", "integrity": "sha512-5KllfAOW02WS6hLRQ7cNvGOxvKW1BKuXELH4EtbWfyWgxQhROoMxEvuQ/3fTgkNjledR0J48F4HbapvYp1zWkQ==", - "dev": true, "requires": { "ansi-escapes": "^4.3.1", "cardinal": "^2.1.1", @@ -11020,7 +9972,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -11029,7 +9980,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11039,7 +9989,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -11047,41 +9996,23 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } } } }, - "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "requires": { - "escape-string-regexp": "^4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - } - } - }, "maxmind": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.1.tgz", @@ -11096,40 +10027,205 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "meow": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", - "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", + "mem": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.0.0.tgz", + "integrity": "sha512-qrcJOe6uD+EW8Wrci1Vdiua/15Xw3n/QnaNXE7varnB6InxSk7nu3/i5jfy3S6kWxr8WYJ6R1o0afMUtvorTsA==", + "requires": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==" + } + } + }, + "memfs": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.0.tgz", + "integrity": "sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A==", + "dev": true, + "requires": { + "fs-monkey": "1.0.1" + } + }, + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "meow": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", + "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", "requires": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", - "normalize-package-data": "^2.5.0", + "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" }, "dependencies": { - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, + "hosted-git-info": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", + "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "lru-cache": "^6.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "requires": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } } + }, + "type-fest": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.0.tgz", + "integrity": "sha512-fbDukFPnJBdn2eZ3RR+5mK2slHLFd6gYHY7jna1KWWy4Yr4XysHuCdXRzy+RiG/HwG4WJat00vdC2UHky5eKiQ==" + }, + "yargs-parser": { + "version": "20.2.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.3.tgz", + "integrity": "sha512-emOFRT9WVHw03QSvN5qor9QQT9+sw5vwxfYweivSMHTcAXPefwVae2FjO7JJjj8hCE4CzPOPeFM83VwT29HCww==" } } }, @@ -11141,8 +10237,7 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "merge2": { "version": "1.4.1", @@ -11155,23 +10250,12 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "braces": "^3.0.1", + "picomatch": "^2.0.5" } }, "mime": { @@ -11195,19 +10279,17 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" }, "minimatch": { "version": "3.0.4", @@ -11226,7 +10308,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, "requires": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", @@ -11234,26 +10315,27 @@ } }, "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { - "yallist": "^4.0.0" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "minipass": "^2.9.0" } }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -11263,6 +10345,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -11270,9 +10353,12 @@ } }, "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } }, "mmdb-lib": { "version": "1.2.0", @@ -11282,13 +10368,12 @@ "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==" }, "moment": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", - "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "moment-timezone": { "version": "0.5.31", @@ -11299,36 +10384,41 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multer": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } }, "mustache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.1.tgz", "integrity": "sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==" }, - "mysql": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", - "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", - "requires": { - "bignumber.js": "9.0.0", - "readable-stream": "2.3.7", - "safe-buffer": "5.1.2", - "sqlstring": "2.3.1" - } - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", - "optional": true + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -11349,6 +10439,31 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "needle": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -11362,28 +10477,25 @@ "nerf-dart": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", - "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", - "dev": true + "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=" + }, + "nestjs-rate-limiter": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/nestjs-rate-limiter/-/nestjs-rate-limiter-2.5.6.tgz", + "integrity": "sha512-daBDy6HS1PKrFVxbwQRYkcQ/m0Jh4Th9V2qmYE7t44H3t00dK9z55pmdzSvqQ/4ITHxmlTe0KbcapeUbz4Wahg==", + "requires": { + "rate-limiter-flexible": "2.1.10" + } }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "no-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", - "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", - "requires": { - "lower-case": "^2.0.1", - "tslib": "^1.10.0" - } + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, - "node-cleanup": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", - "integrity": "sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=" + "node-addon-api": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.2.tgz", + "integrity": "sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg==" }, "node-emoji": { "version": "1.10.0", @@ -11396,8 +10508,7 @@ "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-int64": { "version": "0.4.0", @@ -11424,162 +10535,65 @@ "shellwords": "^0.1.1", "uuid": "^8.3.0", "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "optional": true - }, - "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "dev": true, - "optional": true - } } }, - "node-releases": { - "version": "1.1.61", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.61.tgz", - "integrity": "sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g==" - }, - "node-watch": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.4.tgz", - "integrity": "sha512-cI6CHzivIFESe8djiK3Wh90CtWQBxLwMem8x8S+2GSvCvFgoMuOKVlfJtQ/2v3Afg3wOnHl/+tXotEs8z5vOrg==" - }, - "nodemailer": { - "version": "6.4.11", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.11.tgz", - "integrity": "sha512-BVZBDi+aJV4O38rxsUh164Dk1NCqgh6Cm0rQSb9SK/DHGll/DrCMnycVDD7msJgZCnmVa8ASo8EZzR7jsgTukQ==" - }, - "nodemon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", - "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", - "requires": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^4.0.0" + "node-pre-gyp": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", + "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.3", + "needle": "^2.5.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" }, "dependencies": { - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", - "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", - "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { - "picomatch": "^2.2.1" + "glob": "^7.1.3" } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, + "node-releases": { + "version": "1.1.66", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz", + "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==", + "dev": true + }, + "nodemailer": { + "version": "6.4.15", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.15.tgz", + "integrity": "sha512-2/z13dBTWdgTRlxVMAK6C13dCI22GEShET4+jFLlQsxpblxYhojnucfcTZO1QBu5CsHvABsBj2JCGO3vl0HSQA==" + }, "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "requires": { - "abbrev": "1" + "abbrev": "1", + "osenv": "^0.1.4" } }, + "normalize-email": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/normalize-email/-/normalize-email-1.1.1.tgz", + "integrity": "sha512-d5gghFO3BceKeZ+csXTsw2/qnuqZa5rHabXTtLg6XYEqlm25G7g0TNrPlB72+6qXFitSTHf+lHcJhm6bQurC+Q==" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -11589,12 +10603,20 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "normalize-url": { "version": "4.5.0", @@ -11605,7 +10627,6 @@ "version": "6.14.8", "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz", "integrity": "sha512-HBZVBMYs5blsj94GTeQZel7s9odVuuSUHy1+AlZh7rPVux1os2ashvEGLy/STNK7vUjbrCg5Kq9/GXisJgdf6A==", - "dev": true, "requires": { "JSONStream": "^1.3.5", "abbrev": "~1.1.1", @@ -11734,8 +10755,8 @@ "dependencies": { "JSONStream": { "version": "1.3.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" @@ -11743,29 +10764,29 @@ }, "abbrev": { "version": "1.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "agent-base": { "version": "4.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "requires": { "es6-promisify": "^5.0.0" } }, "agentkeepalive": { "version": "3.5.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "requires": { "humanize-ms": "^1.2.1" } }, "ajv": { "version": "5.5.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -11775,49 +10796,49 @@ }, "ansi-align": { "version": "2.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "requires": { "string-width": "^2.0.0" } }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "ansicolors": { "version": "0.3.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" }, "ansistyles": { "version": "0.1.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", + "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" }, "aproba": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "archy": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -11825,8 +10846,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -11839,8 +10860,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -11849,46 +10870,46 @@ }, "asap": { "version": "2.0.6", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { "version": "0.2.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { "safer-buffer": "~2.1.0" } }, "assert-plus": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "asynckit": { "version": "0.4.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "aws-sign2": { "version": "0.7.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.8.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "bcrypt-pbkdf": { "version": "1.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -11896,8 +10917,8 @@ }, "bin-links": { "version": "1.1.8", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.8.tgz", + "integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==", "requires": { "bluebird": "^3.5.3", "cmd-shim": "^3.0.0", @@ -11909,13 +10930,13 @@ }, "bluebird": { "version": "3.5.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" }, "boxen": { "version": "1.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "requires": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", @@ -11928,8 +10949,8 @@ }, "brace-expansion": { "version": "1.1.11", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -11937,28 +10958,28 @@ }, "buffer-from": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", + "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" }, "builtins": { "version": "1.0.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" }, "byline": { "version": "5.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" }, "byte-size": { "version": "5.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", + "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==" }, "cacache": { "version": "12.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", "requires": { "bluebird": "^3.5.5", "chownr": "^1.1.1", @@ -11979,28 +11000,28 @@ }, "call-limit": { "version": "1.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz", + "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==" }, "camelcase": { "version": "4.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" }, "capture-stack-trace": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" }, "caseless": { "version": "0.12.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { "version": "2.4.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -12009,31 +11030,31 @@ }, "chownr": { "version": "1.1.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "ci-info": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "cidr-regex": { "version": "2.0.10", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", + "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", "requires": { "ip-regex": "^2.1.0" } }, "cli-boxes": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, "cli-columns": { "version": "3.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", + "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", "requires": { "string-width": "^2.0.0", "strip-ansi": "^3.0.1" @@ -12041,8 +11062,8 @@ }, "cli-table3": { "version": "0.5.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", @@ -12051,8 +11072,8 @@ }, "cliui": { "version": "5.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -12061,18 +11082,18 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -12081,8 +11102,8 @@ }, "strip-ansi": { "version": "5.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { "ansi-regex": "^4.1.0" } @@ -12091,13 +11112,13 @@ }, "clone": { "version": "1.0.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" }, "cmd-shim": { "version": "3.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz", + "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==", "requires": { "graceful-fs": "^4.1.2", "mkdirp": "~0.5.0" @@ -12105,37 +11126,37 @@ }, "co": { "version": "4.6.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { "version": "1.9.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "requires": { "color-name": "^1.1.1" } }, "color-name": { "version": "1.1.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "1.3.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", "optional": true }, "columnify": { "version": "1.5.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", "requires": { "strip-ansi": "^3.0.0", "wcwidth": "^1.0.0" @@ -12143,21 +11164,21 @@ }, "combined-stream": { "version": "1.0.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -12167,8 +11188,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12181,8 +11202,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -12191,8 +11212,8 @@ }, "config-chain": { "version": "1.1.12", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -12200,8 +11221,8 @@ }, "configstore": { "version": "3.1.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", + "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", "requires": { "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", @@ -12213,13 +11234,13 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "copy-concurrently": { "version": "1.0.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -12231,33 +11252,33 @@ "dependencies": { "aproba": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "iferr": { "version": "0.1.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" } } }, "core-util-is": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-error-class": { "version": "3.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "requires": { "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { "version": "5.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -12266,8 +11287,8 @@ "dependencies": { "lru-cache": { "version": "4.1.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -12275,104 +11296,104 @@ }, "yallist": { "version": "2.1.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } }, "crypto-random-string": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" }, "cyclist": { "version": "0.2.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" }, "dashdash": { "version": "1.14.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { "assert-plus": "^1.0.0" } }, "debug": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" }, "dependencies": { "ms": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, "debuglog": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" }, "decamelize": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "deep-extend": { "version": "0.6.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "defaults": { "version": "1.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "requires": { "clone": "^1.0.2" } }, "define-properties": { "version": "1.1.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { "object-keys": "^1.0.12" } }, "delayed-stream": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "detect-indent": { "version": "5.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" }, "detect-newline": { "version": "2.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" }, "dezalgo": { "version": "1.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -12380,26 +11401,26 @@ }, "dot-prop": { "version": "4.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", + "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", "requires": { "is-obj": "^1.0.0" } }, "dotenv": { "version": "5.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", + "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" }, "duplexer3": { "version": "0.1.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, "duplexify": { "version": "3.6.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -12409,8 +11430,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12423,8 +11444,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -12433,8 +11454,8 @@ }, "ecc-jsbn": { "version": "0.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { "jsbn": "~0.1.0", @@ -12443,52 +11464,52 @@ }, "editor": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", + "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, "emoji-regex": { "version": "7.0.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "encoding": { "version": "0.1.12", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { "iconv-lite": "~0.4.13" } }, "end-of-stream": { "version": "1.4.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "^1.4.0" } }, "env-paths": { "version": "2.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", + "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" }, "err-code": { "version": "1.1.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" }, "errno": { "version": "0.1.7", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "requires": { "prr": "~1.0.1" } }, "es-abstract": { "version": "1.12.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", "requires": { "es-to-primitive": "^1.1.1", "function-bind": "^1.1.1", @@ -12499,8 +11520,8 @@ }, "es-to-primitive": { "version": "1.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -12509,26 +11530,26 @@ }, "es6-promise": { "version": "4.2.8", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, "es6-promisify": { "version": "5.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "execa": { "version": "0.7.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -12541,45 +11562,45 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" } } }, "extend": { "version": "3.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extsprintf": { "version": "1.3.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "fast-json-stable-stringify": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "figgy-pudding": { "version": "3.5.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, "find-npm-prefix": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", + "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==" }, "flush-write-stream": { "version": "1.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.4" @@ -12587,8 +11608,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12601,8 +11622,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -12611,13 +11632,13 @@ }, "forever-agent": { "version": "0.6.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", @@ -12626,8 +11647,8 @@ }, "from2": { "version": "2.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -12635,8 +11656,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12649,8 +11670,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -12659,16 +11680,16 @@ }, "fs-minipass": { "version": "1.2.7", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "requires": { "minipass": "^2.6.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -12678,8 +11699,8 @@ }, "fs-vacuum": { "version": "1.2.10", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", + "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", "requires": { "graceful-fs": "^4.1.2", "path-is-inside": "^1.0.1", @@ -12688,8 +11709,8 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -12699,13 +11720,13 @@ "dependencies": { "iferr": { "version": "0.1.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12718,8 +11739,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -12728,18 +11749,18 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { "version": "1.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gauge": { "version": "2.7.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -12753,13 +11774,13 @@ "dependencies": { "aproba": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "string-width": { "version": "1.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -12770,13 +11791,13 @@ }, "genfun": { "version": "5.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==" }, "gentle-fs": { "version": "2.3.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.1.tgz", + "integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==", "requires": { "aproba": "^1.1.2", "chownr": "^1.1.2", @@ -12793,41 +11814,41 @@ "dependencies": { "aproba": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "iferr": { "version": "0.1.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" } } }, "get-caller-file": { "version": "2.0.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-stream": { "version": "4.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "requires": { "pump": "^3.0.0" } }, "getpass": { "version": "0.1.7", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12839,16 +11860,16 @@ }, "global-dirs": { "version": "0.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "requires": { "ini": "^1.3.4" } }, "got": { "version": "6.7.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -12865,25 +11886,25 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" } } }, "graceful-fs": { "version": "4.2.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, "har-schema": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { "ajv": "^5.3.0", "har-schema": "^2.0.0" @@ -12891,41 +11912,41 @@ }, "has": { "version": "1.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, "has-unicode": { "version": "2.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "hosted-git-info": { "version": "2.8.8", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, "http-cache-semantics": { "version": "3.8.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" }, "http-proxy-agent": { "version": "2.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "requires": { "agent-base": "4", "debug": "3.1.0" @@ -12933,8 +11954,8 @@ }, "http-signature": { "version": "1.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -12943,8 +11964,8 @@ }, "https-proxy-agent": { "version": "2.2.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -12952,52 +11973,52 @@ }, "humanize-ms": { "version": "1.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", "requires": { "ms": "^2.0.0" } }, "iconv-lite": { "version": "0.4.23", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "iferr": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", + "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==" }, "ignore-walk": { "version": "3.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "requires": { "minimatch": "^3.0.4" } }, "import-lazy": { "version": "2.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" }, "imurmurhash": { "version": "0.1.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "infer-owner": { "version": "1.0.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "inflight": { "version": "1.0.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -13005,18 +12026,18 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "init-package-json": { "version": "1.10.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", + "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", "requires": { "glob": "^7.1.1", "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", @@ -13030,59 +12051,59 @@ }, "ip": { "version": "1.1.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "ip-regex": { "version": "2.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "is-callable": { "version": "1.1.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { "version": "1.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { "ci-info": "^1.5.0" }, "dependencies": { "ci-info": { "version": "1.6.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" } } }, "is-cidr": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", + "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", "requires": { "cidr-regex": "^2.0.10" } }, "is-date-object": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" } }, "is-installed-globally": { "version": "0.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "requires": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" @@ -13090,108 +12111,108 @@ }, "is-npm": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" }, "is-obj": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-path-inside": { "version": "1.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "requires": { "path-is-inside": "^1.0.1" } }, "is-redirect": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, "is-regex": { "version": "1.0.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "requires": { "has": "^1.0.1" } }, "is-retry-allowed": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, "is-stream": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-symbol": { "version": "1.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "requires": { "has-symbols": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "isarray": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isstream": { "version": "0.1.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jsbn": { "version": "0.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, "json-parse-better-errors": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.3.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, "json-stringify-safe": { "version": "5.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "jsonparse": { "version": "1.3.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" }, "jsprim": { "version": "1.4.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -13201,21 +12222,21 @@ }, "latest-version": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "requires": { "package-json": "^4.0.0" } }, "lazy-property": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", + "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" }, "libcipm": { "version": "4.0.8", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.8.tgz", + "integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==", "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.1", @@ -13236,8 +12257,8 @@ }, "libnpm": { "version": "3.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz", + "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==", "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.3", @@ -13263,8 +12284,8 @@ }, "libnpmaccess": { "version": "3.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", + "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", "requires": { "aproba": "^2.0.0", "get-stream": "^4.0.0", @@ -13274,8 +12295,8 @@ }, "libnpmconfig": { "version": "1.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", + "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", "requires": { "figgy-pudding": "^3.5.1", "find-up": "^3.0.0", @@ -13284,16 +12305,16 @@ "dependencies": { "find-up": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -13301,31 +12322,31 @@ }, "p-limit": { "version": "2.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" } } }, "libnpmhook": { "version": "5.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz", + "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==", "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -13335,8 +12356,8 @@ }, "libnpmorg": { "version": "1.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz", + "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==", "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -13346,8 +12367,8 @@ }, "libnpmpublish": { "version": "1.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz", + "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==", "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.5.1", @@ -13362,8 +12383,8 @@ }, "libnpmsearch": { "version": "2.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz", + "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==", "requires": { "figgy-pudding": "^3.5.1", "get-stream": "^4.0.0", @@ -13372,8 +12393,8 @@ }, "libnpmteam": { "version": "1.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz", + "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==", "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -13383,8 +12404,8 @@ }, "libnpx": { "version": "10.2.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.4.tgz", + "integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==", "requires": { "dotenv": "^5.0.1", "npm-package-arg": "^6.0.0", @@ -13398,8 +12419,8 @@ }, "lock-verify": { "version": "2.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", + "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", "requires": { "npm-package-arg": "^6.1.0", "semver": "^5.4.1" @@ -13407,21 +12428,21 @@ }, "lockfile": { "version": "1.0.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", "requires": { "signal-exit": "^3.0.2" } }, "lodash._baseindexof": { "version": "3.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", + "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" }, "lodash._baseuniq": { "version": "4.6.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", + "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", "requires": { "lodash._createset": "~4.0.0", "lodash._root": "~3.0.0" @@ -13429,87 +12450,87 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" }, "lodash._cacheindexof": { "version": "3.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", + "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" }, "lodash._createcache": { "version": "3.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", "requires": { "lodash._getnative": "^3.0.0" } }, "lodash._createset": { "version": "4.0.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", + "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" }, "lodash._getnative": { "version": "3.9.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" }, "lodash._root": { "version": "3.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" }, "lodash.clonedeep": { "version": "4.5.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, "lodash.restparam": { "version": "3.6.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" }, "lodash.union": { "version": "4.6.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, "lodash.uniq": { "version": "4.5.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "lodash.without": { "version": "4.4.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", + "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" }, "lowercase-keys": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "lru-cache": { "version": "5.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { "yallist": "^3.0.2" } }, "make-dir": { "version": "1.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "requires": { "pify": "^3.0.0" } }, "make-fetch-happen": { "version": "5.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", "requires": { "agentkeepalive": "^3.4.1", "cacache": "^12.0.0", @@ -13526,47 +12547,47 @@ }, "meant": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.2.tgz", + "integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg==" }, "mime-db": { "version": "1.35.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" }, "mime-types": { "version": "2.1.19", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "requires": { "mime-db": "~1.35.0" } }, "minimatch": { "version": "3.0.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minizlib": { "version": "1.3.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "requires": { "minipass": "^2.9.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13576,8 +12597,8 @@ }, "mississippi": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -13593,23 +12614,23 @@ }, "mkdirp": { "version": "0.5.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { "minimist": "^1.2.5" }, "dependencies": { "minimist": { "version": "1.2.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } }, "move-concurrently": { "version": "1.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -13621,25 +12642,25 @@ "dependencies": { "aproba": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" } } }, "ms": { "version": "2.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mute-stream": { "version": "0.0.7", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, "node-fetch-npm": { "version": "2.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", "requires": { "encoding": "^0.1.11", "json-parse-better-errors": "^1.0.0", @@ -13648,8 +12669,8 @@ }, "node-gyp": { "version": "5.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", + "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -13666,8 +12687,8 @@ }, "nopt": { "version": "4.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -13675,8 +12696,8 @@ }, "normalize-package-data": { "version": "2.5.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -13686,8 +12707,8 @@ "dependencies": { "resolve": { "version": "1.10.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "requires": { "path-parse": "^1.0.6" } @@ -13696,8 +12717,8 @@ }, "npm-audit-report": { "version": "1.3.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.3.tgz", + "integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==", "requires": { "cli-table3": "^0.5.0", "console-control-strings": "^1.1.0" @@ -13705,29 +12726,29 @@ }, "npm-bundled": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", "requires": { "npm-normalize-package-bin": "^1.0.1" } }, "npm-cache-filename": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", + "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" }, "npm-install-checks": { "version": "3.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz", + "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==", "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" } }, "npm-lifecycle": { "version": "3.1.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", + "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", "requires": { "byline": "^5.0.0", "graceful-fs": "^4.1.15", @@ -13741,18 +12762,18 @@ }, "npm-logical-tree": { "version": "1.2.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", + "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==" }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-package-arg": { "version": "6.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "requires": { "hosted-git-info": "^2.7.1", "osenv": "^0.1.5", @@ -13762,8 +12783,8 @@ }, "npm-packlist": { "version": "1.4.8", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -13772,8 +12793,8 @@ }, "npm-pick-manifest": { "version": "3.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", "requires": { "figgy-pudding": "^3.5.1", "npm-package-arg": "^6.0.0", @@ -13782,8 +12803,8 @@ }, "npm-profile": { "version": "4.0.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", + "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", "requires": { "aproba": "^1.1.2 || 2", "figgy-pudding": "^3.4.1", @@ -13792,8 +12813,8 @@ }, "npm-registry-fetch": { "version": "4.0.7", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz", + "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==", "requires": { "JSONStream": "^1.3.4", "bluebird": "^3.5.1", @@ -13806,23 +12827,28 @@ "dependencies": { "safe-buffer": { "version": "5.2.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, "npm-run-path": { "version": "2.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { "path-key": "^2.0.0" } }, + "npm-user-validate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz", + "integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=" + }, "npmlog": { "version": "4.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -13832,28 +12858,28 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-keys": { "version": "1.0.12", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" }, "object.getownpropertydescriptors": { "version": "2.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -13861,31 +12887,31 @@ }, "once": { "version": "1.4.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" }, "os-homedir": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { "version": "0.1.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -13893,13 +12919,13 @@ }, "p-finally": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "package-json": { "version": "4.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "requires": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", @@ -13909,8 +12935,8 @@ }, "pacote": { "version": "9.5.12", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", + "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", "requires": { "bluebird": "^3.5.3", "cacache": "^12.0.2", @@ -13946,8 +12972,8 @@ "dependencies": { "minipass": { "version": "2.9.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13957,8 +12983,8 @@ }, "parallel-transform": { "version": "1.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "requires": { "cyclist": "~0.2.2", "inherits": "^2.0.3", @@ -13967,8 +12993,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13981,8 +13007,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -13991,58 +13017,58 @@ }, "path-exists": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "path-key": { "version": "2.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { "version": "1.0.6", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "performance-now": { "version": "2.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "prepend-http": { "version": "1.0.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "promise-inflight": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, "promise-retry": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", "requires": { "err-code": "^1.0.0", "retry": "^0.10.0" @@ -14050,51 +13076,51 @@ "dependencies": { "retry": { "version": "0.10.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" } } }, "promzard": { "version": "0.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", "requires": { "read": "1" } }, "proto-list": { "version": "1.2.4", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" }, "protoduck": { "version": "5.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", "requires": { "genfun": "^5.0.0" } }, "prr": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, "pseudomap": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { "version": "1.1.29", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, "pump": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -14102,8 +13128,8 @@ }, "pumpify": { "version": "1.5.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -14112,8 +13138,8 @@ "dependencies": { "pump": { "version": "2.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -14123,23 +13149,23 @@ }, "punycode": { "version": "1.4.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qrcode-terminal": { "version": "0.12.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==" }, "qs": { "version": "6.5.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "6.8.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz", + "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==", "requires": { "decode-uri-component": "^0.2.0", "split-on-first": "^1.0.0", @@ -14148,13 +13174,13 @@ }, "qw": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", + "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=" }, "rc": { "version": "1.2.8", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -14164,24 +13190,24 @@ }, "read": { "version": "1.0.7", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "1.0.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", + "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", "requires": { "graceful-fs": "^4.1.2" } }, "read-installed": { "version": "4.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", "requires": { "debuglog": "^1.0.1", "graceful-fs": "^4.1.2", @@ -14194,8 +13220,8 @@ }, "read-package-json": { "version": "2.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", "requires": { "glob": "^7.1.1", "graceful-fs": "^4.1.2", @@ -14206,8 +13232,8 @@ }, "read-package-tree": { "version": "5.3.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", "requires": { "read-package-json": "^2.0.0", "readdir-scoped-modules": "^1.0.0", @@ -14216,8 +13242,8 @@ }, "readable-stream": { "version": "3.6.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14226,8 +13252,8 @@ }, "readdir-scoped-modules": { "version": "1.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -14237,8 +13263,8 @@ }, "registry-auth-token": { "version": "3.4.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -14246,16 +13272,16 @@ }, "registry-url": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "requires": { "rc": "^1.0.1" } }, "request": { "version": "2.88.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -14281,115 +13307,115 @@ }, "require-directory": { "version": "2.1.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve-from": { "version": "4.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, "retry": { "version": "0.12.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, "rimraf": { "version": "2.7.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } }, "run-queue": { "version": "1.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { "aproba": "^1.1.1" }, "dependencies": { "aproba": { "version": "1.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" } } }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { "version": "5.7.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-diff": { "version": "2.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "requires": { "semver": "^5.0.3" } }, "set-blocking": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "sha": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz", + "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==", "requires": { "graceful-fs": "^4.1.2" } }, "shebang-command": { "version": "1.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "signal-exit": { "version": "3.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "slide": { "version": "1.1.6", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, "smart-buffer": { "version": "4.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" }, "socks": { "version": "2.3.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", "requires": { "ip": "1.1.5", "smart-buffer": "^4.1.0" @@ -14397,8 +13423,8 @@ }, "socks-proxy-agent": { "version": "4.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", "requires": { "agent-base": "~4.2.1", "socks": "~2.3.2" @@ -14406,8 +13432,8 @@ "dependencies": { "agent-base": { "version": "4.2.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "requires": { "es6-promisify": "^5.0.0" } @@ -14416,13 +13442,13 @@ }, "sorted-object": { "version": "2.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", + "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" }, "sorted-union-stream": { "version": "2.1.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", + "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", "requires": { "from2": "^1.3.0", "stream-iterate": "^1.1.0" @@ -14430,8 +13456,8 @@ "dependencies": { "from2": { "version": "1.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", + "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", "requires": { "inherits": "~2.0.1", "readable-stream": "~1.1.10" @@ -14439,13 +13465,13 @@ }, "isarray": { "version": "0.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "readable-stream": { "version": "1.1.14", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -14455,15 +13481,15 @@ }, "string_decoder": { "version": "0.10.31", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } }, "spdx-correct": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -14471,13 +13497,13 @@ }, "spdx-exceptions": { "version": "2.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" }, "spdx-expression-parse": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -14485,18 +13511,18 @@ }, "spdx-license-ids": { "version": "3.0.5", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" }, "split-on-first": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" }, "sshpk": { "version": "1.14.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -14511,16 +13537,16 @@ }, "ssri": { "version": "6.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { "figgy-pudding": "^3.5.1" } }, "stream-each": { "version": "1.2.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", + "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -14528,8 +13554,8 @@ }, "stream-iterate": { "version": "1.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", + "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", "requires": { "readable-stream": "^2.1.5", "stream-shift": "^1.0.0" @@ -14537,8 +13563,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14551,8 +13577,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -14561,18 +13587,18 @@ }, "stream-shift": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, "strict-uri-encode": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" }, "string-width": { "version": "2.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -14580,18 +13606,18 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "strip-ansi": { "version": "4.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { "ansi-regex": "^3.0.0" } @@ -14600,54 +13626,54 @@ }, "string_decoder": { "version": "1.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { "safe-buffer": "~5.2.0" }, "dependencies": { "safe-buffer": { "version": "5.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } }, "stringify-package": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", + "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==" }, "strip-ansi": { "version": "3.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" } }, "strip-eof": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { "version": "5.4.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { "has-flag": "^3.0.0" } }, "tar": { "version": "4.4.13", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -14660,8 +13686,8 @@ "dependencies": { "minipass": { "version": "2.9.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -14671,26 +13697,26 @@ }, "term-size": { "version": "1.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "requires": { "execa": "^0.7.0" } }, "text-table": { "version": "0.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "through": { "version": "2.3.8", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" @@ -14698,8 +13724,8 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14712,8 +13738,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -14722,18 +13748,18 @@ }, "timed-out": { "version": "4.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, "tiny-relative-date": { "version": "1.3.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", + "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==" }, "tough-cookie": { "version": "2.4.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -14741,71 +13767,71 @@ }, "tunnel-agent": { "version": "0.6.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, "typedarray": { "version": "0.0.6", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uid-number": { "version": "0.0.6", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" }, "umask": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" }, "unique-filename": { "version": "1.1.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", "requires": { "imurmurhash": "^0.1.4" } }, "unique-string": { "version": "1.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "requires": { "crypto-random-string": "^1.0.0" } }, "unpipe": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "unzip-response": { "version": "2.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" }, "update-notifier": { "version": "2.5.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", @@ -14821,39 +13847,39 @@ }, "url-parse-lax": { "version": "1.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "requires": { "prepend-http": "^1.0.1" } }, "util-deprecate": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util-extend": { "version": "1.0.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" }, "util-promisify": { "version": "2.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", "requires": { "object.getownpropertydescriptors": "^2.0.3" } }, "uuid": { "version": "3.3.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" }, "validate-npm-package-license": { "version": "3.0.4", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -14861,16 +13887,16 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", "requires": { "builtins": "^1.0.3" } }, "verror": { "version": "1.10.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -14879,37 +13905,37 @@ }, "wcwidth": { "version": "1.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "requires": { "defaults": "^1.0.3" } }, "which": { "version": "1.3.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, "wide-align": { "version": "1.1.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "requires": { "string-width": "^1.0.2" }, "dependencies": { "string-width": { "version": "1.0.2", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -14920,24 +13946,24 @@ }, "widest-line": { "version": "2.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "requires": { "string-width": "^2.1.1" } }, "worker-farm": { "version": "1.7.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "requires": { "errno": "~0.1.7" } }, "wrap-ansi": { "version": "5.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -14946,18 +13972,18 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -14966,8 +13992,8 @@ }, "strip-ansi": { "version": "5.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { "ansi-regex": "^4.1.0" } @@ -14976,13 +14002,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -14991,28 +14017,28 @@ }, "xdg-basedir": { "version": "3.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" }, "xtend": { "version": "4.0.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { "version": "4.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yallist": { "version": "3.0.3", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { "version": "14.2.3", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", "requires": { "cliui": "^5.0.0", "decamelize": "^1.2.0", @@ -15029,26 +14055,26 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "find-up": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { "locate-path": "^3.0.0" } }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "locate-path": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -15056,29 +14082,29 @@ }, "p-limit": { "version": "2.3.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "string-width": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -15087,8 +14113,8 @@ }, "strip-ansi": { "version": "5.2.0", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { "ansi-regex": "^4.1.0" } @@ -15097,8 +14123,8 @@ }, "yargs-parser": { "version": "15.0.1", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -15106,35 +14132,59 @@ "dependencies": { "camelcase": { "version": "5.3.1", - "bundled": true, - "dev": true + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" } } } } }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - } + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, - "npm-user-validate": { + "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.1.tgz", - "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==", - "dev": true + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { "version": "2.2.0", @@ -15157,6 +14207,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -15167,6 +14218,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -15175,26 +14227,40 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==" + }, "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-literal-parse": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object-literal-parse/-/object-literal-parse-2.1.0.tgz", + "integrity": "sha512-qf+vlxH1jZalwOnENjzgPrrDs1kkWSaGallQflnLcDBVYVKSdf3yg5+XMZ8LG9uuRbuwOLKWeM3J/K89DpAH5A==" }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, "requires": { "isobject": "^3.0.0" } @@ -15203,21 +14269,57 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, "requires": { "isobject": "^3.0.1" } }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -15239,141 +14341,128 @@ "wrappy": "1" } }, - "onchange": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/onchange/-/onchange-7.0.2.tgz", - "integrity": "sha512-pyJroR9gZKilbJtdGsuyxhFhwaeYSpYVle9hAORGJ5vQQH8n7QT+qWpncJTMEk9dlIXI9tOMjdJwbPaTSPTKFA==", + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "requires": { - "@blakeembrey/deque": "^1.0.5", - "@blakeembrey/template": "^1.0.0", - "arg": "^4.1.3", - "chokidar": "^3.3.1", - "cross-spawn": "^7.0.1", - "ignore": "^5.1.4", - "tree-kill": "^1.2.2" + "mimic-fn": "^2.1.0" + } + }, + "optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "ora": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz", + "integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.4.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "dependencies": { - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", - "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { - "to-regex-range": "^5.0.1" + "color-convert": "^2.0.1" } }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, "requires": { - "is-glob": "^4.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { - "binary-extensions": "^2.0.0" + "color-name": "~1.1.4" } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", - "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", - "requires": { - "picomatch": "^2.2.1" - } + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" + "has-flag": "^4.0.0" + } + } } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-name": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", - "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.0.tgz", + "integrity": "sha512-caABzDdJMbtykt7GmSogEat3faTKQhmZf0BS5l/pZGmP0vPWQjXWqOhbLyK+b6j2/DQPmEvYdzLXJXXLJNVDNg==", "dev": true, "requires": { "macos-release": "^2.2.0", - "windows-release": "^3.1.0" + "windows-release": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "otplib": { @@ -15387,21 +14476,24 @@ } }, "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==" + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, "p-each-series": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", - "dev": true + "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==" }, "p-filter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", - "dev": true, "requires": { "p-map": "^2.0.0" } @@ -15409,14 +14501,12 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "p-is-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==" }, "p-limit": { "version": "2.3.0", @@ -15437,57 +14527,44 @@ "p-map": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "requires": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + } }, "p-reduce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", - "dev": true + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==" }, "p-retry": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz", "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==", - "dev": true, "requires": { "@types/retry": "^0.12.0", "retry": "^0.12.0" } }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "param-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", - "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", - "requires": { - "dot-case": "^3.0.3", - "tslib": "^1.10.0" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -15497,13 +14574,13 @@ } }, "parse-json": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz", - "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, @@ -15511,7 +14588,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.2.tgz", "integrity": "sha512-HSqVz6iuXSiL8C1ku5Gl1Z5cwDd9Wo0q8CoffdAghP6bz8pJa1tcMC+m4N+z6VAS8QdksnIGq1TB6EgR4vPR6w==", - "dev": true, "requires": { "is-ssh": "^1.3.0", "protocols": "^1.4.0" @@ -15521,7 +14597,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.2.tgz", "integrity": "sha512-Czj+GIit4cdWtxo3ISZCvLiUjErSo0iI3wJ+q9Oi3QuMYTI6OZu+7cewMWZ+C1YAnKhYTk6/TLuhIgCypLthPA==", - "dev": true, "requires": { "is-ssh": "^1.3.0", "normalize-url": "^3.3.0", @@ -15532,8 +14607,7 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" } } }, @@ -15548,34 +14622,42 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "pascal-case": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", - "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0" - } - }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true }, - "path-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.3.tgz", - "integrity": "sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==", + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", "requires": { - "dot-case": "^3.0.3", - "tslib": "^1.10.0" + "passport-strategy": "1.x.x", + "pause": "0.0.1" } }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "optional": true + "passport-headerapikey": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", + "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", + "requires": { + "lodash": "^4.17.15", + "passport-strategy": "^1.0.0" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, "path-exists": { "version": "3.0.0", @@ -15598,15 +14680,20 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", + "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==" }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -15649,6 +14736,17 @@ "locate-path": "^2.0.0" } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -15678,6 +14776,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } } } }, @@ -15726,93 +14833,58 @@ } } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, "pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" }, - "popsicle": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/popsicle/-/popsicle-12.0.5.tgz", - "integrity": "sha512-PZt2+KfNQVwYXEwaAdJPLsYFJ+j0M25+26GhBovxhq9TZFRJfigAlJ5JfioCf/9R4RcTSu9VeaovJcb20Br7mw==", - "requires": { - "popsicle-content-encoding": "^1.0.0", - "popsicle-cookie-jar": "^1.0.0", - "popsicle-redirects": "^1.1.0", - "popsicle-transport-http": "^1.0.6", - "popsicle-transport-xhr": "^1.0.2", - "popsicle-user-agent": "^1.0.0", - "servie": "^4.3.2", - "throwback": "^4.1.0", - "tough-cookie": "^3.0.1" - } - }, - "popsicle-content-encoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/popsicle-content-encoding/-/popsicle-content-encoding-1.0.0.tgz", - "integrity": "sha512-4Df+vTfM8wCCJVTzPujiI6eOl3SiWQkcZg0AMrOkD1enMXsF3glIkFUZGvour1Sj7jOWCsNSEhBxpbbhclHhzw==" - }, - "popsicle-cookie-jar": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/popsicle-cookie-jar/-/popsicle-cookie-jar-1.0.0.tgz", - "integrity": "sha512-vrlOGvNVELko0+J8NpGC5lHWDGrk8LQJq9nwAMIVEVBfN1Lib3BLxAaLRGDTuUnvl45j5N9dT2H85PULz6IjjQ==", - "requires": { - "@types/tough-cookie": "^2.3.5", - "tough-cookie": "^3.0.1" - } - }, - "popsicle-redirects": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/popsicle-redirects/-/popsicle-redirects-1.1.0.tgz", - "integrity": "sha512-XCpzVjVk7tty+IJnSdqWevmOr1n8HNDhL86v7mZ6T1JIIf2KGybxUk9mm7ZFOhWMkGB0e8XkacHip7BV8AQWQA==" - }, - "popsicle-transport-http": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/popsicle-transport-http/-/popsicle-transport-http-1.0.8.tgz", - "integrity": "sha512-5jeUUNSAElwNnFkb6LE1b/YlOHlaFWKN8N8BBdHZWIK6QQzb34nuXkbKJZxn7xK5VrGpCAraHayycQf7KpIJOw==", - "requires": { - "make-error-cause": "^2.2.0", - "pump": "^3.0.0" - } - }, - "popsicle-transport-xhr": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/popsicle-transport-xhr/-/popsicle-transport-xhr-1.0.2.tgz", - "integrity": "sha512-v9eAJnj1tydT4VmDdyKFE1z/+oL01vB7AS3LfSFMAYv33dzqlxtbApKALcYWBQotIqw3FoIqd2FiDR6qJsOxtA==" - }, - "popsicle-user-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/popsicle-user-agent/-/popsicle-user-agent-1.0.0.tgz", - "integrity": "sha512-epKaq3TTfTzXcxBxjpoKYMcTTcAX8Rykus6QZu77XNhJuRHSRxMd+JJrbX/3PFI0opFGSN0BabbAYCbGxbu0mA==" + "pop-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz", + "integrity": "sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M=" }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true }, "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + "prettier": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "dev": true }, "pretty-format": { - "version": "26.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.0.tgz", - "integrity": "sha512-Uumr9URVB7bm6SbaByXtx+zGlS+0loDkFMHP0kHahMjmfCtmFY03iqd++5v3Ld6iB5TocVXlBN/T+DXMn9d4BA==", + "version": "26.6.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.1.tgz", + "integrity": "sha512-MeqqsP5PYcRBbGMvwzsyBdmAJ4EFX7pWFyl7x4+dMVg5pE0ZDdBIvEH2ergvIO+Gvwv1wh64YuOY9y5LuyY/GA==", "dev": true, "requires": { - "@jest/types": "^26.6.0", + "@jest/types": "^26.6.1", "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" + "react-is": "^17.0.1" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -15847,7 +14919,8 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, "prompts": { "version": "2.4.0", @@ -15862,8 +14935,7 @@ "protocols": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", - "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", - "dev": true + "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==" }, "proxy-addr": { "version": "2.0.6", @@ -15874,15 +14946,17 @@ "ipaddr.js": "1.9.1" } }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true }, "pump": { "version": "3.0.0", @@ -15894,24 +14968,21 @@ } }, "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, - "pupa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", - "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "q": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", + "integrity": "sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ=", "requires": { - "escape-goat": "^2.0.0" + "asap": "^2.0.0", + "pop-iterate": "^1.0.1", + "weak-map": "^1.0.5" } }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, "qrcode": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz", @@ -15926,42 +14997,124 @@ "yargs": "^13.2.4" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.1.tgz", + "integrity": "sha512-2z15UUHpS9/3tk9mY/q+Rl3rydOi7yMp5XWNQnRvoz+mJwiv8brqYwp9a+nOCtma6dwuEIxljD8W3ysVBZ05Vg==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" }, - "random-int": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/random-int/-/random-int-2.0.1.tgz", - "integrity": "sha512-YALjWK2Rt9EMIv9BF/3mvlzFWQathsvb5UZmN1QmhfIOfcQYXc/UcLzg0ablqesSBpBVLt2Tlwv/eTuBh4LXUQ==" + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } }, "randomcolor": { "version": "0.6.2", @@ -15973,6 +15126,11 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "rate-limiter-flexible": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.1.10.tgz", + "integrity": "sha512-Pa+8TPD4xYaiCUB5K4a/+j2FHDUe4HP1g49JmKEmkOkhqPaeVqxJsZuuVaza/svSCOT+V73vtsyBiSFK/e1yXw==" + }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", @@ -15993,148 +15151,137 @@ "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } } }, "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", "dev": true }, "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, "requires": { + "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" + "path-type": "^2.0.0" }, "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "pify": "^2.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" }, "dependencies": { "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "requires": { + "locate-path": "^2.0.0" } }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "p-try": "^1.0.0" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } + "p-limit": "^1.1.0" } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true } } }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "optional": true, + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.2.1" } }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, "requires": { "resolve": "^1.1.6" } }, - "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", - "requires": { - "minimatch": "3.0.4" - } - }, "redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, "requires": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" @@ -16144,92 +15291,30 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "dev": true, "requires": { "esprima": "~4.0.0" } }, - "redis": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz", - "integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==", - "requires": { - "denque": "^1.4.1", - "redis-commands": "^1.5.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - } - }, - "redis-commands": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", - "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==" - }, - "redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" - }, - "redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", - "requires": { - "redis-errors": "^1.0.0" - } - }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, - "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==" - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true }, "registry-auth-token": { "version": "4.2.0", @@ -16239,48 +15324,23 @@ "rc": "^1.2.8" } }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "requires": { - "rc": "^1.2.8" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "request": { "version": "2.88.2", @@ -16310,23 +15370,6 @@ "uuid": "^3.3.2" }, "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -16342,9 +15385,23 @@ "psl": "^1.1.28", "punycode": "^2.1.1" } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, + "request-ip": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-2.1.3.tgz", + "integrity": "sha512-J3qdE/IhVM3BXkwMIVO4yFrvhJlU3H7JH16+6yHucadT4fePnR8dyh+vEs6FIx0S2x5TCt2ptiPfHcn0sqhbYQ==", + "requires": { + "is_js": "^0.9.0" + } + }, "request-promise-core": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", @@ -16365,12 +15422,6 @@ "tough-cookie": "^2.3.3" }, "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -16393,14 +15444,25 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", "requires": { + "is-core-module": "^2.0.0", "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz", + "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==" + }, "resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -16426,7 +15488,8 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true }, "response-time": { "version": "2.3.2", @@ -16438,23 +15501,33 @@ } }, "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, "requires": { - "lowercase-keys": "^1.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" } }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, "reusify": { "version": "1.0.4", @@ -16469,15 +15542,10 @@ "glob": "^7.1.3" } }, - "rsmq": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/rsmq/-/rsmq-0.12.2.tgz", - "integrity": "sha512-Rr1S/YH3hQ1X4rLSkHXL9odEJldE/wtfvZxPAMRyNR3Bb5d6wiRERIAaM6CfINNd9V2H/wdoC/yNixiv+Ehvjw==", - "requires": { - "@types/redis": "^2.8.18", - "lodash": "^4.17.15", - "redis": "^3.0.2" - } + "rootpath": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz", + "integrity": "sha1-Wzeah9ypBum5HWkKWZQ5vvJn6ms=" }, "rsvp": { "version": "4.8.5", @@ -16485,10 +15553,16 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", + "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==" }, "rxjs": { "version": "6.6.3", @@ -16496,6 +15570,13 @@ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "safe-buffer": { @@ -16507,6 +15588,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, "requires": { "ret": "~0.1.10" } @@ -16531,12 +15613,224 @@ "micromatch": "^3.1.4", "minimist": "^1.1.1", "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "saxes": { "version": "5.0.1", @@ -16547,16 +15841,26 @@ "xmlchars": "^2.2.0" } }, - "secure-json-parse": { + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "scmp": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.1.0.tgz", - "integrity": "sha512-GckO+MS/wT4UogDyoI/H/S1L0MCcKS1XX/vp48wfmU7Nw4woBmb8mIpu4zPBQjKlRT88/bt9xdoV4111jPpNJA==" + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" }, "semantic-release": { "version": "17.2.2", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.2.2.tgz", "integrity": "sha512-LNU68ud3a3oU46H11OThXaKAK430jGGGTIF4VsiP843kRmS6s8kVCceLRdi7yWWz/sCCMD0zygPTQV2Jw79J5g==", - "dev": true, "requires": { "@semantic-release/commit-analyzer": "^8.0.0", "@semantic-release/error": "^2.2.0", @@ -16588,158 +15892,48 @@ "yargs": "^15.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "to-regex-range": "^5.0.1" + "ms": "2.1.2" } }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "hosted-git-info": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "requires": { "p-locate": "^4.1.0" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "requires": { "p-limit": "^2.2.0" } @@ -16747,69 +15941,45 @@ "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } } }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" } }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" } } }, @@ -16817,7 +15987,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/semantic-release-gitmoji/-/semantic-release-gitmoji-1.3.4.tgz", "integrity": "sha512-uuuEmlhCwnSm3KMhu/bO2TMza/Fh8tZ8XVarHBVOVReSoGlJZKXn/TI1BSCgs2iPaxEJM3yJQ/zVCJISwfPtrQ==", - "dev": true, "requires": { "dateformat": "^3.0.3", "debug": "^4.1.1", @@ -16831,18 +16000,30 @@ "node-emoji": "^1.10.0" }, "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, "emoji-regex": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.0.0.tgz", - "integrity": "sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w==", - "dev": true + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", + "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" }, "semver-diff": { "version": "3.1.1", @@ -16862,8 +16043,7 @@ "semver-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", - "dev": true + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==" }, "send": { "version": "0.17.1", @@ -16885,21 +16065,6 @@ "statuses": "~1.5.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -16907,14 +16072,13 @@ } } }, - "sentence-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.3.tgz", - "integrity": "sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==", + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0", - "upper-case-first": "^2.0.1" + "randombytes": "^2.1.0" } }, "serve-static": { @@ -16928,15 +16092,6 @@ "send": "0.17.1" } }, - "servie": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/servie/-/servie-4.3.2.tgz", - "integrity": "sha512-1NpFf3LjkDDq4IIuBqtqHfSdPWhXpuyWwuBdwbifZjWSxQd8rCWz5W9AluxNvWfteM1qQ26puODIzWljvBJc5A==", - "requires": { - "@servie/events": "^1.0.0", - "byte-length": "^1.0.2" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -16946,6 +16101,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -16957,6 +16113,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -16985,6 +16142,7 @@ "version": "0.8.4", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -17011,6 +16169,16 @@ "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + } } }, "sisteransi": { @@ -17020,28 +16188,34 @@ "dev": true }, "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "slugify": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.5.tgz", - "integrity": "sha512-WpECLAgYaxHoEAJ8Q1Lo8HOs1ngn7LN7QjXgOLbmmfkcWvosyk4ZTXkTzKyhngK640USTZUlgoQJfED1kz5fnQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, - "snake-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz", - "integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==", + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, "requires": { - "dot-case": "^3.0.3", - "tslib": "^1.10.0" + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", @@ -17053,18 +16227,11 @@ "use": "^3.1.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -17073,14 +16240,16 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true } } }, @@ -17088,6 +16257,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -17098,6 +16268,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -17106,6 +16277,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -17114,6 +16286,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -17122,6 +16295,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -17134,6 +16308,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, "requires": { "kind-of": "^3.2.0" }, @@ -17142,21 +16317,30 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, "requires": { "atob": "^2.1.2", "decode-uri-component": "^0.2.0", @@ -17186,18 +16370,19 @@ "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true }, - "spawn-command": { - "version": "0.0.2-1", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=" + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true }, "spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", - "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", - "dev": true + "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=" }, "spdx-correct": { "version": "3.1.1", @@ -17223,15 +16408,14 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==" }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, "requires": { "through": "2" } @@ -17240,6 +16424,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, "requires": { "extend-shallow": "^3.0.0" } @@ -17248,16 +16433,41 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", - "dev": true, "requires": { "through2": "^2.0.2" }, "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -17271,11 +16481,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sqlstring": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", - "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" - }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -17314,6 +16519,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -17323,6 +16529,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -17344,12 +16551,45 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string-length": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", @@ -17371,24 +16611,27 @@ } }, "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", + "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" }, "dependencies": { "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", "is-regex": "^1.1.1", "object-inspect": "^1.8.0", "object-keys": "^1.1.1", @@ -17400,24 +16643,27 @@ } }, "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", + "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" }, "dependencies": { "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", "is-regex": "^1.1.1", "object-inspect": "^1.8.0", "object-keys": "^1.1.1", @@ -17429,12 +16675,9 @@ } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, "strip-ansi": { "version": "6.0.0", @@ -17442,6 +16685,13 @@ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { "ansi-regex": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + } } }, "strip-bom": { @@ -17452,38 +16702,131 @@ "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, "strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, "requires": { "min-indent": "^1.0.0" } }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true }, "stripe": { - "version": "8.91.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-8.91.0.tgz", - "integrity": "sha512-qn9cO1tUK/IKpXl2uhVW0G4GPOI5K299qOBH9gDB6vILaqUJhQaNsykzRBtDMLkmLyGh7AFw62ghZPXmlOFdeA==", + "version": "8.120.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-8.120.0.tgz", + "integrity": "sha512-OzqyUWwdYPla1Onjn94pdGwqpVsOAOlNwo75Yr3T3n1eN17CMUclAVU9hIAqBrDVeyHOyriYklLRhT3NGr7BNw==", "requires": { "@types/node": ">=8.1.0", "qs": "^6.6.0" } }, + "superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "supertest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.0.1.tgz", + "integrity": "sha512-8yDNdm+bbAN/jeDdXsRipbq9qMpVF7wRsbwLgsANHqdjPsCoecmlTuqEcLQMGpmojFBhxayZ0ckXmLXYq7e+0g==", + "dev": true, + "requires": { + "methods": "1.1.2", + "superagent": "6.1.0" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -17496,7 +16839,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", - "dev": true, "requires": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -17505,55 +16847,124 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { "has-flag": "^4.0.0" } } } }, + "swagger-ui-dist": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.36.0.tgz", + "integrity": "sha512-y+ZTvI5vU1xnb2TtUk6JctoCyDDnjXWdpxJbE3BAd7wOXa8vdwNND4suJIpIRffxRygoZw42z3qGWjRK+xqfJA==" + }, + "swagger-ui-express": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.4.tgz", + "integrity": "sha512-Ea96ecpC+Iq9GUqkeD/LFR32xSs8gYqmTW1gXCuKg81c26WV6ZC2FsBSPVExQP6WkyUuz5HEiR0sEv/HCC343g==", + "requires": { + "swagger-ui-dist": "^3.18.1" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "systeminformation": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.28.1.tgz", - "integrity": "sha512-g9WQy+Igsf0efbbTlXzDkV7iYeUerFJeqI/zh07F9sWHxclejmXn5hrGdgHf2ok+1DuRmC9t4mEh7XS0b8Zk9w==" + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true }, "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" } }, "temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==" }, "tempy": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.5.0.tgz", "integrity": "sha512-VEY96x7gbIRfsxqsafy2l5yVxxp3PhwAGoWMyC2D2Zt5DmEv+2tGiPOrquNRpf21hhGnKLVEsuqleqiZmKG/qw==", - "dev": true, "requires": { "is-stream": "^2.0.0", "temp-dir": "^2.0.0", @@ -17561,35 +16972,96 @@ "unique-string": "^2.0.0" }, "dependencies": { - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, "type-fest": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", - "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==" + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "terser": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", + "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-zFdGk8Lh9ZJGPxxPE6jwysOlATWB8GMW8HcfGULWA/nPal+3VdATflQvSBSLQJRCmYZnfFJl6vkRTiwJGNgPiQ==", + "dev": true, + "requires": { + "jest-worker": "^26.6.1", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.3.8" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, - "term-size": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", - "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==" - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -17604,7 +17076,12 @@ "text-extensions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "thirty-two": { @@ -17621,29 +17098,55 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" + "readable-stream": "3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } } }, - "throwback": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throwback/-/throwback-4.1.0.tgz", - "integrity": "sha512-dLFe8bU8SeH0xeqeKL7BNo8XoPC/o91nz9/ooeplZPiso+DZukhoyZcSz9TFnUNScm+cA9qjU1m1853M6sPOng==" - }, "tiny-lru": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -17653,12 +17156,14 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -17667,21 +17172,18 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -17690,12 +17192,11 @@ } }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "toidentifier": { @@ -17703,29 +17204,15 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "requires": { - "nopt": "~1.0.10" - } - }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, "requires": { "ip-regex": "^2.1.0", "psl": "^1.1.28", "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } } }, "tr46": { @@ -17735,38 +17222,28 @@ "dev": true, "requires": { "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", - "dev": true + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true }, "trim-newlines": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", - "dev": true + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==" }, "trim-off-newlines": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=" }, "ts-jest": { "version": "26.4.3", @@ -17788,10 +17265,19 @@ "yargs-parser": "20.x" }, "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "yargs-parser": { @@ -17802,10 +17288,84 @@ } } }, + "ts-loader": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.10.tgz", + "integrity": "sha512-5fVbbZldz6LQi6RQ0v1P7lZ98CZGlQyM8b4xGZXw3G/XUqL8GIH+Ib6H01nImPhkHZ9+PVXZgTb+v3fRsaIHlg==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^1.0.2", + "micromatch": "^4.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "tsconfig-paths-webpack-plugin": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.3.0.tgz", + "integrity": "sha512-MpQeZpwPY4gYASCUjY4yt2Zj8yv86O8f++3Ai4o0yI0fUC6G1syvnL9VuY71PBgimRYDQU47f12BEmJq9wRaSw==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "tsconfig-paths": "^3.4.0" + } + }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } }, "tunnel-agent": { "version": "0.6.0", @@ -17822,18 +17382,68 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "twt": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/twt/-/twt-1.3.1.tgz", - "integrity": "sha512-1r3Gvuci78MVgjyC2TI471lFhJtTTOmBBUGev/Y3nBza1rjmMOjI346uDE35uQr4dtwY+KoxDKUyM4tQ/Gpy0A==" + "twilio": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.51.0.tgz", + "integrity": "sha512-6TjXI7U1FWlKhqqdM2tKSZoq7MlRxv+K5IgKhKSrgcoYTm6/qZ51UwwY2rfVHUMicr6y6j4NgaBDrPiOtiu9Xg==", + "requires": { + "@types/express": "^4.17.7", + "@types/qs": "6.9.4", + "axios": "^0.19.2", + "dayjs": "^1.8.29", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.19", + "q": "2.0.x", + "qs": "^6.9.4", + "rootpath": "^0.1.2", + "scmp": "^2.1.0", + "url-parse": "^1.4.7", + "xmlbuilder": "^13.0.2" + }, + "dependencies": { + "@types/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + } + } }, "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" } }, "type-detect": { @@ -17843,9 +17453,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" }, "type-is": { "version": "1.6.18", @@ -17856,107 +17466,47 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, "requires": { "is-typedarray": "^1.0.0" } }, - "typedoc": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.19.2.tgz", - "integrity": "sha512-oDEg1BLEzi1qvgdQXc658EYgJ5qJLVSeZ0hQ57Eq4JXy6Vj2VX4RVo18qYxRWz75ifAaYuYNBUCnbhjd37TfOg==", - "requires": { - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "highlight.js": "^10.2.0", - "lodash": "^4.17.20", - "lunr": "^2.3.9", - "marked": "^1.1.1", - "minimatch": "^3.0.0", - "progress": "^2.0.3", - "semver": "^7.3.2", - "shelljs": "^0.8.4", - "typedoc-default-themes": "^0.11.4" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - } - } - }, - "typedoc-default-themes": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.11.4.tgz", - "integrity": "sha512-Y4Lf+qIb9NTydrexlazAM46SSLrmrQRqWiD52593g53SsmUFioAsMWt8m834J6qsp+7wHRjxCXSZeiiW5cMUdw==" - }, "typescript": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", "dev": true }, + "ua-parser-js": { + "version": "0.7.22", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", + "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==" + }, "uglify-js": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz", - "integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==", + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.3.tgz", + "integrity": "sha512-wDRziHG94mNj2n3R864CvYw/+pc9y/RNImiTyrrf8BzgWn75JgFSwYvXrtZQMnMnOp/4UTrf3iCSQxSStPiByA==", "optional": true }, - "undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -17976,9 +17526,105 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", - "dev": true, "requires": { "os-name": "^3.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "windows-release": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", + "integrity": "sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==", + "requires": { + "execa": "^1.0.0" + } + } } }, "universalify": { @@ -17995,6 +17641,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -18004,6 +17651,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -18014,6 +17662,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, "requires": { "isarray": "1.0.0" } @@ -18023,108 +17672,17 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "optional": true - }, - "update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "requires": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true } } }, - "update-template": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-template/-/update-template-1.1.2.tgz", - "integrity": "sha512-RMbew0khRi382boGlushU47rlpeVnHi1jY9DlY5XBD5DSjRV4kqugFQre0LhXv6oNa88S+ElJfX/7bQ0GkfebA==", - "dev": true, - "requires": { - "fast-glob": "^3.2.4", - "fs-extra": "^9.0.1", - "recursive-readdir": "^2.2.2" - } - }, - "upper-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.1.tgz", - "integrity": "sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==", - "requires": { - "tslib": "^1.10.0" - } - }, - "upper-case-first": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.1.tgz", - "integrity": "sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==", - "requires": { - "tslib": "^1.10.0" - } - }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -18132,48 +17690,33 @@ "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true }, "url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", "requires": { - "prepend-http": "^2.0.0" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true }, "util-deprecate": { "version": "1.0.2", @@ -18186,9 +17729,15 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true }, "v8-to-istanbul": { "version": "7.0.0", @@ -18199,14 +17748,6 @@ "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } }, "validate-npm-package-license": { @@ -18218,6 +17759,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "validator": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.0.0.tgz", + "integrity": "sha512-anYx5fURbgF04lQV18nEQWZ/3wHGnxiKdG4aL8J+jEDsm98n/sU/bey+tYk6tnGJzm7ioh5FoqrAiQ6m03IgaA==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -18261,12 +17807,133 @@ "makeerror": "1.0.x" } }, + "watchpack": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.0.1.tgz", + "integrity": "sha512-vO8AKGX22ZRo6PiOFM9dC0re8IcKh8Kd/aH2zeqUc6w4/jBGlTy2P7fTC6ekT0NjVeGjgU2dGC5rNstKkeLEQg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "weak-map": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz", + "integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes=" + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true }, + "webpack": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.4.0.tgz", + "integrity": "sha512-udpYTyqz8toTTdaOsL2QKPLeZLt2IEm9qY7yTXuFEQhKu5bk0yQD9BtAdVQksmz4jFbbWOiWmm3NHarO0zr/ng==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.45", + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^8.0.4", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.3.1", + "eslint-scope": "^5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "pkg-dir": "^4.2.0", + "schema-utils": "^3.0.0", + "tapable": "^2.0.0", + "terser-webpack-plugin": "^5.0.3", + "watchpack": "^2.0.0", + "webpack-sources": "^2.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "enhanced-resolve": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.3.1.tgz", + "integrity": "sha512-G1XD3MRGrGfNcf6Hg0LVZG7GIKcYkbfHa5QMxt1HDUTdYoXH0JR1xXyg+MaKLF73E9A27uWNVxvFivNRYeUB6w==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.0.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "tapable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.0.0.tgz", + "integrity": "sha512-bjzn0C0RWoffnNdTzNi7rNDhs1Zlwk2tRXgk8EiHKAOX1Mag3d6T0Y5zNa7l9CJ+EoUne/0UHdwS8tMbkh9zDg==", + "dev": true + } + } + }, + "webpack-node-externals": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz", + "integrity": "sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==", + "dev": true + }, + "webpack-sources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", + "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", @@ -18306,21 +17973,50 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "^4.0.0" + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "windows-release": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", - "integrity": "sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", + "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", "dev": true, "requires": { - "execa": "^1.0.0" + "execa": "^4.0.2" } }, "word-wrap": { @@ -18335,9 +18031,9 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -18372,10 +18068,20 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, "requires": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -18389,30 +18095,16 @@ "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==", "dev": true }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" }, "xmlchars": { "version": "2.2.0", @@ -18423,8 +18115,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "4.0.0", @@ -18432,9 +18123,9 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yaml": { "version": "1.10.0", @@ -18442,65 +18133,69 @@ "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^3.0.0", + "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "yargs-parser": "^18.1.2" }, "dependencies": { - "ansi-regex": { + "find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "p-locate": "^4.1.0" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { - "ansi-regex": "^4.1.0" + "p-limit": "^2.2.0" } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" } } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 66480bf5a..35176ebe9 100644 --- a/package.json +++ b/package.json @@ -1,102 +1,124 @@ { - "name": "@staart/api", + "name": "api", "version": "2.21.0", - "publishConfig": { - "tag": "next" - }, - "main": "index.js", + "description": "SaaS backend framework with users, payments, APIs, and more", "repository": "git@github.com:staart/api.git", "author": "Anand Chowdhary ", "license": "MIT", "scripts": { - "dev": "staart dev", - "start": "staart start", - "build": "staart build", - "eject": "staart eject", - "build-babel": "staart build-babel", - "launch": "staart launch", - "update": "staart update api", - "update-template": "update-template https://github.com/staart/api", - "generate-docs": "staart docs", - "test": "jest --forceExit", - "snyk-protect": "snyk protect", - "semantic-release": "semantic-release" - }, - "engines": { - "node": ">= 10.16.0" - }, - "jest": { - "roots": [ - "/src" - ], - "transform": { - "^.+\\.tsx?$": "ts-jest" - } - }, - "devDependencies": { - "@prisma/cli": "^2.10.2", - "@semantic-release/git": "^9.0.0", - "@types/cron": "^1.7.2", - "@types/fs-extra": "^9.0.3", - "@types/geolite2": "^2.0.0", - "@types/hapi__joi": "^17.1.6", - "@types/jest": "^26.0.15", - "@types/jsonwebtoken": "^8.5.0", - "@types/mysql": "^2.15.15", - "@types/node": "^14.14.6", - "@types/node-emoji": "^1.8.1", - "@types/qrcode": "^1.3.5", - "@types/randomcolor": "^0.5.5", - "@types/request": "^2.48.5", - "@types/signale": "^1.4.1", - "@types/validator": "^13.1.0", - "@types/yaml": "^1.9.7", - "dotenv": "^8.2.0", - "jest": "^26.6.3", - "semantic-release": "^17.2.2", - "semantic-release-gitmoji": "^1.3.4", - "ts-jest": "^26.4.3", - "typescript": "^4.0.5", - "update-template": "^1.1.2", - "yaml": "^1.10.0" + "prebuild": "rimraf dist", + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "__test": "jest", + "test": "exit 0", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { - "@anandchowdhary/cosmic": "^1.0.1", - "@prisma/client": "^2.10.2", - "@sentry/node": "^5.27.3", - "@staart/config": "^1.0.1", - "@staart/disposable-email": "^2.0.3", - "@staart/elasticsearch": "^2.2.4", - "@staart/errors": "^2.1.2", - "@staart/mail": "^2.3.0", - "@staart/messages": "^2.1.3", + "@koj/config": "^1.2.8", + "@nestjs/common": "^7.5.1", + "@nestjs/config": "^0.5.0", + "@nestjs/core": "^7.5.1", + "@nestjs/jwt": "^7.2.0", + "@nestjs/passport": "^7.1.0", + "@nestjs/platform-express": "^7.5.1", + "@nestjs/schedule": "^0.4.1", + "@nestjs/swagger": "^4.7.0", "@staart/mustache-markdown": "^3.0.3", - "@staart/payments": "^4.0.1", - "@staart/redis": "^2.3.1", - "@staart/scripts": "^1.18.4", - "@staart/server": "^2.7.1", - "@staart/text": "^2.3.1", - "@staart/validate": "^3.0.2", - "axios": "^0.21.0", - "casbin": "^5.2.0", - "client-oauth2": "^4.3.3", - "cron": "^1.8.2", - "fs-extra": "^9.0.1", + "bcrypt": "^5.0.0", + "class-transformer": "^0.3.1", + "class-validator": "^0.12.2", "geolite2-redist": "^1.0.7", + "got": "^11.8.0", + "handlebars": "^4.7.6", + "helmet": "^4.2.0", + "hibp": "^9.0.0", + "ip-anonymize": "^0.1.0", + "ip-range-check": "^0.2.0", "jsonwebtoken": "^8.5.1", "maxmind": "^4.3.1", - "mysql": "^2.18.1", - "node-emoji": "^1.10.0", + "mem": "^8.0.0", + "minimatch": "^3.0.4", + "nestjs-rate-limiter": "^2.5.6", + "nodemailer": "^6.4.15", + "normalize-email": "^1.1.1", + "object-literal-parse": "^2.1.0", "otplib": "^12.0.1", + "p-queue": "^6.6.2", + "p-retry": "^4.2.0", + "passport": "^0.4.1", + "passport-headerapikey": "^1.2.2", + "passport-local": "^1.0.0", "qrcode": "^1.4.4", - "random-int": "^2.0.1", + "quick-lru": "^5.1.1", "randomcolor": "^0.6.2", - "systeminformation": "^4.28.1", - "twt": "^1.3.1" + "reflect-metadata": "^0.1.13", + "request-ip": "^2.1.3", + "response-time": "^2.3.2", + "rimraf": "^3.0.2", + "rxjs": "^6.6.3", + "stripe": "^8.120.0", + "swagger-ui-express": "^4.1.4", + "twilio": "^3.51.0", + "ua-parser-js": "^0.7.22", + "uuid": "^8.3.1" }, - "files": [ - "setup" - ], - "snyk": true, - "staart-version": "1.3.157" + "devDependencies": { + "@nestjs/cli": "^7.5.2", + "@nestjs/schematics": "^7.2.1", + "@nestjs/testing": "^7.5.1", + "@prisma/cli": "^2.10.2", + "@prisma/client": "^2.10.2", + "@types/bcrypt": "^3.0.0", + "@types/express": "^4.17.8", + "@types/jest": "26.0.15", + "@types/jsonwebtoken": "^8.5.0", + "@types/minimatch": "^3.0.3", + "@types/node": "^14.14.6", + "@types/nodemailer": "^6.4.0", + "@types/passport-local": "^1.0.33", + "@types/qrcode": "^1.3.5", + "@types/randomcolor": "^0.5.5", + "@types/request-ip": "0.0.35", + "@types/response-time": "^2.3.4", + "@types/supertest": "^2.0.10", + "@types/ua-parser-js": "^0.7.33", + "@types/uuid": "^8.3.0", + "@typescript-eslint/eslint-plugin": "4.6.1", + "@typescript-eslint/parser": "4.6.1", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "eslint": "7.13.0", + "eslint-config-prettier": "^6.15.0", + "eslint-plugin-import": "^2.22.1", + "jest": "26.6.3", + "prettier": "^2.1.2", + "supertest": "^6.0.1", + "ts-jest": "26.4.3", + "ts-loader": "^8.0.10", + "ts-node": "9.0.0", + "tsconfig-paths": "^3.9.0", + "typescript": "^4.0.5" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } } diff --git a/prisma/migrations/20200803235103/README.md b/prisma/migrations/20200803235103/README.md deleted file mode 100644 index 52a1461dd..000000000 --- a/prisma/migrations/20200803235103/README.md +++ /dev/null @@ -1,479 +0,0 @@ -# Migration `20200803235103` - -This migration has been generated by Anand Chowdhary at 8/3/2020, 11:51:03 PM. -You can check out the [state of the schema](./schema.prisma) after the migration. - -## Database Steps - -```sql -CREATE TABLE `staart`.`users` ( -`checkLocationOnLogin` boolean NOT NULL DEFAULT false, -`countryCode` varchar(191) NOT NULL DEFAULT 'us', -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`gender` ENUM('MALE', 'FEMALE', 'NONBINARY', 'UNKNOWN') NOT NULL DEFAULT 'UNKNOWN', -`id` int NOT NULL AUTO_INCREMENT, -`name` varchar(191) NOT NULL , -`notificationEmails` ENUM('ACCOUNT', 'UPDATES', 'PROMOTIONS') NOT NULL DEFAULT 'ACCOUNT', -`password` varchar(191) , -`prefersLanguage` varchar(191) NOT NULL DEFAULT 'en-us', -`prefersColorScheme` ENUM('NO_PREFERENCE', 'LIGHT', 'DARK') NOT NULL DEFAULT 'NO_PREFERENCE', -`prefersReducedMotion` ENUM('NO_PREFERENCE', 'REDUCE') NOT NULL DEFAULT 'NO_PREFERENCE', -`prefersEmailId` int NOT NULL , -`profilePictureUrl` varchar(191) NOT NULL DEFAULT 'https://unavatar.now.sh/fallback.png', -`role` ENUM('SUDO', 'USER') NOT NULL DEFAULT 'USER', -`timezone` varchar(191) NOT NULL DEFAULT 'America/Los_Angeles', -`twoFactorEnabled` boolean NOT NULL DEFAULT false, -`twoFactorSecret` varchar(191) , -`attributes` json , -`updatedAt` datetime(3) NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`groups` ( -`autoJoinDomain` boolean NOT NULL DEFAULT false, -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`forceTwoFactor` boolean NOT NULL DEFAULT false, -`id` int NOT NULL AUTO_INCREMENT, -`ipRestrictions` varchar(191) , -`name` varchar(191) NOT NULL , -`onlyAllowDomain` boolean NOT NULL DEFAULT false, -`profilePictureUrl` varchar(191) NOT NULL DEFAULT 'https://unavatar.now.sh/fallback.png', -`attributes` json , -`updatedAt` datetime(3) NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`emails` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`email` varchar(191) NOT NULL , -`id` int NOT NULL AUTO_INCREMENT, -`isVerified` boolean NOT NULL DEFAULT false, -`updatedAt` datetime(3) NOT NULL , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`accessTokens` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`description` varchar(191) , -`expiresAt` datetime(3) NOT NULL , -`id` int NOT NULL AUTO_INCREMENT, -`accessToken` varchar(191) NOT NULL , -`name` varchar(191) , -`scopes` json , -`updatedAt` datetime(3) NOT NULL , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`apiKeys` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`description` varchar(191) , -`expiresAt` datetime(3) NOT NULL , -`id` int NOT NULL AUTO_INCREMENT, -`ipRestrictions` json , -`apiKey` varchar(191) NOT NULL , -`name` varchar(191) , -`groupId` int NOT NULL , -`referrerRestrictions` varchar(191) , -`scopes` json , -`updatedAt` datetime(3) NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`approvedLocations` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`id` int NOT NULL AUTO_INCREMENT, -`subnet` varchar(191) NOT NULL , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`backupCodes` ( -`id` int NOT NULL AUTO_INCREMENT, -`code` varchar(191) NOT NULL , -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`updatedAt` datetime(3) NOT NULL , -`isUsed` boolean NOT NULL DEFAULT false, -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`couponCodes` ( -`id` int NOT NULL AUTO_INCREMENT, -`code` varchar(191) NOT NULL , -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`updatedAt` datetime(3) NOT NULL , -`expiresAt` datetime(3) , -`maxUses` int NOT NULL DEFAULT 1000, -`usedCount` int NOT NULL DEFAULT 0, -`teamRestrictions` varchar(191) , -`amount` int NOT NULL , -`currency` varchar(191) NOT NULL , -`description` varchar(191) , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`domains` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`domain` varchar(191) NOT NULL , -`id` int NOT NULL AUTO_INCREMENT, -`isVerified` boolean NOT NULL DEFAULT false, -`groupId` int NOT NULL , -`updatedAt` datetime(3) NOT NULL , -`verificationCode` varchar(191) NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`identities` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`id` int NOT NULL AUTO_INCREMENT, -`loginName` varchar(191) NOT NULL , -`type` ENUM('GOOGLE', 'APPLE', 'SLACK') NOT NULL , -`updatedAt` datetime(3) NOT NULL , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`memberships` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`id` int NOT NULL AUTO_INCREMENT, -`groupId` int NOT NULL , -`role` ENUM('OWNER', 'ADMIN', 'MEMBER') NOT NULL DEFAULT 'MEMBER', -`updatedAt` datetime(3) NOT NULL , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`sessions` ( -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`id` int NOT NULL AUTO_INCREMENT, -`ipAddress` varchar(191) NOT NULL , -`token` varchar(191) NOT NULL , -`updatedAt` datetime(3) NOT NULL , -`userAgent` varchar(191) NOT NULL , -`city` varchar(191) , -`region` varchar(191) , -`timezone` varchar(191) , -`countryCode` varchar(191) , -`browser` varchar(191) , -`operatingSystem` varchar(191) , -`userId` int NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE TABLE `staart`.`webhooks` ( -`contentType` varchar(191) NOT NULL DEFAULT 'application/json', -`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -`event` varchar(191) NOT NULL , -`id` int NOT NULL AUTO_INCREMENT, -`isActive` boolean NOT NULL DEFAULT false, -`lastFiredAt` datetime(3) , -`groupId` int NOT NULL , -`secret` varchar(191) , -`updatedAt` datetime(3) NOT NULL , -`url` varchar(191) NOT NULL , -PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - -CREATE INDEX `userId` ON `staart`.`emails`(`userId`) - -CREATE INDEX `userId` ON `staart`.`accessTokens`(`userId`) - -CREATE INDEX `userId` ON `staart`.`backupCodes`(`userId`) - -CREATE INDEX `groupId` ON `staart`.`domains`(`groupId`) - -CREATE INDEX `userId` ON `staart`.`identities`(`userId`) - -CREATE INDEX `groupId` ON `staart`.`memberships`(`groupId`) - -CREATE INDEX `userId` ON `staart`.`memberships`(`userId`) - -CREATE INDEX `userId` ON `staart`.`sessions`(`userId`) - -CREATE INDEX `groupId` ON `staart`.`webhooks`(`groupId`) - -ALTER TABLE `staart`.`users` ADD FOREIGN KEY (`prefersEmailId`) REFERENCES `staart`.`emails`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`emails` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`accessTokens` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`apiKeys` ADD FOREIGN KEY (`groupId`) REFERENCES `staart`.`groups`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`approvedLocations` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`backupCodes` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`domains` ADD FOREIGN KEY (`groupId`) REFERENCES `staart`.`groups`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`identities` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`memberships` ADD FOREIGN KEY (`groupId`) REFERENCES `staart`.`groups`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`memberships` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`sessions` ADD FOREIGN KEY (`userId`) REFERENCES `staart`.`users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - -ALTER TABLE `staart`.`webhooks` ADD FOREIGN KEY (`groupId`) REFERENCES `staart`.`groups`(`id`) ON DELETE CASCADE ON UPDATE CASCADE -``` - -## Changes - -```diff -diff --git schema.prisma schema.prisma -migration ..20200803235103 ---- datamodel.dml -+++ datamodel.dml -@@ -1,0 +1,247 @@ -+generator client { -+ provider = "prisma-client-js" -+} -+ -+datasource mysql { -+ provider = "mysql" -+ url = "***" -+} -+ -+enum Gender { -+ MALE -+ FEMALE -+ NONBINARY -+ UNKNOWN -+} -+ -+enum NotificationEmails { -+ ACCOUNT -+ UPDATES -+ PROMOTIONS -+} -+ -+enum PrefersColorScheme { -+ NO_PREFERENCE -+ LIGHT -+ DARK -+} -+ -+enum PrefersReducedMotion { -+ NO_PREFERENCE -+ REDUCE -+} -+ -+enum UserRole { -+ SUDO -+ USER -+} -+ -+enum MembershipRole { -+ OWNER -+ ADMIN -+ MEMBER -+} -+ -+enum IdentityType { -+ GOOGLE -+ APPLE -+ SLACK -+} -+ -+model users { -+ checkLocationOnLogin Boolean @default(false) -+ countryCode String @default("us") -+ createdAt DateTime @default(now()) -+ gender Gender @default(UNKNOWN) -+ id Int @default(autoincrement()) @id -+ name String -+ notificationEmails NotificationEmails @default(ACCOUNT) -+ password String? -+ prefersLanguage String @default("en-us") -+ prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) -+ prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) -+ prefersEmail emails @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) -+ prefersEmailId Int -+ profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") -+ role UserRole @default(USER) -+ timezone String @default("America/Los_Angeles") -+ twoFactorEnabled Boolean @default(false) -+ twoFactorSecret String? -+ attributes Json? -+ updatedAt DateTime @updatedAt -+ emails emails[] @relation("userEmails") -+ accessTokens accessTokens[] @relation("userAccessTokens") -+ approvedLocations approvedLocations[] @relation("userApprovedLocations") -+ backupCodes backupCodes[] @relation("userBackupCodes") -+ identities identities[] @relation("userIdentities") -+ memberships memberships[] @relation("userMemberships") -+ sessions sessions[] @relation("userSessions") -+} -+ -+model groups { -+ autoJoinDomain Boolean @default(false) -+ createdAt DateTime @default(now()) -+ forceTwoFactor Boolean @default(false) -+ id Int @default(autoincrement()) @id -+ ipRestrictions String? -+ name String -+ onlyAllowDomain Boolean @default(false) -+ profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") -+ attributes Json? -+ updatedAt DateTime @updatedAt -+ apiKeys apiKeys[] @relation("groupApiKeys") -+ domains domains[] @relation("groupDomains") -+ memberships memberships[] @relation("groupMemberships") -+ webhooks webhooks[] @relation("groupWebhooks") -+} -+ -+model emails { -+ createdAt DateTime @default(now()) -+ email String -+ id Int @default(autoincrement()) @id -+ isVerified Boolean @default(false) -+ updatedAt DateTime @updatedAt -+ user users @relation("userEmails", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([userId], name: "userId") -+ users users[] @relation("userPrefersEmail") -+} -+ -+model accessTokens { -+ createdAt DateTime @default(now()) -+ description String? -+ expiresAt DateTime -+ id Int @default(autoincrement()) @id -+ accessToken String -+ name String? -+ scopes Json? -+ updatedAt DateTime @updatedAt -+ user users @relation("userAccessTokens", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([userId], name: "userId") -+} -+ -+model apiKeys { -+ createdAt DateTime @default(now()) -+ description String? -+ expiresAt DateTime -+ id Int @default(autoincrement()) @id -+ ipRestrictions Json? -+ apiKey String -+ name String? -+ group groups @relation("groupApiKeys", fields: [groupId], references: [id]) -+ groupId Int -+ referrerRestrictions String? -+ scopes Json? -+ updatedAt DateTime @updatedAt -+} -+ -+model approvedLocations { -+ createdAt DateTime @default(now()) -+ id Int @default(autoincrement()) @id -+ subnet String -+ user users @relation("userApprovedLocations", fields: [userId], references: [id]) -+ userId Int -+} -+ -+model backupCodes { -+ id Int @default(autoincrement()) @id -+ code String -+ createdAt DateTime @default(now()) -+ updatedAt DateTime @updatedAt -+ isUsed Boolean @default(false) -+ user users @relation("userBackupCodes", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([userId], name: "userId") -+} -+ -+model couponCodes { -+ id Int @default(autoincrement()) @id -+ code String -+ createdAt DateTime @default(now()) -+ updatedAt DateTime @updatedAt -+ expiresAt DateTime? -+ maxUses Int @default(1000) -+ usedCount Int @default(0) -+ teamRestrictions String? -+ amount Int -+ currency String -+ description String? -+} -+ -+model domains { -+ createdAt DateTime @default(now()) -+ domain String -+ id Int @default(autoincrement()) @id -+ isVerified Boolean @default(false) -+ group groups @relation("groupDomains", fields: [groupId], references: [id]) -+ groupId Int -+ updatedAt DateTime @updatedAt -+ verificationCode String -+ -+ @@index([groupId], name: "groupId") -+} -+ -+model identities { -+ createdAt DateTime @default(now()) -+ id Int @default(autoincrement()) @id -+ loginName String -+ type IdentityType -+ updatedAt DateTime @updatedAt -+ user users @relation("userIdentities", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([userId], name: "userId") -+} -+ -+model memberships { -+ createdAt DateTime @default(now()) -+ id Int @default(autoincrement()) @id -+ group groups @relation("groupMemberships", fields: [groupId], references: [id]) -+ groupId Int -+ role MembershipRole @default(MEMBER) -+ updatedAt DateTime @updatedAt -+ user users @relation("userMemberships", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([groupId], name: "groupId") -+ @@index([userId], name: "userId") -+} -+ -+model sessions { -+ createdAt DateTime @default(now()) -+ id Int @default(autoincrement()) @id -+ ipAddress String -+ token String -+ updatedAt DateTime @updatedAt -+ userAgent String -+ city String? -+ region String? -+ timezone String? -+ countryCode String? -+ browser String? -+ operatingSystem String? -+ user users @relation("userSessions", fields: [userId], references: [id]) -+ userId Int -+ -+ @@index([userId], name: "userId") -+} -+ -+model webhooks { -+ contentType String @default("application/json") -+ createdAt DateTime @default(now()) -+ event String -+ id Int @default(autoincrement()) @id -+ isActive Boolean @default(false) -+ lastFiredAt DateTime? -+ group groups @relation("groupWebhooks", fields: [groupId], references: [id]) -+ groupId Int -+ secret String? -+ updatedAt DateTime @updatedAt -+ url String -+ -+ @@index([groupId], name: "groupId") -+} -``` - - diff --git a/prisma/migrations/20200803235103/schema.prisma b/prisma/migrations/20200803235103/schema.prisma deleted file mode 100644 index fa6436b4f..000000000 --- a/prisma/migrations/20200803235103/schema.prisma +++ /dev/null @@ -1,247 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource mysql { - provider = "mysql" - url = "***" -} - -enum Gender { - MALE - FEMALE - NONBINARY - UNKNOWN -} - -enum NotificationEmails { - ACCOUNT - UPDATES - PROMOTIONS -} - -enum PrefersColorScheme { - NO_PREFERENCE - LIGHT - DARK -} - -enum PrefersReducedMotion { - NO_PREFERENCE - REDUCE -} - -enum UserRole { - SUDO - USER -} - -enum MembershipRole { - OWNER - ADMIN - MEMBER -} - -enum IdentityType { - GOOGLE - APPLE - SLACK -} - -model users { - checkLocationOnLogin Boolean @default(false) - countryCode String @default("us") - createdAt DateTime @default(now()) - gender Gender @default(UNKNOWN) - id Int @default(autoincrement()) @id - name String - notificationEmails NotificationEmails @default(ACCOUNT) - password String? - prefersLanguage String @default("en-us") - prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) - prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) - prefersEmail emails @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) - prefersEmailId Int - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - role UserRole @default(USER) - timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) - twoFactorSecret String? - attributes Json? - updatedAt DateTime @updatedAt - emails emails[] @relation("userEmails") - accessTokens accessTokens[] @relation("userAccessTokens") - approvedLocations approvedLocations[] @relation("userApprovedLocations") - backupCodes backupCodes[] @relation("userBackupCodes") - identities identities[] @relation("userIdentities") - memberships memberships[] @relation("userMemberships") - sessions sessions[] @relation("userSessions") -} - -model groups { - autoJoinDomain Boolean @default(false) - createdAt DateTime @default(now()) - forceTwoFactor Boolean @default(false) - id Int @default(autoincrement()) @id - ipRestrictions String? - name String - onlyAllowDomain Boolean @default(false) - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - attributes Json? - updatedAt DateTime @updatedAt - apiKeys apiKeys[] @relation("groupApiKeys") - domains domains[] @relation("groupDomains") - memberships memberships[] @relation("groupMemberships") - webhooks webhooks[] @relation("groupWebhooks") -} - -model emails { - createdAt DateTime @default(now()) - email String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - updatedAt DateTime @updatedAt - user users @relation("userEmails", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") - users users[] @relation("userPrefersEmail") -} - -model accessTokens { - createdAt DateTime @default(now()) - description String? - expiresAt DateTime - id Int @default(autoincrement()) @id - accessToken String - name String? - scopes Json? - updatedAt DateTime @updatedAt - user users @relation("userAccessTokens", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model apiKeys { - createdAt DateTime @default(now()) - description String? - expiresAt DateTime - id Int @default(autoincrement()) @id - ipRestrictions Json? - apiKey String - name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int - referrerRestrictions String? - scopes Json? - updatedAt DateTime @updatedAt -} - -model approvedLocations { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - subnet String - user users @relation("userApprovedLocations", fields: [userId], references: [id]) - userId Int -} - -model backupCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - isUsed Boolean @default(false) - user users @relation("userBackupCodes", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model couponCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - expiresAt DateTime? - maxUses Int @default(1000) - usedCount Int @default(0) - teamRestrictions String? - amount Int - currency String - description String? -} - -model domains { - createdAt DateTime @default(now()) - domain String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - group groups @relation("groupDomains", fields: [groupId], references: [id]) - groupId Int - updatedAt DateTime @updatedAt - verificationCode String - - @@index([groupId], name: "groupId") -} - -model identities { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - loginName String - type IdentityType - updatedAt DateTime @updatedAt - user users @relation("userIdentities", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model memberships { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - group groups @relation("groupMemberships", fields: [groupId], references: [id]) - groupId Int - role MembershipRole @default(MEMBER) - updatedAt DateTime @updatedAt - user users @relation("userMemberships", fields: [userId], references: [id]) - userId Int - - @@index([groupId], name: "groupId") - @@index([userId], name: "userId") -} - -model sessions { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - ipAddress String - token String - updatedAt DateTime @updatedAt - userAgent String - city String? - region String? - timezone String? - countryCode String? - browser String? - operatingSystem String? - user users @relation("userSessions", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model webhooks { - contentType String @default("application/json") - createdAt DateTime @default(now()) - event String - id Int @default(autoincrement()) @id - isActive Boolean @default(false) - lastFiredAt DateTime? - group groups @relation("groupWebhooks", fields: [groupId], references: [id]) - groupId Int - secret String? - updatedAt DateTime @updatedAt - url String - - @@index([groupId], name: "groupId") -} diff --git a/prisma/migrations/20200803235103/steps.json b/prisma/migrations/20200803235103/steps.json deleted file mode 100644 index 27b81f3f0..000000000 --- a/prisma/migrations/20200803235103/steps.json +++ /dev/null @@ -1,3751 +0,0 @@ -{ - "version": "0.3.14-fixed", - "steps": [ - { - "tag": "CreateEnum", - "enum": "Gender", - "values": [ - "MALE", - "FEMALE", - "NONBINARY", - "UNKNOWN" - ] - }, - { - "tag": "CreateEnum", - "enum": "NotificationEmails", - "values": [ - "ACCOUNT", - "UPDATES", - "PROMOTIONS" - ] - }, - { - "tag": "CreateEnum", - "enum": "PrefersColorScheme", - "values": [ - "NO_PREFERENCE", - "LIGHT", - "DARK" - ] - }, - { - "tag": "CreateEnum", - "enum": "PrefersReducedMotion", - "values": [ - "NO_PREFERENCE", - "REDUCE" - ] - }, - { - "tag": "CreateEnum", - "enum": "UserRole", - "values": [ - "SUDO", - "USER" - ] - }, - { - "tag": "CreateEnum", - "enum": "MembershipRole", - "values": [ - "OWNER", - "ADMIN", - "MEMBER" - ] - }, - { - "tag": "CreateEnum", - "enum": "IdentityType", - "values": [ - "GOOGLE", - "APPLE", - "SLACK" - ] - }, - { - "tag": "CreateSource", - "source": "mysql" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Source", - "source": "mysql" - }, - "argument": "provider", - "value": "\"mysql\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Source", - "source": "mysql" - }, - "argument": "url", - "value": "\"***\"" - }, - { - "tag": "CreateModel", - "model": "users" - }, - { - "tag": "CreateField", - "model": "users", - "field": "checkLocationOnLogin", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "checkLocationOnLogin" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "checkLocationOnLogin" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "users", - "field": "countryCode", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "countryCode" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "countryCode" - }, - "directive": "default" - }, - "argument": "", - "value": "\"us\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "users", - "field": "gender", - "type": "Gender", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "gender" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "gender" - }, - "directive": "default" - }, - "argument": "", - "value": "UNKNOWN" - }, - { - "tag": "CreateField", - "model": "users", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "users", - "field": "name", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "users", - "field": "notificationEmails", - "type": "NotificationEmails", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "notificationEmails" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "notificationEmails" - }, - "directive": "default" - }, - "argument": "", - "value": "ACCOUNT" - }, - { - "tag": "CreateField", - "model": "users", - "field": "password", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "users", - "field": "prefersLanguage", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "prefersLanguage" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersLanguage" - }, - "directive": "default" - }, - "argument": "", - "value": "\"en-us\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "prefersColorScheme", - "type": "PrefersColorScheme", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "prefersColorScheme" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersColorScheme" - }, - "directive": "default" - }, - "argument": "", - "value": "NO_PREFERENCE" - }, - { - "tag": "CreateField", - "model": "users", - "field": "prefersReducedMotion", - "type": "PrefersReducedMotion", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "prefersReducedMotion" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersReducedMotion" - }, - "directive": "default" - }, - "argument": "", - "value": "NO_PREFERENCE" - }, - { - "tag": "CreateField", - "model": "users", - "field": "prefersEmail", - "type": "emails", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "prefersEmail" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersEmail" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userPrefersEmail\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersEmail" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[prefersEmailId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "prefersEmail" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "users", - "field": "prefersEmailId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "users", - "field": "profilePictureUrl", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "profilePictureUrl" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "profilePictureUrl" - }, - "directive": "default" - }, - "argument": "", - "value": "\"https://unavatar.now.sh/fallback.png\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "role", - "type": "UserRole", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "role" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "role" - }, - "directive": "default" - }, - "argument": "", - "value": "USER" - }, - { - "tag": "CreateField", - "model": "users", - "field": "timezone", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "timezone" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "timezone" - }, - "directive": "default" - }, - "argument": "", - "value": "\"America/Los_Angeles\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "twoFactorEnabled", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "twoFactorEnabled" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "twoFactorEnabled" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "users", - "field": "twoFactorSecret", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "users", - "field": "attributes", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "users", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "users", - "field": "emails", - "type": "emails", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "emails" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "emails" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userEmails\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "accessTokens", - "type": "accessTokens", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "accessTokens" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "accessTokens" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userAccessTokens\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "approvedLocations", - "type": "approvedLocations", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "approvedLocations" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "approvedLocations" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userApprovedLocations\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "backupCodes", - "type": "backupCodes", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "backupCodes" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "backupCodes" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userBackupCodes\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "identities", - "type": "identities", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "identities" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "identities" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userIdentities\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "memberships", - "type": "memberships", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "memberships" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "memberships" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userMemberships\"" - }, - { - "tag": "CreateField", - "model": "users", - "field": "sessions", - "type": "sessions", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "users", - "field": "sessions" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "users", - "field": "sessions" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userSessions\"" - }, - { - "tag": "CreateModel", - "model": "groups" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "autoJoinDomain", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "autoJoinDomain" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "autoJoinDomain" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "forceTwoFactor", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "forceTwoFactor" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "forceTwoFactor" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "groups", - "field": "ipRestrictions", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "name", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "onlyAllowDomain", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "onlyAllowDomain" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "onlyAllowDomain" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "profilePictureUrl", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "profilePictureUrl" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "profilePictureUrl" - }, - "directive": "default" - }, - "argument": "", - "value": "\"https://unavatar.now.sh/fallback.png\"" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "attributes", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "groups", - "field": "apiKeys", - "type": "apiKeys", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "apiKeys" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "apiKeys" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupApiKeys\"" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "domains", - "type": "domains", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "domains" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "domains" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupDomains\"" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "memberships", - "type": "memberships", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "memberships" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "memberships" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupMemberships\"" - }, - { - "tag": "CreateField", - "model": "groups", - "field": "webhooks", - "type": "webhooks", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "groups", - "field": "webhooks" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "groups", - "field": "webhooks" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupWebhooks\"" - }, - { - "tag": "CreateModel", - "model": "emails" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "email", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "emails", - "field": "isVerified", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "isVerified" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "isVerified" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "emails", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userEmails\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "emails", - "field": "users", - "type": "users", - "arity": "List" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "emails", - "field": "users" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "emails", - "field": "users" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userPrefersEmail\"" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "emails", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "accessTokens" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "description", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "expiresAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "accessToken", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "name", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "scopes", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userAccessTokens\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "accessTokens", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "accessTokens", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "apiKeys" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "description", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "expiresAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "ipRestrictions", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "apiKey", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "name", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "group", - "type": "groups", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "group" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "group" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupApiKeys\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "group" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[groupId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "group" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "groupId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "referrerRestrictions", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "scopes", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "apiKeys", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "apiKeys", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateModel", - "model": "approvedLocations" - }, - { - "tag": "CreateField", - "model": "approvedLocations", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "approvedLocations", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "approvedLocations", - "field": "subnet", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "approvedLocations", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userApprovedLocations\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "approvedLocations", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "approvedLocations", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateModel", - "model": "backupCodes" - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "code", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "isUsed", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "isUsed" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "isUsed" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userBackupCodes\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "backupCodes", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "backupCodes", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "backupCodes", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "couponCodes" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "code", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "expiresAt", - "type": "DateTime", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "maxUses", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "maxUses" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "maxUses" - }, - "directive": "default" - }, - "argument": "", - "value": "1000" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "usedCount", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "usedCount" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "couponCodes", - "field": "usedCount" - }, - "directive": "default" - }, - "argument": "", - "value": "0" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "teamRestrictions", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "amount", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "currency", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "couponCodes", - "field": "description", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateModel", - "model": "domains" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "domain", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "domains", - "field": "isVerified", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "isVerified" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "isVerified" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "group", - "type": "groups", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "group" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "group" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupDomains\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "group" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[groupId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "domains", - "field": "group" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "groupId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "domains", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "domains", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "domains", - "field": "verificationCode", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "domains", - "arguments": [ - { - "name": "", - "value": "[groupId]" - }, - { - "name": "name", - "value": "\"groupId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "identities" - }, - { - "tag": "CreateField", - "model": "identities", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "identities", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "identities", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "identities", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "identities", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "identities", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "identities", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "identities", - "field": "loginName", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "identities", - "field": "type", - "type": "IdentityType", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "identities", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "identities", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "identities", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "identities", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "identities", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userIdentities\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "identities", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "identities", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "identities", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "identities", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "memberships" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "group", - "type": "groups", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "group" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "group" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupMemberships\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "group" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[groupId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "group" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "groupId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "role", - "type": "MembershipRole", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "role" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "role" - }, - "directive": "default" - }, - "argument": "", - "value": "MEMBER" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "memberships", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userMemberships\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "memberships", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "memberships", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "memberships", - "arguments": [ - { - "name": "", - "value": "[groupId]" - }, - { - "name": "name", - "value": "\"groupId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "memberships", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "sessions" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "sessions", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "sessions", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "sessions", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "sessions", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "sessions", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "ipAddress", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "token", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "sessions", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "userAgent", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "city", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "region", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "timezone", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "countryCode", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "browser", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "operatingSystem", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "user", - "type": "users", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "sessions", - "field": "user" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "sessions", - "field": "user" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"userSessions\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "sessions", - "field": "user" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[userId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "sessions", - "field": "user" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "sessions", - "field": "userId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "sessions", - "arguments": [ - { - "name": "", - "value": "[userId]" - }, - { - "name": "name", - "value": "\"userId\"" - } - ] - }, - "directive": "index" - } - }, - { - "tag": "CreateModel", - "model": "webhooks" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "contentType", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "contentType" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "contentType" - }, - "directive": "default" - }, - "argument": "", - "value": "\"application/json\"" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "createdAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "createdAt" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "createdAt" - }, - "directive": "default" - }, - "argument": "", - "value": "now()" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "event", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "id", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "id" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "id" - }, - "directive": "default" - }, - "argument": "", - "value": "autoincrement()" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "id" - }, - "directive": "id" - } - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "isActive", - "type": "Boolean", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "isActive" - }, - "directive": "default" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "isActive" - }, - "directive": "default" - }, - "argument": "", - "value": "false" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "lastFiredAt", - "type": "DateTime", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "group", - "type": "groups", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "group" - }, - "directive": "relation" - } - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "group" - }, - "directive": "relation" - }, - "argument": "", - "value": "\"groupWebhooks\"" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "group" - }, - "directive": "relation" - }, - "argument": "fields", - "value": "[groupId]" - }, - { - "tag": "CreateArgument", - "location": { - "tag": "Directive", - "path": { - "tag": "Field", - "model": "webhooks", - "field": "group" - }, - "directive": "relation" - }, - "argument": "references", - "value": "[id]" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "groupId", - "type": "Int", - "arity": "Required" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "secret", - "type": "String", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "updatedAt", - "type": "DateTime", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Field", - "model": "webhooks", - "field": "updatedAt" - }, - "directive": "updatedAt" - } - }, - { - "tag": "CreateField", - "model": "webhooks", - "field": "url", - "type": "String", - "arity": "Required" - }, - { - "tag": "CreateDirective", - "location": { - "path": { - "tag": "Model", - "model": "webhooks", - "arguments": [ - { - "name": "", - "value": "[groupId]" - }, - { - "name": "name", - "value": "\"groupId\"" - } - ] - }, - "directive": "index" - } - } - ] -} \ No newline at end of file diff --git a/prisma/migrations/20200804141140/README.md b/prisma/migrations/20200804141140/README.md deleted file mode 100644 index 66d6d209a..000000000 --- a/prisma/migrations/20200804141140/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Migration `20200804141140` - -This migration has been generated by Anand Chowdhary at 8/4/2020, 2:11:40 PM. -You can check out the [state of the schema](./schema.prisma) after the migration. - -## Database Steps - -```sql -ALTER TABLE `staart`.`users` MODIFY `prefersEmailId` int; -``` - -## Changes - -```diff -diff --git schema.prisma schema.prisma -migration 20200803235103..20200804141140 ---- datamodel.dml -+++ datamodel.dml -@@ -3,9 +3,9 @@ - } - datasource mysql { - provider = "mysql" -- url = "***" -+ url = "***" - } - enum Gender { - MALE -@@ -59,10 +59,10 @@ - password String? - prefersLanguage String @default("en-us") - prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) - prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) -- prefersEmail emails @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) -- prefersEmailId Int -+ prefersEmail emails? @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) -+ prefersEmailId Int? - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - role UserRole @default(USER) - timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) -``` - - diff --git a/prisma/migrations/20200804141140/schema.prisma b/prisma/migrations/20200804141140/schema.prisma deleted file mode 100644 index 34b053cd0..000000000 --- a/prisma/migrations/20200804141140/schema.prisma +++ /dev/null @@ -1,247 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource mysql { - provider = "mysql" - url = "***" -} - -enum Gender { - MALE - FEMALE - NONBINARY - UNKNOWN -} - -enum NotificationEmails { - ACCOUNT - UPDATES - PROMOTIONS -} - -enum PrefersColorScheme { - NO_PREFERENCE - LIGHT - DARK -} - -enum PrefersReducedMotion { - NO_PREFERENCE - REDUCE -} - -enum UserRole { - SUDO - USER -} - -enum MembershipRole { - OWNER - ADMIN - MEMBER -} - -enum IdentityType { - GOOGLE - APPLE - SLACK -} - -model users { - checkLocationOnLogin Boolean @default(false) - countryCode String @default("us") - createdAt DateTime @default(now()) - gender Gender @default(UNKNOWN) - id Int @default(autoincrement()) @id - name String - notificationEmails NotificationEmails @default(ACCOUNT) - password String? - prefersLanguage String @default("en-us") - prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) - prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) - prefersEmail emails? @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) - prefersEmailId Int? - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - role UserRole @default(USER) - timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) - twoFactorSecret String? - attributes Json? - updatedAt DateTime @updatedAt - emails emails[] @relation("userEmails") - accessTokens accessTokens[] @relation("userAccessTokens") - approvedLocations approvedLocations[] @relation("userApprovedLocations") - backupCodes backupCodes[] @relation("userBackupCodes") - identities identities[] @relation("userIdentities") - memberships memberships[] @relation("userMemberships") - sessions sessions[] @relation("userSessions") -} - -model groups { - autoJoinDomain Boolean @default(false) - createdAt DateTime @default(now()) - forceTwoFactor Boolean @default(false) - id Int @default(autoincrement()) @id - ipRestrictions String? - name String - onlyAllowDomain Boolean @default(false) - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - attributes Json? - updatedAt DateTime @updatedAt - apiKeys apiKeys[] @relation("groupApiKeys") - domains domains[] @relation("groupDomains") - memberships memberships[] @relation("groupMemberships") - webhooks webhooks[] @relation("groupWebhooks") -} - -model emails { - createdAt DateTime @default(now()) - email String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - updatedAt DateTime @updatedAt - user users @relation("userEmails", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") - users users[] @relation("userPrefersEmail") -} - -model accessTokens { - createdAt DateTime @default(now()) - description String? - expiresAt DateTime - id Int @default(autoincrement()) @id - accessToken String - name String? - scopes Json? - updatedAt DateTime @updatedAt - user users @relation("userAccessTokens", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model apiKeys { - createdAt DateTime @default(now()) - description String? - expiresAt DateTime - id Int @default(autoincrement()) @id - ipRestrictions Json? - apiKey String - name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int - referrerRestrictions String? - scopes Json? - updatedAt DateTime @updatedAt -} - -model approvedLocations { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - subnet String - user users @relation("userApprovedLocations", fields: [userId], references: [id]) - userId Int -} - -model backupCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - isUsed Boolean @default(false) - user users @relation("userBackupCodes", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model couponCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - expiresAt DateTime? - maxUses Int @default(1000) - usedCount Int @default(0) - teamRestrictions String? - amount Int - currency String - description String? -} - -model domains { - createdAt DateTime @default(now()) - domain String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - group groups @relation("groupDomains", fields: [groupId], references: [id]) - groupId Int - updatedAt DateTime @updatedAt - verificationCode String - - @@index([groupId], name: "groupId") -} - -model identities { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - loginName String - type IdentityType - updatedAt DateTime @updatedAt - user users @relation("userIdentities", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model memberships { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - group groups @relation("groupMemberships", fields: [groupId], references: [id]) - groupId Int - role MembershipRole @default(MEMBER) - updatedAt DateTime @updatedAt - user users @relation("userMemberships", fields: [userId], references: [id]) - userId Int - - @@index([groupId], name: "groupId") - @@index([userId], name: "userId") -} - -model sessions { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - ipAddress String - token String - updatedAt DateTime @updatedAt - userAgent String - city String? - region String? - timezone String? - countryCode String? - browser String? - operatingSystem String? - user users @relation("userSessions", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model webhooks { - contentType String @default("application/json") - createdAt DateTime @default(now()) - event String - id Int @default(autoincrement()) @id - isActive Boolean @default(false) - lastFiredAt DateTime? - group groups @relation("groupWebhooks", fields: [groupId], references: [id]) - groupId Int - secret String? - updatedAt DateTime @updatedAt - url String - - @@index([groupId], name: "groupId") -} diff --git a/prisma/migrations/20200804141140/steps.json b/prisma/migrations/20200804141140/steps.json deleted file mode 100644 index 6763275d6..000000000 --- a/prisma/migrations/20200804141140/steps.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "0.3.14-fixed", - "steps": [ - { - "tag": "UpdateField", - "model": "users", - "field": "prefersEmail", - "arity": "Optional" - }, - { - "tag": "UpdateField", - "model": "users", - "field": "prefersEmailId", - "arity": "Optional" - } - ] -} \ No newline at end of file diff --git a/prisma/migrations/20200902181624/README.md b/prisma/migrations/20200902181624/README.md deleted file mode 100644 index 7b597293a..000000000 --- a/prisma/migrations/20200902181624/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Migration `20200902181624` - -This migration has been generated by Anand Chowdhary at 9/2/2020, 11:46:24 PM. -You can check out the [state of the schema](./schema.prisma) after the migration. - -## Database Steps - -```sql -ALTER TABLE `staart`.`accessTokens` DROP COLUMN `expiresAt`, -ADD COLUMN `ipRestrictions` json , -ADD COLUMN `referrerRestrictions` json - -ALTER TABLE `staart`.`apiKeys` DROP COLUMN `expiresAt` -``` - -## Changes - -```diff -diff --git schema.prisma schema.prisma -migration 20200804141140..20200902181624 ---- datamodel.dml -+++ datamodel.dml -@@ -1,11 +1,12 @@ - generator client { -- provider = "prisma-client-js" -+ provider = "prisma-client-js" -+ previewFeatures = ["middlewares"] - } - datasource mysql { - provider = "mysql" -- url = "***" -+ url = "***" - } - enum Gender { - MALE -@@ -108,33 +109,33 @@ - users users[] @relation("userPrefersEmail") - } - model accessTokens { -- createdAt DateTime @default(now()) -- description String? -- expiresAt DateTime -- id Int @default(autoincrement()) @id -- accessToken String -- name String? -- scopes Json? -- updatedAt DateTime @updatedAt -- user users @relation("userAccessTokens", fields: [userId], references: [id]) -- userId Int -+ createdAt DateTime @default(now()) -+ description String? -+ id Int @default(autoincrement()) @id -+ accessToken String -+ name String? -+ scopes Json? -+ updatedAt DateTime @updatedAt -+ user users @relation("userAccessTokens", fields: [userId], references: [id]) -+ userId Int -+ ipRestrictions Json? -+ referrerRestrictions Json? - @@index([userId], name: "userId") - } - model apiKeys { - createdAt DateTime @default(now()) - description String? -- expiresAt DateTime - id Int @default(autoincrement()) @id - ipRestrictions Json? - apiKey String - name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int -- referrerRestrictions String? -+ referrerRestrictions Json? - scopes Json? - updatedAt DateTime @updatedAt - } -``` - - diff --git a/prisma/migrations/20200902181624/schema.prisma b/prisma/migrations/20200902181624/schema.prisma deleted file mode 100644 index a1937f0b3..000000000 --- a/prisma/migrations/20200902181624/schema.prisma +++ /dev/null @@ -1,248 +0,0 @@ -generator client { - provider = "prisma-client-js" - previewFeatures = ["middlewares"] -} - -datasource mysql { - provider = "mysql" - url = "***" -} - -enum Gender { - MALE - FEMALE - NONBINARY - UNKNOWN -} - -enum NotificationEmails { - ACCOUNT - UPDATES - PROMOTIONS -} - -enum PrefersColorScheme { - NO_PREFERENCE - LIGHT - DARK -} - -enum PrefersReducedMotion { - NO_PREFERENCE - REDUCE -} - -enum UserRole { - SUDO - USER -} - -enum MembershipRole { - OWNER - ADMIN - MEMBER -} - -enum IdentityType { - GOOGLE - APPLE - SLACK -} - -model users { - checkLocationOnLogin Boolean @default(false) - countryCode String @default("us") - createdAt DateTime @default(now()) - gender Gender @default(UNKNOWN) - id Int @default(autoincrement()) @id - name String - notificationEmails NotificationEmails @default(ACCOUNT) - password String? - prefersLanguage String @default("en-us") - prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) - prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) - prefersEmail emails? @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) - prefersEmailId Int? - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - role UserRole @default(USER) - timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) - twoFactorSecret String? - attributes Json? - updatedAt DateTime @updatedAt - emails emails[] @relation("userEmails") - accessTokens accessTokens[] @relation("userAccessTokens") - approvedLocations approvedLocations[] @relation("userApprovedLocations") - backupCodes backupCodes[] @relation("userBackupCodes") - identities identities[] @relation("userIdentities") - memberships memberships[] @relation("userMemberships") - sessions sessions[] @relation("userSessions") -} - -model groups { - autoJoinDomain Boolean @default(false) - createdAt DateTime @default(now()) - forceTwoFactor Boolean @default(false) - id Int @default(autoincrement()) @id - ipRestrictions String? - name String - onlyAllowDomain Boolean @default(false) - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - attributes Json? - updatedAt DateTime @updatedAt - apiKeys apiKeys[] @relation("groupApiKeys") - domains domains[] @relation("groupDomains") - memberships memberships[] @relation("groupMemberships") - webhooks webhooks[] @relation("groupWebhooks") -} - -model emails { - createdAt DateTime @default(now()) - email String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - updatedAt DateTime @updatedAt - user users @relation("userEmails", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") - users users[] @relation("userPrefersEmail") -} - -model accessTokens { - createdAt DateTime @default(now()) - description String? - id Int @default(autoincrement()) @id - accessToken String - name String? - scopes Json? - updatedAt DateTime @updatedAt - user users @relation("userAccessTokens", fields: [userId], references: [id]) - userId Int - ipRestrictions Json? - referrerRestrictions Json? - - @@index([userId], name: "userId") -} - -model apiKeys { - createdAt DateTime @default(now()) - description String? - id Int @default(autoincrement()) @id - ipRestrictions Json? - apiKey String - name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int - referrerRestrictions Json? - scopes Json? - updatedAt DateTime @updatedAt -} - -model approvedLocations { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - subnet String - user users @relation("userApprovedLocations", fields: [userId], references: [id]) - userId Int -} - -model backupCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - isUsed Boolean @default(false) - user users @relation("userBackupCodes", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model couponCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - expiresAt DateTime? - maxUses Int @default(1000) - usedCount Int @default(0) - teamRestrictions String? - amount Int - currency String - description String? -} - -model domains { - createdAt DateTime @default(now()) - domain String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - group groups @relation("groupDomains", fields: [groupId], references: [id]) - groupId Int - updatedAt DateTime @updatedAt - verificationCode String - - @@index([groupId], name: "groupId") -} - -model identities { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - loginName String - type IdentityType - updatedAt DateTime @updatedAt - user users @relation("userIdentities", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model memberships { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - group groups @relation("groupMemberships", fields: [groupId], references: [id]) - groupId Int - role MembershipRole @default(MEMBER) - updatedAt DateTime @updatedAt - user users @relation("userMemberships", fields: [userId], references: [id]) - userId Int - - @@index([groupId], name: "groupId") - @@index([userId], name: "userId") -} - -model sessions { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - ipAddress String - token String - updatedAt DateTime @updatedAt - userAgent String - city String? - region String? - timezone String? - countryCode String? - browser String? - operatingSystem String? - user users @relation("userSessions", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model webhooks { - contentType String @default("application/json") - createdAt DateTime @default(now()) - event String - id Int @default(autoincrement()) @id - isActive Boolean @default(false) - lastFiredAt DateTime? - group groups @relation("groupWebhooks", fields: [groupId], references: [id]) - groupId Int - secret String? - updatedAt DateTime @updatedAt - url String - - @@index([groupId], name: "groupId") -} diff --git a/prisma/migrations/20200902181624/steps.json b/prisma/migrations/20200902181624/steps.json deleted file mode 100644 index b7eb3ba7c..000000000 --- a/prisma/migrations/20200902181624/steps.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": "0.3.14-fixed", - "steps": [ - { - "tag": "CreateField", - "model": "accessTokens", - "field": "ipRestrictions", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "CreateField", - "model": "accessTokens", - "field": "referrerRestrictions", - "type": "Json", - "arity": "Optional" - }, - { - "tag": "DeleteField", - "model": "accessTokens", - "field": "expiresAt" - }, - { - "tag": "DeleteField", - "model": "apiKeys", - "field": "expiresAt" - }, - { - "tag": "UpdateField", - "model": "apiKeys", - "field": "referrerRestrictions", - "type": "Json" - } - ] -} \ No newline at end of file diff --git a/prisma/migrations/20200923132041/README.md b/prisma/migrations/20200923132041/README.md deleted file mode 100644 index 767b41cc0..000000000 --- a/prisma/migrations/20200923132041/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Migration `20200923132041` - -This migration has been generated by Anand Chowdhary at 9/23/2020, 6:50:41 PM. -You can check out the [state of the schema](./schema.prisma) after the migration. - -## Database Steps - -```sql -ALTER TABLE `staart`.`emails` ADD COLUMN `emailSafe` varchar(191) NOT NULL -``` - -## Changes - -```diff -diff --git schema.prisma schema.prisma -migration 20200902181624..20200923132041 ---- datamodel.dml -+++ datamodel.dml -@@ -1,12 +1,11 @@ - generator client { -- provider = "prisma-client-js" -- previewFeatures = ["middlewares"] -+ provider = "prisma-client-js" - } - datasource mysql { - provider = "mysql" -- url = "***" -+ url = "***" - } - enum Gender { - MALE -@@ -98,8 +97,9 @@ - model emails { - createdAt DateTime @default(now()) - email String -+ emailSafe String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - updatedAt DateTime @updatedAt - user users @relation("userEmails", fields: [userId], references: [id]) -``` - - diff --git a/prisma/migrations/20200923132041/schema.prisma b/prisma/migrations/20200923132041/schema.prisma deleted file mode 100644 index 9c708a072..000000000 --- a/prisma/migrations/20200923132041/schema.prisma +++ /dev/null @@ -1,248 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource mysql { - provider = "mysql" - url = "***" -} - -enum Gender { - MALE - FEMALE - NONBINARY - UNKNOWN -} - -enum NotificationEmails { - ACCOUNT - UPDATES - PROMOTIONS -} - -enum PrefersColorScheme { - NO_PREFERENCE - LIGHT - DARK -} - -enum PrefersReducedMotion { - NO_PREFERENCE - REDUCE -} - -enum UserRole { - SUDO - USER -} - -enum MembershipRole { - OWNER - ADMIN - MEMBER -} - -enum IdentityType { - GOOGLE - APPLE - SLACK -} - -model users { - checkLocationOnLogin Boolean @default(false) - countryCode String @default("us") - createdAt DateTime @default(now()) - gender Gender @default(UNKNOWN) - id Int @default(autoincrement()) @id - name String - notificationEmails NotificationEmails @default(ACCOUNT) - password String? - prefersLanguage String @default("en-us") - prefersColorScheme PrefersColorScheme @default(NO_PREFERENCE) - prefersReducedMotion PrefersReducedMotion @default(NO_PREFERENCE) - prefersEmail emails? @relation("userPrefersEmail", fields: [prefersEmailId], references: [id]) - prefersEmailId Int? - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - role UserRole @default(USER) - timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) - twoFactorSecret String? - attributes Json? - updatedAt DateTime @updatedAt - emails emails[] @relation("userEmails") - accessTokens accessTokens[] @relation("userAccessTokens") - approvedLocations approvedLocations[] @relation("userApprovedLocations") - backupCodes backupCodes[] @relation("userBackupCodes") - identities identities[] @relation("userIdentities") - memberships memberships[] @relation("userMemberships") - sessions sessions[] @relation("userSessions") -} - -model groups { - autoJoinDomain Boolean @default(false) - createdAt DateTime @default(now()) - forceTwoFactor Boolean @default(false) - id Int @default(autoincrement()) @id - ipRestrictions String? - name String - onlyAllowDomain Boolean @default(false) - profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") - attributes Json? - updatedAt DateTime @updatedAt - apiKeys apiKeys[] @relation("groupApiKeys") - domains domains[] @relation("groupDomains") - memberships memberships[] @relation("groupMemberships") - webhooks webhooks[] @relation("groupWebhooks") -} - -model emails { - createdAt DateTime @default(now()) - email String - emailSafe String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - updatedAt DateTime @updatedAt - user users @relation("userEmails", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") - users users[] @relation("userPrefersEmail") -} - -model accessTokens { - createdAt DateTime @default(now()) - description String? - id Int @default(autoincrement()) @id - accessToken String - name String? - scopes Json? - updatedAt DateTime @updatedAt - user users @relation("userAccessTokens", fields: [userId], references: [id]) - userId Int - ipRestrictions Json? - referrerRestrictions Json? - - @@index([userId], name: "userId") -} - -model apiKeys { - createdAt DateTime @default(now()) - description String? - id Int @default(autoincrement()) @id - ipRestrictions Json? - apiKey String - name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int - referrerRestrictions Json? - scopes Json? - updatedAt DateTime @updatedAt -} - -model approvedLocations { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - subnet String - user users @relation("userApprovedLocations", fields: [userId], references: [id]) - userId Int -} - -model backupCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - isUsed Boolean @default(false) - user users @relation("userBackupCodes", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model couponCodes { - id Int @default(autoincrement()) @id - code String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - expiresAt DateTime? - maxUses Int @default(1000) - usedCount Int @default(0) - teamRestrictions String? - amount Int - currency String - description String? -} - -model domains { - createdAt DateTime @default(now()) - domain String - id Int @default(autoincrement()) @id - isVerified Boolean @default(false) - group groups @relation("groupDomains", fields: [groupId], references: [id]) - groupId Int - updatedAt DateTime @updatedAt - verificationCode String - - @@index([groupId], name: "groupId") -} - -model identities { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - loginName String - type IdentityType - updatedAt DateTime @updatedAt - user users @relation("userIdentities", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model memberships { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - group groups @relation("groupMemberships", fields: [groupId], references: [id]) - groupId Int - role MembershipRole @default(MEMBER) - updatedAt DateTime @updatedAt - user users @relation("userMemberships", fields: [userId], references: [id]) - userId Int - - @@index([groupId], name: "groupId") - @@index([userId], name: "userId") -} - -model sessions { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - ipAddress String - token String - updatedAt DateTime @updatedAt - userAgent String - city String? - region String? - timezone String? - countryCode String? - browser String? - operatingSystem String? - user users @relation("userSessions", fields: [userId], references: [id]) - userId Int - - @@index([userId], name: "userId") -} - -model webhooks { - contentType String @default("application/json") - createdAt DateTime @default(now()) - event String - id Int @default(autoincrement()) @id - isActive Boolean @default(false) - lastFiredAt DateTime? - group groups @relation("groupWebhooks", fields: [groupId], references: [id]) - groupId Int - secret String? - updatedAt DateTime @updatedAt - url String - - @@index([groupId], name: "groupId") -} diff --git a/prisma/migrations/20200923132041/steps.json b/prisma/migrations/20200923132041/steps.json deleted file mode 100644 index c8b9ed119..000000000 --- a/prisma/migrations/20200923132041/steps.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "0.3.14-fixed", - "steps": [ - { - "tag": "CreateField", - "model": "emails", - "field": "emailSafe", - "type": "String", - "arity": "Required" - } - ] -} \ No newline at end of file diff --git a/prisma/migrations/migrate.lock b/prisma/migrations/migrate.lock deleted file mode 100644 index 396842bac..000000000 --- a/prisma/migrations/migrate.lock +++ /dev/null @@ -1,6 +0,0 @@ -# Prisma Migrate lockfile v1 - -20200803235103 -20200804141140 -20200902181624 -20200923132041 \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 98c6492b3..d57190e26 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -36,6 +36,13 @@ enum UserRole { USER } +enum MfaMethod { + NONE + SMS + TOTP + EMAIL +} + enum MembershipRole { OWNER ADMIN @@ -53,7 +60,7 @@ model users { countryCode String @default("us") createdAt DateTime @default(now()) gender Gender @default(UNKNOWN) - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) name String notificationEmails NotificationEmails @default(ACCOUNT) password String? @@ -65,24 +72,26 @@ model users { profilePictureUrl String @default("https://unavatar.now.sh/fallback.png") role UserRole @default(USER) timezone String @default("America/Los_Angeles") - twoFactorEnabled Boolean @default(false) + twoFactorMethod MfaMethod @default(NONE) + twoFactorPhone String? twoFactorSecret String? attributes Json? updatedAt DateTime @updatedAt emails emails[] @relation("userEmails") - accessTokens accessTokens[] @relation("userAccessTokens") - approvedLocations approvedLocations[] @relation("userApprovedLocations") + approvedSubnets approvedSubnets[] @relation("userApprovedSubnets") backupCodes backupCodes[] @relation("userBackupCodes") identities identities[] @relation("userIdentities") memberships memberships[] @relation("userMemberships") sessions sessions[] @relation("userSessions") + auditLogs auditLogs[] @relation("userAuditLog") + apiKeys apiKeys[] @relation("userApiKeys") } model groups { autoJoinDomain Boolean @default(false) createdAt DateTime @default(now()) forceTwoFactor Boolean @default(false) - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) ipRestrictions String? name String onlyAllowDomain Boolean @default(false) @@ -93,62 +102,54 @@ model groups { domains domains[] @relation("groupDomains") memberships memberships[] @relation("groupMemberships") webhooks webhooks[] @relation("groupWebhooks") + auditLogs auditLogs[] @relation("groupAuditLog") } model emails { createdAt DateTime @default(now()) - email String - emailSafe String - id Int @default(autoincrement()) @id + email String @unique + emailSafe String @unique + id Int @id @default(autoincrement()) isVerified Boolean @default(false) updatedAt DateTime @updatedAt user users @relation("userEmails", fields: [userId], references: [id]) userId Int - @@index([userId], name: "userId") users users[] @relation("userPrefersEmail") -} - -model accessTokens { - createdAt DateTime @default(now()) - description String? - id Int @default(autoincrement()) @id - accessToken String - name String? - scopes Json? - updatedAt DateTime @updatedAt - user users @relation("userAccessTokens", fields: [userId], references: [id]) - userId Int - ipRestrictions Json? - referrerRestrictions Json? - @@index([userId], name: "userId") } model apiKeys { createdAt DateTime @default(now()) description String? - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) ipRestrictions Json? - apiKey String + apiKey String @unique name String? - group groups @relation("groupApiKeys", fields: [groupId], references: [id]) - groupId Int + group groups? @relation("groupApiKeys", fields: [groupId], references: [id]) + groupId Int? + user users? @relation("userApiKeys", fields: [userId], references: [id]) + userId Int? referrerRestrictions Json? scopes Json? updatedAt DateTime @updatedAt } -model approvedLocations { - createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id - subnet String - user users @relation("userApprovedLocations", fields: [userId], references: [id]) - userId Int +model approvedSubnets { + createdAt DateTime @default(now()) + id Int @id @default(autoincrement()) + subnet String + city String? + region String? + timezone String? + countryCode String? + updatedAt DateTime @updatedAt + user users @relation("userApprovedSubnets", fields: [userId], references: [id]) + userId Int } model backupCodes { - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) code String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -160,7 +161,7 @@ model backupCodes { } model couponCodes { - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) code String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -176,7 +177,7 @@ model couponCodes { model domains { createdAt DateTime @default(now()) domain String - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) isVerified Boolean @default(false) group groups @relation("groupDomains", fields: [groupId], references: [id]) groupId Int @@ -188,7 +189,7 @@ model domains { model identities { createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) loginName String type IdentityType updatedAt DateTime @updatedAt @@ -200,7 +201,7 @@ model identities { model memberships { createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) group groups @relation("groupMemberships", fields: [groupId], references: [id]) groupId Int role MembershipRole @default(MEMBER) @@ -214,7 +215,7 @@ model memberships { model sessions { createdAt DateTime @default(now()) - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) ipAddress String token String updatedAt DateTime @updatedAt @@ -235,7 +236,7 @@ model webhooks { contentType String @default("application/json") createdAt DateTime @default(now()) event String - id Int @default(autoincrement()) @id + id Int @id @default(autoincrement()) isActive Boolean @default(false) lastFiredAt DateTime? group groups @relation("groupWebhooks", fields: [groupId], references: [id]) @@ -246,3 +247,25 @@ model webhooks { @@index([groupId], name: "groupId") } + +model auditLogs { + createdAt DateTime @default(now()) + event String + id Int @id @default(autoincrement()) + group groups? @relation("groupAuditLog", fields: [groupId], references: [id]) + groupId Int? + updatedAt DateTime @updatedAt + user users? @relation("userAuditLog", fields: [userId], references: [id]) + userId Int? + ipAddress String? + userAgent String? + city String? + region String? + timezone String? + countryCode String? + browser String? + operatingSystem String? + + @@index([userId], name: "userId") + @@index([groupId], name: "groupId") +} diff --git a/release.config.js b/release.config.js new file mode 100644 index 000000000..2aba67b1b --- /dev/null +++ b/release.config.js @@ -0,0 +1 @@ +module.exports = require("@koj/config").releaseMaster; diff --git a/src/@types/babel__polyfill.d.ts b/src/@types/babel__polyfill.d.ts deleted file mode 100644 index 877d939ed..000000000 --- a/src/@types/babel__polyfill.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "@babel/polyfill" {} diff --git a/src/@types/regenerator-runtime.d.ts b/src/@types/regenerator-runtime.d.ts deleted file mode 100644 index f80ab1ea9..000000000 --- a/src/@types/regenerator-runtime.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "regenerator-runtime" {} diff --git a/src/_staart/config.ts b/src/_staart/config.ts deleted file mode 100644 index 06f629f80..000000000 --- a/src/_staart/config.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This is the central configuration file for Staart - * It is RECOMMENDED that you do not modify this file, but create - * your own configuration file in `src/` to add custom properties. - */ - -import { cosmicSync } from "@anandchowdhary/cosmic"; -import { - BaseScopesUser, - BaseScopesGroup, - BaseScopesAdmin, -} from "./helpers/authorization"; -cosmicSync("staart"); - -/** - * Convert a Check if a boolean value is true (supports strings) - * @param booleanValue - Value to convert - */ -export const bool = (booleanValue?: string | boolean) => - String(booleanValue).toLowerCase() === "true"; - -export const ScopesUser = { ...BaseScopesUser }; -export const ScopesGroup = { ...BaseScopesGroup }; -export const ScopesAdmin = { ...BaseScopesAdmin }; diff --git a/src/_staart/helpers/__tests__/utils.ts b/src/_staart/helpers/__tests__/utils.ts deleted file mode 100644 index 95e38741f..000000000 --- a/src/_staart/helpers/__tests__/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { deleteSensitiveInfoUser } from "../utils"; - -test("Remove sensitive info", () => { - expect( - deleteSensitiveInfoUser({ - id: "wiuhoeijpaoe", - name: "Anand Chowdhary", - password: "1abc9c", - }).password - ).toBeUndefined(); -}); diff --git a/src/_staart/helpers/authorization.ts b/src/_staart/helpers/authorization.ts deleted file mode 100644 index 4394ad5c6..000000000 --- a/src/_staart/helpers/authorization.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Model, newEnforcer, StringAdapter } from "casbin"; -import { join } from "path"; -import { ScopesAdmin, ScopesGroup, ScopesUser } from "../config"; -import { getUserById } from "../services/user.service"; -import { AccessTokenResponse, ApiKeyResponse } from "./jwt"; -import { prisma } from "./prisma"; -import { twtToId } from "./utils"; - -/** - * You should not overwrite these scopes - * Instead, add them to .staartrc.json - * Acts are prepended to scopes to generate actions - * "read:" + "users/info" = "read:users/info" - */ -export enum Acts { - READ = "read:", - WRITE = "write:", - DELETE = "delete:", -} - -/** Base scopes for users */ -export const BaseScopesUser = { - INFO: "users/info", - ACCESS_TOKENS: "users/access-tokens", - EMAILS: "users/emails", - IDENTITIES: "users/identities", - MEMBERSHIPS: "users/memberships", - SECURITY: "users/security", - SESSIONS: "users/sessions", -}; - -/** Base scopes for groups */ -export const BaseScopesGroup = { - INFO: "groups/info", - API_KEYS: "groups/api-keys", - API_KEY_LOGS: "groups/api-key-logs", - BILLING: "groups/billing", - DOMAINS: "groups/domains", - INVOICES: "groups/invoices", - MEMBERSHIPS: "groups/memberships", - SOURCES: "groups/sources", - SUBSCRIPTIONS: "groups/subscriptions", - TRANSACTIONS: "groups/transactions", - WEBHOOKS: "groups/webhooks", - SECURITY: "groups/security", -}; - -/** Base scopes for admin users */ -export const BaseScopesAdmin = { - GROUPS: "admin/groups", - USERS: "admin/users", - COUPONS: "admin/coupons", - PAYMENT_EVENTS: "admin/payment-events", - SERVER_LOGS: "admin/server-logs", -}; - -/** - * Generate and fetch the casbin policy for a user - * @param id - User ID (TWT-encoded) - */ -const getPolicyForUser = async (id: number) => { - let policy = ""; - const userId = twtToId(id); - - // A user can do anything to themselves, for all user scopes - Object.values(ScopesUser).forEach((scope) => { - policy += `p, user-${userId}, user-${userId}, ${Acts.READ}${scope}\n`; - policy += `p, user-${userId}, user-${userId}, ${Acts.WRITE}${scope}\n`; - }); - - // A user can delete themself - policy += `p, user-${userId}, user-${userId}, ${Acts.DELETE}${ScopesUser.INFO}\n`; - - // Find all the memberships for this user - // Then add the rules for each memberships - const memberships = await prisma.memberships.findMany({ - where: { id }, - }); - for await (const membership of memberships) { - const membershipId = twtToId(membership.id); - const groupId = twtToId(membership.groupId); - - // A user can read, write, and delete the membership - policy += `p, user-${userId}, membership-${membershipId}, ${Acts.READ}${ScopesUser.MEMBERSHIPS}\n`; - policy += `p, user-${userId}, membership-${membershipId}, ${Acts.WRITE}${ScopesUser.MEMBERSHIPS}\n`; - policy += `p, user-${userId}, membership-${membershipId}, ${Acts.DELETE}${ScopesUser.MEMBERSHIPS}\n`; - - // Admins can also delete other memberships in a group - if (membership.role === "ADMIN" || membership.role === "OWNER") { - // Find all the memberships in a group the user is admin of - // Then, add the rules to read, write, delete them - const groupMemberships = await prisma.memberships.findMany({ - where: { groupId: membership.groupId }, - }); - - // You can delete the group if you're an admin - policy += `p, user-${userId}, group-${groupId}, ${Acts.DELETE}${ScopesGroup.INFO}\n`; - - groupMemberships.forEach((groupMembership) => { - const memberId = twtToId(groupMembership.id); - // You can read each membership - policy += `p, user-${userId}, membership-${memberId}, ${Acts.READ}${ScopesUser.MEMBERSHIPS}\n`; - - // If you're the owner, not just an admin, you can edit the membership - if (groupMembership.role !== "OWNER") { - policy += `p, user-${userId}, membership-${memberId}, ${Acts.WRITE}${ScopesUser.MEMBERSHIPS}\n`; - policy += `p, user-${userId}, membership-${memberId}, ${Acts.DELETE}${ScopesUser.MEMBERSHIPS}\n`; - } - }); - } - - Object.values(ScopesGroup).forEach((scope) => { - if (membership.role === "ADMIN" || membership.role === "OWNER") { - // Admins can read and write groups - policy += `p, user-${userId}, group-${groupId}, ${Acts.READ}${scope}\n`; - policy += `p, user-${userId}, group-${groupId}, ${Acts.WRITE}${scope}\n`; - } else { - // Non-admins can only read the group - policy += `p, user-${userId}, group-${groupId}, ${Acts.READ}${scope}\n`; - } - }); - } - const userDetails = await getUserById(id); - if (userDetails.role === "SUDO") { - // Superadmins can read and write anything - Object.values(ScopesAdmin).forEach((scope) => { - policy += `p, user-${userId}, ${Acts.READ}, ${scope}\n`; - policy += `p, user-${userId}, ${Acts.WRITE}, ${scope}\n`; - }); - } - return policy; -}; - -// Load the model from root config -const model = new Model(); -model.loadModel(join(".", "casbin-model.conf")); - -/** - * Authorization helper to check whether a user has permission to do something - * Apart from user IDs, API key or access token objects can be used as well - * @param subject - Subject of the authorization check - * @param action - Action of the authorization check - * @param object - Object of the authorization check - */ -export const can = async ( - subject: number | ApiKeyResponse | AccessTokenResponse, - action: string, - object: string -) => { - if (typeof subject === "number") { - const policy = await getPolicyForUser(subject); - const enforcer = await newEnforcer(model, new StringAdapter(policy)); - return enforcer.enforce(`user-${subject}`, object, action); - } - return false; -}; diff --git a/src/_staart/helpers/cache.ts b/src/_staart/helpers/cache.ts deleted file mode 100644 index 9fdd7a882..000000000 --- a/src/_staart/helpers/cache.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { RESOURCE_NOT_FOUND } from "@staart/errors"; -import { redis } from "@staart/redis"; - -/** - * Get an item from Redis cache - * @param key - Key - */ -export const getItemFromCache = async (key: string) => { - const result = await redis.get(key); - if (result) return JSON.parse(result) as T; - throw new Error(RESOURCE_NOT_FOUND); -}; - -/** - * Delete items from Redis cache - * @param keys - Keys to delete - */ -export const deleteItemFromCache = async (...keys: string[]) => { - return redis.del(...keys); -}; - -/** - * Set a new item in Redis cache - * @param key - Item key - * @param value - Item value object - * @param expiry - Expiry time (defaults to 10 mins) - */ -export const setItemInCache = async ( - key: string, - value: any, - expiry?: Date -) => { - await redis.set(key, JSON.stringify(value), [ - "EX", - expiry ? Math.floor((expiry.getTime() - new Date().getTime()) / 1000) : 600, - ]); -}; diff --git a/src/_staart/helpers/elasticsearch.ts b/src/_staart/helpers/elasticsearch.ts deleted file mode 100644 index 543a4f3df..000000000 --- a/src/_staart/helpers/elasticsearch.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { elasticSearch, elasticSearchEnabled } from "@staart/elasticsearch"; -import { logError } from "@staart/errors"; -import { redisQueue } from "@staart/redis"; -import { config } from "@anandchowdhary/cosmic"; - -const ELASTIC_QUEUE = `${config("redisQueuePrefix")}_es-records`; - -let queueSetup = false; -/** Setup the Redis queue to ElasticSearch records */ -const setupQueue = async () => { - if (queueSetup) return true; - const queues = redisQueue.listQueuesAsync(); - if ((await queues).includes(ELASTIC_QUEUE)) return (queueSetup = true); - await redisQueue.createQueueAsync({ qname: ELASTIC_QUEUE }); - return (queueSetup = true); -}; - -/** - * Add a new record to an ElasticSearch index - * @param indexParams - Params (index and body) - */ -export const elasticSearchIndex = async (indexParams: { - index: string; - body: any; -}) => { - await setupQueue(); - await redisQueue.sendMessageAsync({ - qname: ELASTIC_QUEUE, - message: JSON.stringify({ indexParams, tryNumber: 1 }), - }); -}; - -/** Receieve new messages from the queue and index records */ -export const receiveElasticSearchMessage = async () => { - await setupQueue(); - const result = await redisQueue.receiveMessageAsync({ - qname: ELASTIC_QUEUE, - }); - if ("id" in result) { - if (!elasticSearchEnabled) - return redisQueue.deleteMessageAsync({ - qname: ELASTIC_QUEUE, - id: result.id, - }); - const { - indexParams, - tryNumber, - }: { - tryNumber: number; - indexParams: { - index: string; - body: string; - type: string; - }; - } = JSON.parse(result.message); - if (tryNumber && tryNumber > 3) - return redisQueue.deleteMessageAsync({ - qname: ELASTIC_QUEUE, - id: result.id, - }); - try { - await elasticSearch.index(indexParams); - } catch (error) { - logError( - "ElasticSearch", - `Unable to save record, trying again: ${JSON.stringify(error)}` - ); - await redisQueue.sendMessageAsync({ - qname: ELASTIC_QUEUE, - message: JSON.stringify({ - indexParams, - tryNumber: tryNumber + 1, - }), - }); - } - await redisQueue.deleteMessageAsync({ - qname: ELASTIC_QUEUE, - id: result.id, - }); - receiveElasticSearchMessage(); - } -}; diff --git a/src/_staart/helpers/errors.ts b/src/_staart/helpers/errors.ts deleted file mode 100644 index 0ff9792b0..000000000 --- a/src/_staart/helpers/errors.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { EXPIRED_TOKEN, INVALID_TOKEN, warn } from "@staart/errors"; -import { ValidationError } from "@staart/validate"; -import { HTTPError } from "../interfaces/general"; - -/** - * Parse default errors and send a safe string - */ -export const safeError = (error: string) => { - let errorString = error.toString(); - if (errorString.startsWith("Error: ")) - errorString = errorString.replace("Error: ", ""); - if (errorString.startsWith("joi:")) { - const joiError = JSON.parse( - errorString.split("joi:")[1] - ) as ValidationError; - return sendError(`422/${joiError.details[0].message}`); - } - if (errorString === "TokenExpiredError: jwt expired") - return sendError(EXPIRED_TOKEN); - if (errorString.startsWith("JsonWebToken")) return sendError(INVALID_TOKEN); - console.log(error); - return sendError(errorString); -}; - -/** - * Send an HTTPError object - */ -export const sendError = (error: string) => { - if (error.includes("/")) { - let status = parseInt(error.split("/")[0]); - if (isNaN(status)) status = 500; - const code = error.split("/")[1]; - return { status, code } as HTTPError; - } - warn(error); - return { status: 500, code: error } as HTTPError; -}; diff --git a/src/_staart/helpers/jwt.ts b/src/_staart/helpers/jwt.ts deleted file mode 100644 index 912d66787..000000000 --- a/src/_staart/helpers/jwt.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { users } from "@prisma/client"; -import { - IP_RANGE_CHECK_FAIL, - REFERRER_CHECK_FAIL, - REVOKED_TOKEN, - UNAPPROVED_LOCATION, - UNVERIFIED_EMAIL, - USER_NOT_FOUND, -} from "@staart/errors"; -import { redis } from "@staart/redis"; -import { ipRangeCheck, randomString } from "@staart/text"; -import { decode, sign, verify } from "jsonwebtoken"; -import { EventType, Templates, Tokens } from "../interfaces/enum"; -import { Locals } from "../interfaces/general"; -import { - checkApprovedLocation, - getUserPrimaryEmail, - updateSessionByJwt, -} from "../services/user.service"; -import { getGeolocationFromIp } from "./location"; -import { mail } from "./mail"; -import { prisma } from "./prisma"; -import { includesDomainInCommaList } from "./utils"; - -const JWT_ISSUER = config("jwtIssuer"); -const JWT_SECRET = config("jwtSecret"); -const TOKEN_EXPIRY_APPROVE_LOCATION = config("tokenExpiryApproveLocation"); -const TOKEN_EXPIRY_EMAIL_VERIFICATION = config("tokenExpiryEmailVerification"); -const TOKEN_EXPIRY_LOGIN = config("tokenExpiryLogin"); -const TOKEN_EXPIRY_PASSWORD_RESET = config("tokenExpiryPasswordReset"); -const TOKEN_EXPIRY_REFRESH = config("tokenExpiryRefresh"); - -/** - * Generate a new JWT - */ -export const generateToken = ( - payload: string | object | Buffer, - expiresIn: string | number, - subject: Tokens -): Promise => - new Promise((resolve, reject) => { - sign( - // Payload is expected to be a plain object - JSON.parse(JSON.stringify(payload)), - JWT_SECRET, - { - expiresIn, - subject, - issuer: JWT_ISSUER, - jwtid: randomString({ length: 12 }), - }, - (error, token) => { - if (error) return reject(error); - resolve(token); - } - ); - }); - -export interface TokenResponse { - id: number; - ipAddress?: string; -} -export interface ApiKeyResponse { - id: number; - groupId: string; - scopes: string; - jti: string; - sub: Tokens.API_KEY; - exp: number; - ipRestrictions?: string; - referrerRestrictions?: string; -} -export interface AccessTokenResponse { - id: number; - userId: string; - scopes: string; - jti: string; - sub: Tokens.ACCESS_TOKEN; - exp: number; -} - -/** - * Verify a JWT - */ -export const verifyToken = (token: string, subject: Tokens): Promise => - new Promise((resolve, reject) => { - verify(token, JWT_SECRET, { subject }, (error, data) => { - if (error) return reject(error); - resolve((data as any) as T); - }); - }); - -/** - * Generate a new coupon JWT - */ -export const couponCodeJwt = ( - amount: number, - currency: string, - description?: string, - expiresAt?: string -) => - generateToken( - { amount, currency, description }, - expiresAt - ? (new Date(expiresAt).getTime() - new Date().getTime()) / 1000 - : "30d", - Tokens.COUPON - ); - -/** - * Generate a new email verification JWT - */ -export const emailVerificationToken = (id: number) => - generateToken({ id }, TOKEN_EXPIRY_EMAIL_VERIFICATION, Tokens.EMAIL_VERIFY); - -/** - * Generate a new email verification JWT - */ -export const resendEmailVerificationToken = (id: number) => - generateToken({ id }, TOKEN_EXPIRY_EMAIL_VERIFICATION, Tokens.EMAIL_RESEND); - -/** - * Generate a new password reset JWT - */ -export const passwordResetToken = (id: number) => - generateToken({ id }, TOKEN_EXPIRY_PASSWORD_RESET, Tokens.PASSWORD_RESET); - -/** - * Generate a new login JWT - */ -export const loginToken = (id: number) => - generateToken({ id }, TOKEN_EXPIRY_LOGIN, Tokens.LOGIN); - -/** - * Generate a new login link JWT - */ -export const loginLinkToken = (user: users) => - generateToken({ id: user.id }, TOKEN_EXPIRY_LOGIN, Tokens.LOGIN_LINK); - -/** - * Generate a new 2FA JWT - */ -export const twoFactorToken = (user: users) => - generateToken({ id: user.id }, TOKEN_EXPIRY_LOGIN, Tokens.TWO_FACTOR); - -/** - * Generate a new approve location JWT - */ -export const approveLocationToken = (id: number, ipAddress: string) => - generateToken( - { id, ipAddress }, - TOKEN_EXPIRY_APPROVE_LOCATION, - Tokens.APPROVE_LOCATION - ); - -/** - * Generate a new refresh JWT - */ -export const refreshToken = (id: number) => - generateToken({ id }, TOKEN_EXPIRY_REFRESH, Tokens.REFRESH); - -export const postLoginTokens = async ( - user: users, - locals: Locals | any, - refreshTokenString?: string -) => { - if (!user.id) throw new Error(USER_NOT_FOUND); - const refresh = await refreshToken(user.id); - if (!refreshTokenString) { - let token = refresh; - try { - const decoded = decode(refresh); - if (decoded && typeof decoded === "object" && decoded.jti) { - token = decoded.jti; - } - } catch (error) {} - await prisma.sessions.create({ - data: { - token, - ipAddress: locals.ipAddress || "unknown-ip-address", - userAgent: locals.userAgent || "unknown-user-agent", - user: { connect: { id: user.id } }, - }, - }); - } else { - await updateSessionByJwt(user.id, refreshTokenString, {}); - } - return { - token: await loginToken(user.id), - refresh: !refreshTokenString ? refresh : undefined, - }; -}; - -export interface LoginResponse { - twoFactorToken?: string; - token?: string; - refresh?: string; - [index: string]: string | undefined; -} -/** - * Get the token response after logging in a user - */ -export const getLoginResponse = async ( - user: users, - type: EventType, - strategy: string, - locals: Locals | any -): Promise => { - if (!user.id) throw new Error(USER_NOT_FOUND); - const verifiedEmails = await prisma.emails.findMany({ - where: { userId: user.id, isVerified: true }, - }); - if (!verifiedEmails.length) throw new Error(UNVERIFIED_EMAIL); - if (locals) { - if (!(await checkApprovedLocation(user.id, locals.ipAddress))) { - const location = await getGeolocationFromIp(locals.ipAddress); - await mail({ - to: (await getUserPrimaryEmail(user.id)).email, - template: Templates.UNAPPROVED_LOCATION, - data: { - ...user, - location: location - ? location.city || location.region_name || location.country_code - : "Unknown location", - token: await approveLocationToken(user.id, locals.ipAddress), - }, - }); - throw new Error(UNAPPROVED_LOCATION); - } - } - if (user.twoFactorEnabled) - return { - twoFactorToken: await twoFactorToken(user), - }; - return postLoginTokens(user, locals); -}; - -/** - * Check if a token is invalidated in Redis - * @param token - JWT - */ -export const checkInvalidatedToken = async (token: string) => { - if (!redis) return; - const details = decode(token); - if ( - details && - typeof details === "object" && - details.jti && - (await redis.get(`${JWT_ISSUER}-revoke-${details.sub}-${details.jti}`)) - ) - throw new Error(REVOKED_TOKEN); -}; - -/** - * Invalidate a JWT using Redis - * @param token - JWT - */ -export const invalidateToken = async (token: string) => { - if (!redis) return; - const details = decode(token); - if (details && typeof details === "object" && details.jti) - await redis.set( - `${JWT_ISSUER}-revoke-${details.sub}-${details.jti}`, - "1", - details.exp && [ - "EX", - Math.floor((details.exp - new Date().getTime()) / 1000), - ] - ); -}; - -export const checkIpRestrictions = ( - apiKey: ApiKeyResponse, - locals: Locals | any -) => { - if (!apiKey.ipRestrictions) return; - if ( - !ipRangeCheck( - locals.ipAddress, - apiKey.ipRestrictions.split(",").map((range) => range.trim()) - ) - ) - throw new Error(IP_RANGE_CHECK_FAIL); -}; - -export const checkReferrerRestrictions = ( - apiKey: ApiKeyResponse, - domain: string -) => { - if (!apiKey.referrerRestrictions || !domain) return; - if (!includesDomainInCommaList(apiKey.referrerRestrictions, domain)) - throw new Error(REFERRER_CHECK_FAIL); -}; diff --git a/src/_staart/helpers/location.ts b/src/_staart/helpers/location.ts deleted file mode 100644 index 3210a281d..000000000 --- a/src/_staart/helpers/location.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { success } from "@staart/errors"; -import geolite2 from "geolite2-redist"; -import maxmind, { CityResponse, Reader } from "maxmind"; - -export interface GeoLocation { - city?: string; - country_code?: string; - continent?: string; - latitude?: number; - longitude?: number; - time_zone?: string; - accuracy_radius?: number; - zip_code?: string; - region_name?: string; - region_code?: string; -} - -// In-memory cache of the reader -let lookup: Reader | undefined = undefined; - -/** Get cached lookup or open a new one */ -const getLookup = async () => { - if (lookup) return lookup; - lookup = await geolite2.open("GeoLite2-City", (path) => { - return maxmind.open(path); - }); - success("Opened GeoIP2 database reader"); - return lookup; -}; - -/** - * Get the geolocation from an IP address using GeoIP2 - * @param ipAddress - IP address - */ -export const getGeolocationFromIp = async ( - ipAddress: string -): Promise => { - const location: GeoLocation = {}; - try { - const lookup = await getLookup(); - const ipLookup = lookup.get(ipAddress); - if (!ipLookup) return location; - if (ipLookup.city) location.city = ipLookup.city.names.en; - if (ipLookup.continent) location.continent = ipLookup.continent.names.en; - if (ipLookup.country) location.country_code = ipLookup.country.iso_code; - if (ipLookup.location) location.latitude = ipLookup.location.latitude; - if (ipLookup.location) location.longitude = ipLookup.location.longitude; - if (ipLookup.location) location.time_zone = ipLookup.location.time_zone; - if (ipLookup.location) - location.accuracy_radius = ipLookup.location.accuracy_radius; - if (ipLookup.postal) location.zip_code = ipLookup.postal.code; - if (ipLookup.subdivisions) - location.region_name = ipLookup.subdivisions[0].names.en; - if (ipLookup.subdivisions) - location.region_code = ipLookup.subdivisions[0].iso_code; - } catch (error) {} - return location; -}; diff --git a/src/_staart/helpers/mail.ts b/src/_staart/helpers/mail.ts deleted file mode 100644 index 7e0753de3..000000000 --- a/src/_staart/helpers/mail.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { logError } from "@staart/errors"; -import { Mail, sendMail } from "@staart/mail"; -import { render } from "@staart/mustache-markdown"; -import { redisQueue } from "@staart/redis"; -import { readFile } from "fs-extra"; -import { join } from "path"; -import { PartialBy } from "../../_staart/helpers/utils"; -import { config } from "@anandchowdhary/cosmic"; - -const MAIL_QUEUE = `${config("redisQueuePrefix")}-outbound-emails`; - -let queueSetup = false; -/** Setup the Redis queue to send emails */ -const setupQueue = async () => { - if (queueSetup) return true; - const queues = redisQueue.listQueuesAsync(); - if ((await queues).includes(MAIL_QUEUE)) return (queueSetup = true); - await redisQueue.createQueueAsync({ qname: MAIL_QUEUE }); - return (queueSetup = true); -}; - -/** Receieve messages from the Redis queue and send emails */ -export const receiveEmailMessage = async () => { - await setupQueue(); - const result = await redisQueue.receiveMessageAsync({ - qname: MAIL_QUEUE, - }); - if ("id" in result) { - const data: PartialBy, "message"> & { - template?: string; - data?: any; - tryNumber: number; - } = JSON.parse(result.message); - if (data.tryNumber && data.tryNumber > 3) { - logError("Email", `Unable to send email: ${data.to}`); - return redisQueue.deleteMessageAsync({ - qname: MAIL_QUEUE, - id: result.id, - }); - } - try { - await safeSendEmail(data); - } catch (error) { - console.log(error); - await redisQueue.sendMessageAsync({ - qname: MAIL_QUEUE, - message: JSON.stringify({ - ...data, - tryNumber: (data.tryNumber || 0) + 1, - }), - }); - } - await redisQueue.deleteMessageAsync({ - qname: MAIL_QUEUE, - id: result.id, - }); - receiveEmailMessage(); - } -}; - -/** Send a new email using AWS SES or SMTP */ -export const mail = async ( - options: PartialBy, "message"> & { - template?: string; - data?: any; - } -) => { - await setupQueue(); - await redisQueue.sendMessageAsync({ - qname: MAIL_QUEUE, - message: JSON.stringify({ ...options, tryNumber: 1 }), - }); -}; - -/** Send an email suppressing any errors */ -const safeSendEmail = async ( - options: PartialBy, "message"> & { - template?: string; - data?: any; - } -) => { - options.subject = options.subject || ""; - options.message = options.message || ""; - if (options.template) { - const result = render( - ( - await readFile( - join( - __dirname, - "..", - "..", - "..", - "..", - "src", - "templates", - `${options.template}.md` - ) - ) - ).toString(), - { ...options.data, frontendUrl: config("frontendUrl") } - ); - options.altText = result[0]; - options.message = result[1]; - options.subject = result[1] - .split("\n", 1)[0] - .replace(/<\/?[^>]+(>|$)/g, ""); - } - return sendMail( - options as Mail & { - template?: string; - data?: any; - } - ); -}; diff --git a/src/_staart/helpers/middleware.ts b/src/_staart/helpers/middleware.ts deleted file mode 100644 index 4ac8454bc..000000000 --- a/src/_staart/helpers/middleware.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { - INVALID_SIGNATURE, - MISSING_SIGNATURE, - MISSING_TOKEN, -} from "@staart/errors"; -import { constructWebhookEvent } from "@staart/payments"; -import { - NextFunction, - RateLimit, - RawRequest, - Request, - Response, - slowDown, -} from "@staart/server"; -import { ms } from "@staart/text"; -import { joiValidate, SchemaMap } from "@staart/validate"; -import pkg from "../../../package.json"; -import { Tokens } from "../interfaces/enum"; -import { StripeLocals, Locals } from "../interfaces/general"; -import { safeError } from "./errors"; -import { - ApiKeyResponse, - checkInvalidatedToken, - checkIpRestrictions, - checkReferrerRestrictions, - TokenResponse, - verifyToken, -} from "./jwt"; -import { trackUrl } from "./tracking"; -import { includesDomainInCommaList } from "./utils"; -import { config } from "@anandchowdhary/cosmic"; - -const bruteForce = slowDown({ - windowMs: config("bruteForceTime", 300000), // 10 minutes - delayAfter: config("bruteForceCount", 250), // 250 requests - delayMs: config("bruteForceDelay", 5), // 50ms -}); -const rateLimiter = RateLimit({ - windowMs: config("rateLimitTime", 60000), // 1 minute - max: config("rateLimitMax", 1000), // 1000 requests -}); -const publicRateLimiter = RateLimit({ - windowMs: config("publicRateLimitTime", 60000), // 1 minute - max: config("publicRateLimitMax", 60), // 60 requests -}); -const speedLimiter = slowDown({ - windowMs: config("speedLimitTime", 600000), // 10 minutes - delayAfter: config("speedLimitCount", 100), // 100 requests - delayMs: config("speedLimitDelay", 1000), // 1000ms -}); - -/** - * Handle any errors for Express - */ -export const errorHandler = ( - error: any, - req: Request, - res: Response, - next: NextFunction -) => { - if (error.api_error_code) { - // Handle Chargebee errors - error = error.message; - } - const response = safeError(error.toString().replace("Error: ", "")); - res.status(response.status); - res.json({ error: response.code, message: response.message }); -}; - -/** - * Add locals for IP address and user agent - */ -export const trackingHandler = ( - req: Request, - res: Response, - next: NextFunction -) => { - res.locals.userAgent = req.get("User-Agent"); - res.setHeader("X-Api-Version", pkg.version); - let ip = - req.headers["x-forwarded-for"] || - req.connection.remoteAddress || - req.socket.remoteAddress; - if (ip === "::1") ip = "2001:67c:2564:a309:f0e0:1ee6:137b:29e8"; - if (typeof ip === "string") ip = ip.split(",")[0]; - if (Array.isArray(ip) && ip.length) ip = ip[0]; - res.locals.ipAddress = ip; - res.locals.referrer = req.headers.referer as string; - trackUrl(req, res) - .then(() => {}) - .then(() => {}) - .finally(() => next()); -}; - -/** - * Add locals for a user after verifying their token - */ -export const authHandler = async ( - req: Request, - res: Response, - next: NextFunction -) => { - try { - let userJwt = req.get("Authorization"); - if (userJwt) { - if (userJwt.startsWith("Bearer ")) - userJwt = userJwt.replace("Bearer ", ""); - const userToken = await verifyToken(userJwt, Tokens.LOGIN); - await checkInvalidatedToken(userJwt); - if (userToken) res.locals.token = userToken; - } - - let apiKeyJwt = req.get("X-Api-Key") || req.query.key; - if (typeof apiKeyJwt === "string") { - if (apiKeyJwt.startsWith("Bearer ")) - apiKeyJwt = apiKeyJwt.replace("Bearer ", ""); - const apiKeyToken = await verifyToken( - apiKeyJwt, - Tokens.API_KEY - ); - await checkInvalidatedToken(apiKeyJwt); - checkIpRestrictions(apiKeyToken, res.locals as Locals); - const origin = req.get("Origin"); - if (origin) { - const referrerDomain = new URL(origin).hostname; - checkReferrerRestrictions(apiKeyToken, referrerDomain); - if (apiKeyToken.referrerRestrictions) { - if ( - includesDomainInCommaList( - apiKeyToken.referrerRestrictions, - referrerDomain - ) - ) { - res.setHeader("Access-Control-Allow-Origin", origin); - } - } else { - res.setHeader("Access-Control-Allow-Origin", "*"); - } - } - if (apiKeyToken && !res.locals.token) res.locals.token = apiKeyToken; - } - } catch (error) { - const jwtError = safeError(error); - res.status(jwtError.status); - return res.json(jwtError); - } - - if (res.locals.token) return next(); - const error = safeError(MISSING_TOKEN); - res.status(error.status); - return res.json(error); -}; - -/** - * Brute force middleware - */ -export const bruteForceHandler = bruteForce; - -/** - * Rate limiting middleware - */ -export const rateLimitHandler = async ( - req: Request, - res: Response, - next: NextFunction -) => { - const apiKey = req.get("X-Api-Key") || req.query.key; - if (typeof apiKey === "string") { - try { - const details = await verifyToken(apiKey, Tokens.API_KEY); - if (details.groupId) { - res.setHeader("X-Rate-Limit-Type", "api-key"); - return rateLimiter(req, res, next); - } - } catch (error) {} - } - res.setHeader("X-RateLimit-Limit-Type", "public"); - return publicRateLimiter(req, res, next); -}; - -/** - * Speed limiting middleware - */ -export const speedLimitHandler = async ( - req: Request, - res: Response, - next: NextFunction -) => { - const apiKey = req.get("X-Api-Key") || req.query.key; - if (typeof apiKey === "string") { - try { - const details = await verifyToken(apiKey, Tokens.API_KEY); - if (details.groupId) { - res.setHeader("X-Rate-Limit-Type", "api-key"); - return next(); - } - } catch (error) {} - } - return speedLimiter(req, res, next); -}; - -/** - * Response caching middleware - * @param time - Amount of time to cache contenr for - */ -export const cachedResponse = (time: string) => { - return (req: Request, res: Response, next: NextFunction) => { - res.set( - "Cache-Control", - `max-age=${Math.floor(ms(time) / 1000)}, must-revalidate` - ); - return next(); - }; -}; - -/** - * Validate the request contents - * @param schemaMap - Schema map object - * @param type - Request property - */ -export const validator = ( - schemaMap: SchemaMap, - type: "body" | "params" | "query" -) => { - return (req: Request, _: Response, next: NextFunction) => { - let data: any; - switch (type) { - case "params": - data = req.params; - break; - case "query": - data = req.query; - break; - default: - data = req.body; - } - joiValidate(schemaMap, data); - next(); - }; -}; - -/** - * Handle Stripe's webhook authentication - */ -export const stripeWebhookAuthHandler = async ( - req: Request, - res: Response, - next: NextFunction -) => { - const signature = req.get("stripe-signature"); - if (!signature) { - const error = safeError(MISSING_SIGNATURE); - res.status(error.status); - return res.json(error); - } - try { - const event = constructWebhookEvent((req as RawRequest).rawBody, signature); - (res.locals as StripeLocals).stripeEvent = event; - next(); - } catch (error) { - console.log("Webhook error", error); - const webhookError = safeError(INVALID_SIGNATURE); - res.status(webhookError.status); - return res.json(webhookError); - } -}; diff --git a/src/_staart/helpers/prisma.ts b/src/_staart/helpers/prisma.ts deleted file mode 100644 index 2b0ac2a3a..000000000 --- a/src/_staart/helpers/prisma.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { PrismaClient } from "@prisma/client"; -import { complete, success } from "@staart/errors"; -import { sign, verify } from "twt"; -import { cleanup } from "@staart/server"; -import { config } from "@anandchowdhary/cosmic"; - -/** Prisma client */ -export const prisma = new PrismaClient({ - log: config("nodeEnv") === "production" ? ["warn"] : ["info", "warn"], -}); - -/** - * Decode all TWT IDs as numbers in an object - * @param object - Object to decode - */ -const decodeTwtId = (object: any) => { - if (typeof object === "object" && !Array.isArray(object)) { - Object.keys(object).forEach((key: any) => { - if ( - typeof object[key] === "string" && - ((typeof key === "string" && key === "id") || key.endsWith("Id")) - ) { - object[key] = parseInt( - verify(object[key], config("twtSecret"), 10), - 10 - ); - } else if ( - typeof object[key] === "object" && - !Array.isArray(object[key]) - ) { - object[key] = decodeTwtId(object[key]); - } else if (Array.isArray(object[key])) { - object[key] = object[key].map((value: any) => decodeTwtId(value)); - } - }); - } else if (Array.isArray(object)) { - object = object.map((value: any) => decodeTwtId(value)); - } - return object; -}; - -prisma.$use(async (params, next) => { - // Decode TWT - if (typeof params.args === "object") params.args = decodeTwtId(params.args); - - const result = await next(params); - - // Use TWT IDs for objects - if (typeof result === "object" && !Array.isArray(result)) - Object.keys(result).forEach((key) => { - if ( - (key === "id" || key.endsWith("Id")) && - typeof result[key] === "number" - ) - result[key] = sign(String(result[key]), config("twtSecret"), 10); - }); - - // Use TWT IDs for arrays of objects - if (Array.isArray(result)) - result.map((result) => { - Object.keys(result).forEach((key) => { - if ( - (key === "id" || key.endsWith("Id")) && - typeof result[key] === "number" - ) - result[key] = sign(String(result[key]), config("twtSecret"), 10); - }); - return result; - }); - return result; -}); - -cleanup(() => { - complete("Gracefully exiting Staart API app"); - prisma.disconnect().then(() => success("Disconnected database connection")); -}); - -/** Convert search query params */ -export const queryParamsToSelect = (queryParams: any) => { - const data: any = {}; - - ["first", "last", "skip"].forEach((i: string) => { - if ( - typeof queryParams[i] === "string" && - !isNaN(parseInt(queryParams[i])) - ) { - data[i] = parseInt(queryParams[i]); - } - }); - - ["before", "after"].forEach((i: string) => { - if ( - typeof queryParams[i] === "string" && - !isNaN(parseInt(queryParams[i])) - ) { - data[i] = { - id: parseInt(queryParams[i]), - }; - } - }); - - ["select", "include"].forEach((i: string) => { - if (typeof queryParams[i] === "string") { - queryParams[i] - .split(",") - .map((j: string) => j.trim()) - .forEach((j: string) => { - data[i] = data[i] || {}; - data[i][j] = true; - }); - } - }); - - const orderBy = queryParams.orderBy; - if (typeof orderBy === "string") { - const orders = orderBy.split(",").map((i: string) => i.trim()); - orders.forEach((order) => { - data.orderBy = data.orderBy || {}; - data.orderBy[order.split(":")[0]] = - order.includes(":") && order.split(":")[1] === "desc" ? "desc" : "asc"; - }); - } - - return data; -}; - -/** Convert a Prisma response to pagination responses */ -export const paginatedResult = (data: T, { take }: { take?: number }) => { - const dataArray = (data as any) as { id: number }[]; - const hasMore = dataArray.length >= (take || Infinity); - return { - data, - hasMore, - next: hasMore ? dataArray[dataArray.length - 1].id : undefined, - }; -}; diff --git a/src/_staart/helpers/tracking.ts b/src/_staart/helpers/tracking.ts deleted file mode 100644 index e50ec8ff9..000000000 --- a/src/_staart/helpers/tracking.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Request, Response } from "@staart/server"; -import { Tokens } from "../interfaces/enum"; -import { Event, Locals } from "../interfaces/general"; -import { verifyToken } from "./jwt"; -import { config } from "@anandchowdhary/cosmic"; - -let trackingData: Array = []; -let securityEventsData: Array = []; - -/** Get tracking data currently in memory */ -export const getTrackingData = () => trackingData; - -/** Get audit events currently in memory */ -export const getSecurityEvents = () => securityEventsData; - -/** Clear tracking data currently in memory */ -export const clearTrackingData = () => (trackingData = []); - -/** Clear audit events currently in memory */ -export const clearSecurityEventsData = () => (securityEventsData = []); - -/** - * Track a new audit event - * @param event - Event to track - * @param locals - res.locals - */ -export const trackEvent = (event: Event, locals?: Locals | any) => { - if (!config("trackAuditLogData")) return; - event.date = new Date(); - if (locals) { - event.ipAddress = locals.ipAddress; - event.userAgent = locals.userAgent; - } - securityEventsData.push(event); -}; - -/** - * Track a new HTTP request - * @param req - Request - * @param res - Response - */ -export const trackUrl = async (req: Request, res: Response) => { - if (!config("trackRequestData")) return; - if (req.method === "OPTIONS") return; - const trackingObject: { [index: string]: any } = { - date: new Date(), - apiKey: req.get("X-Api-Key") || req.query.key, - method: req.method, - params: req.params, - protocol: req.protocol, - query: req.query, - body: req.body, - cookies: req.cookies, - headers: req.headers, - url: req.url, - ipCountry: (req.get("cf-ipcountry") || "").toLowerCase(), - ...res.locals, - }; - if (typeof trackingObject.apiKey === "string") { - try { - const token = await verifyToken( - trackingObject.apiKey, - Tokens.API_KEY - ); - trackingObject.apiKeyId = token.id; - trackingObject.apiKeyGroupId = token.groupId; - trackingObject.apiKeyJti = token.jti; - delete trackingObject.apiKey; - } catch (error) { - return; - } - } - Object.keys(trackingObject).forEach((key) => { - if ( - typeof trackingObject[key] === "object" && - !Array.isArray(trackingObject[key]) && - !(trackingObject[key] instanceof Date) - ) { - trackingObject[key] = JSON.stringify(trackingObject[key]); - } - if (trackingObject[key] === undefined) delete trackingObject[key]; - if (trackingObject[key] === "{}") delete trackingObject[key]; - }); - res.on("finish", () => { - trackingObject.statusCode = res.statusCode; - trackingObject.completedDate = new Date(); - trackingData.push(trackingObject); - }); -}; diff --git a/src/_staart/helpers/utils.ts b/src/_staart/helpers/utils.ts deleted file mode 100644 index b8d7d5349..000000000 --- a/src/_staart/helpers/utils.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { users } from "@prisma/client"; -import { Request, Response } from "@staart/server"; -import { isMatch } from "@staart/text"; -import { Joi, joiValidate } from "@staart/validate"; -import dns from "dns"; -import { verify } from "twt"; -import { Tokens } from "../interfaces/enum"; -import { ApiKeyResponse } from "./jwt"; - -/** - * Make s single property optional - * @source https://stackoverflow.com/a/54178819/1656944 - */ -export type PartialBy = Omit & Partial>; - -export const twtToId = (twt: string | number, userId?: string) => { - if (String(twt).length < 10 && twt !== "me") return parseInt(String(twt)); - return twt === "me" && userId - ? parseInt(verify(userId, config("twtSecret"), 10), 10) - : parseInt(verify(String(twt), config("twtSecret"), 10), 10); -}; - -/** - * Delete any sensitive information for a user like passwords and tokens - */ -export const deleteSensitiveInfoUser = (_user: users) => { - const user: PartialBy, "twoFactorSecret"> = { - ..._user, - }; - delete user.password; - delete user.twoFactorSecret; - return user as users; -}; - -/** Convert locals to ID */ -export const localsToTokenOrKey = (res: Response) => { - if (res.locals.token.sub == Tokens.API_KEY) { - return res.locals.token as ApiKeyResponse; - } - return twtToId(res.locals.token.id) as number; -}; - -/** Redirect a request to a URL */ -export const safeRedirect = (req: Request, res: Response, url: string) => { - if (req.get("X-Requested-With") === "XMLHttpRequest") - return res.json({ redirect: url }); - return res.redirect(url); -}; - -/** Get the authoriazation token from a request */ -export const getCodeFromRequest = (req: Request) => { - const code = - req.body.code || (req.get("Authorization") || "").replace("Bearer ", ""); - joiValidate({ code: Joi.string().required() }, { code }); - return code; -}; - -/** - * MySQL columns which are booleans - */ -export const boolValues = [ - "twoFactorEnabled", - "prefersReducedMotion", - "prefersColorSchemeDark", - "used", - "isVerified", - "forceTwoFactor", - "autoJoinDomain", - "onlyAllowDomain", - "isActive", - "checkLocationOnLogin", -]; - -/** - * MySQL columns which are datetime values - */ -export const dateValues = [ - "createdAt", - "updatedAt", - "lastFiredAt", - "expiresAt", -]; - -/** - * MySQL columns which are JSON values - */ -export const jsonValues = ["data"]; - -/** - * MySQL columns which are read-only - */ -export const readOnlyValues = [ - "createdAt", - "id", - "jwtApiKey", - "userId", - "groupId", -]; - -/** - * MySQL columns which are for int IDs - */ -export const IdValues = [ - "id", - "userId", - "groupId", - "prefersEmailId", - "apiKeyId", - "apiKeyGroupId", -]; - -/** Remove any falsy values an object */ -export const removeFalsyValues = (value: any) => { - if (value && typeof value === "object") { - Object.keys(value).map((key) => { - if (!value[key]) delete value[key]; - }); - } - return value; -}; - -/** Check if a value is part of a comma-separated list */ -export const includesDomainInCommaList = (commaList: string, value: string) => { - const list = commaList.split(",").map((item) => item.trim()); - let includes = false; - list.forEach((item) => { - if (item === value || isMatch(value, `*.${item}`)) includes = true; - }); - return includes; -}; - -/** Resolve a hostname and get its DNS records */ -export const dnsResolve = ( - hostname: string, - recordType: - | "A" - | "AAAA" - | "ANY" - | "CNAME" - | "MX" - | "NAPTR" - | "NS" - | "PTR" - | "SOA" - | "SRV" - | "TXT" -): Promise< - | Array - | Array - | Array - | dns.SoaRecord - | Array - | Array> - | Array -> => - new Promise((resolve, reject) => { - dns.resolve(hostname, recordType, (error, records) => { - if (error) return reject(error); - resolve(records); - }); - }); - -/** Convert query parameters to Prisma body */ -export const queryToParams = (req: Request) => { - if (typeof req.query === "object") { - const query: { [index: string]: string | string[] } = req.query as any; - const result: { - [index: string]: number | { [index: string]: string | boolean }; - } = {}; - if (typeof query.skip === "string") result.skip = parseInt(query.skip); - if (typeof query.take === "string") result.take = parseInt(query.take); - - query.select = query.select || []; - if (typeof query.select === "string") query.select = [query.select]; - const select: { [index: string]: boolean } = {}; - query.select.forEach((selectQuery) => (select[selectQuery] = true)); - if (Object.keys(select).length) result.select = select; - - query.include = query.include || []; - if (typeof query.include === "string") query.include = [query.include]; - const include: { [index: string]: boolean } = {}; - query.include.forEach((includeQuery) => (include[includeQuery] = true)); - if (Object.keys(include).length) result.include = include; - - query.orderBy = query.orderBy || []; - if (typeof query.orderBy === "string") query.orderBy = [query.orderBy]; - const orderBy: { [index: string]: string } = {}; - query.orderBy.forEach((orderByQuery) => { - if (orderByQuery.trim() && orderByQuery.includes(":")) { - const orderByArg = orderByQuery.split(":")[1]; - if (["asc", "desc"].includes(orderByArg)) - orderBy[orderByQuery.split(":")[0]] = orderByArg; - } - }); - if (Object.keys(orderBy).length) result.orderBy = orderBy; - - console.log(JSON.stringify(query), JSON.stringify(result)); - return result; - } - return {}; -}; diff --git a/src/_staart/helpers/webhooks.ts b/src/_staart/helpers/webhooks.ts deleted file mode 100644 index c61cafe6e..000000000 --- a/src/_staart/helpers/webhooks.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { logError } from "@staart/errors"; -import { redisQueue } from "@staart/redis"; -import axios from "axios"; -import { createHmac } from "crypto"; -import { Webhooks } from "../interfaces/enum"; -import { webhooks } from "@prisma/client"; -import { prisma } from "./prisma"; -import { config } from "@anandchowdhary/cosmic"; - -const JWT_ISSUER = config("jwtIssuer"); - -const WEBHOOK_QUEUE = `${config("redisQueuePrefix")}-webhooks`; - -let queueSetup = false; -/** Setup the webhook queue using Redis */ -const setupQueue = async () => { - if (queueSetup) return true; - const queues = redisQueue.listQueuesAsync(); - if ((await queues).includes(WEBHOOK_QUEUE)) return (queueSetup = true); - await redisQueue.createQueueAsync({ qname: WEBHOOK_QUEUE }); - return (queueSetup = true); -}; - -/** Queue a webhook for a group */ -export const queueWebhook = ( - groupId: number, - webhook: Webhooks, - data?: any -) => { - setupQueue() - .then(() => - redisQueue.sendMessageAsync({ - qname: WEBHOOK_QUEUE, - message: JSON.stringify({ - groupId, - webhook, - data, - tryNumber: 1, - }), - }) - ) - .then(() => {}) - .catch(() => logError("Webhook queue", "Unable to queue webhook")); -}; - -/** Receive a webhook from a message and call the webhook */ -export const receiveWebhookMessage = async () => { - await setupQueue(); - const result = await redisQueue.receiveMessageAsync({ - qname: WEBHOOK_QUEUE, - }); - if ("id" in result) { - const { - groupId, - webhook, - data, - tryNumber, - }: { - tryNumber: number; - groupId: string; - webhook: Webhooks; - data?: any; - } = JSON.parse(result.message); - if (tryNumber && tryNumber > 3) { - logError("Webhook", `Unable to fire: ${groupId} ${webhook}`); - return redisQueue.deleteMessageAsync({ - qname: WEBHOOK_QUEUE, - id: result.id, - }); - } - try { - safeFireWebhook(groupId, webhook, data); - } catch (error) { - await redisQueue.sendMessageAsync({ - qname: WEBHOOK_QUEUE, - message: JSON.stringify({ - groupId, - webhook, - data, - tryNumber: tryNumber + 1, - }), - }); - } - await redisQueue.deleteMessageAsync({ - qname: WEBHOOK_QUEUE, - id: result.id, - }); - receiveWebhookMessage(); - } -}; - -/** Fire a webhook suppressing errors */ -const safeFireWebhook = async ( - groupId: string, - webhook: Webhooks, - data?: any -) => { - const webhooksToFire = await prisma.webhooks.findMany({ - where: { groupId: parseInt(groupId), event: webhook }, - }); - for await (const hook of webhooksToFire) { - try { - await fireSingleWebhook(hook, webhook, data); - } catch (error) {} - } - return; -}; - -/** Fire a single webhook */ -export const fireSingleWebhook = async ( - webhook: webhooks, - hookType: Webhooks, - data?: any -) => { - let secret; - if (webhook.secret) - secret = createHmac("sha1", webhook.secret) - .update(data || "") - .digest("hex"); - const options = { - headers: { - "User-Agent": `${JWT_ISSUER}-webhook-service`, - "X-Signature": secret, - "Content-Type": webhook.contentType, - }, - data: { - hookType, - data, - }, - }; - const result = await axios.post(webhook.url, options); - if (webhook.id) - await prisma.webhooks.update({ - where: { id: webhook.id }, - data: { lastFiredAt: new Date() }, - }); - return result; -}; diff --git a/src/_staart/interfaces/enum.ts b/src/_staart/interfaces/enum.ts deleted file mode 100644 index 0f50ff544..000000000 --- a/src/_staart/interfaces/enum.ts +++ /dev/null @@ -1,75 +0,0 @@ -export enum EventType { - USER_CREATED = "user.created", - USER_UPDATED = "user.updated", - USER_DELETED = "user.deleted", - AUTH_REFRESH = "auth.refresh", - AUTH_LOGIN = "auth.login", - AUTH_LOGIN_OAUTH = "auth.login_oauth", - AUTH_LOGIN_BACKUP_CODE = "auth.login_backupCode", - AUTH_LOGIN_GOOGLE = "auth.login_google", - AUTH_PASSWORD_CHANGED = "auth.password_changed", - AUTH_PASSWORD_RESET_REQUESTED = "auth.passwordReset", - AUTH_APPROVE_LOCATION = "auth.approveLocation", - ORGANIZATION_CREATED = "group.created", - ORGANIZATION_UPDATED = "group.updated", - ORGANIZATION_DELETED = "group.deleted", - EMAIL_CREATED = "email.created", - EMAIL_UPDATED = "email.updated", - EMAIL_DELETED = "email.deleted", - EMAIL_VERIFIED = "email.verified", - MEMBERSHIP_CREATED = "membership.created", - MEMBERSHIP_UPDATED = "membership.updated", - MEMBERSHIP_DELETED = "membership.deleted", - BILLING_UPDATED = "billing.updated", - API_KEY_CREATED = "apiKey.created", - API_KEY_UPDATED = "apiKey.updated", - API_KEY_DELETED = "apiKey.deleted", -} - -export enum Templates { - EMAIL_VERIFY = "email-verify", - PASSWORD_RESET = "password-reset", - NEW_PASSWORD = "new-password", - INVITED_TO_TEAM = "invited", - UNAPPROVED_LOCATION = "unapproved-location", - CREDITS_NEW_USER = "credits-new-user", - CREDITS_INVITED_BY = "credits-invited-by", - LOGIN_LINK = "login-link", -} - -export enum Tokens { - LOGIN = "auth", - LOGIN_LINK = "login-link", - API_KEY = "api-key", - ACCESS_TOKEN = "access-token", - TWO_FACTOR = "2fa", - REFRESH = "refresh", - PASSWORD_RESET = "password-reset", - EMAIL_VERIFY = "email-verify", - EMAIL_RESEND = "email-resend", - APPROVE_LOCATION = "approve-location", - COUPON = "coupon", -} - -export enum Webhooks { - ALL_EVENTS = "*", - UPDATE_ORGANIZATION = "update-group", - DELETE_ORGANIZATION = "delete-group", - UPDATE_ORGANIZATION_BILLING = "update-group-billing", - UPDATE_ORGANIZATION_SUBSCRIPTION = "update-group-subscription", - CREATE_ORGANIZATION_SUBSCRIPTION = "create-group-subscription", - DELETE_ORGANIZATION_SOURCE = "delete-group-source", - UPDATE_ORGANIZATION_SOURCE = "update-group-source", - CREATE_ORGANIZATION_SOURCE = "create-group-source", - UPDATE_API_KEY = "update-api-key", - CREATE_API_KEY = "create-api-key", - DELETE_API_KEY = "delete-api-key", - UPDATE_DOMAIN = "update-domain", - CREATE_DOMAIN = "create-domain", - DELETE_DOMAIN = "delete-domain", - VERIFY_DOMAIN = "verify-domain", - TEST_WEBHOOK = "test-webhook", - UPDATE_WEBHOOK = "update-webhook", - CREATE_WEBHOOK = "create-webhook", - DELETE_WEBHOOK = "delete-webhook", -} diff --git a/src/_staart/interfaces/general.ts b/src/_staart/interfaces/general.ts deleted file mode 100644 index c1bbfcd72..000000000 --- a/src/_staart/interfaces/general.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Stripe from "stripe"; - -export interface KeyValue { - [index: string]: any; -} - -export interface HTTPError { - status: number; - code: string; - message?: string; -} - -export interface Locals { - userAgent: string; - ipAddress: string; - referrer?: string; -} - -export interface StripeLocals extends Locals { - stripeEvent: Stripe.Event; -} - -export interface Row { - createdAt?: Date; - updatedAt?: Date; -} - -export interface IdRow extends Row { - id?: string; -} - -export interface Event { - date?: Date; - ipAddress?: string; - userAgent?: string; - groupId?: number | string; - userId?: number | string; - type?: string; - data?: any; -} diff --git a/src/_staart/rest/admin.ts b/src/_staart/rest/admin.ts deleted file mode 100644 index 5effef303..000000000 --- a/src/_staart/rest/admin.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { couponCodesUpdateInput } from "@prisma/client"; -import { - cleanElasticSearchQueryResponse, - elasticSearch, -} from "@staart/elasticsearch"; -import { INSUFFICIENT_PERMISSION } from "@staart/errors"; -import { getEvents } from "@staart/payments"; -import { ms, randomString } from "@staart/text"; -import { ScopesAdmin } from "../config"; -import { Acts, can } from "../helpers/authorization"; -import { couponCodeJwt } from "../helpers/jwt"; -import { - paginatedResult, - prisma, - queryParamsToSelect, -} from "../helpers/prisma"; - -const ELASTIC_LOGS_INDEX = config("elasticLogsIndex"); - -export const getAllGroupForUser = async ( - tokenUserId: number, - queryParams: any -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.GROUPS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.groups.findMany(queryParamsToSelect(queryParams)), - { take: queryParams.take } - ); -}; - -export const getAllUsersForUser = async ( - tokenUserId: number, - queryParams: any -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.USERS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.users.findMany(queryParamsToSelect(queryParams)), - { take: queryParams.take } - ); -}; - -export const getAllCouponsForUser = async ( - tokenUserId: number, - queryParams: any -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.COUPONS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.couponCodes.findMany(queryParamsToSelect(queryParams)), - { take: queryParams.take } - ); -}; - -export const getCouponForUser = async ( - tokenUserId: number, - couponId: string -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.COUPONS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.couponCodes.findOne({ where: { id: parseInt(couponId) } }); -}; - -export const updateCouponForUser = async ( - tokenUserId: number, - couponId: string, - data: couponCodesUpdateInput -) => { - if (!(await can(tokenUserId, Acts.WRITE, ScopesAdmin.COUPONS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.couponCodes.update({ - data, - where: { id: parseInt(couponId) }, - }); -}; - -export const deleteCouponForUser = async ( - tokenUserId: number, - couponId: string -) => { - if (!(await can(tokenUserId, Acts.WRITE, ScopesAdmin.COUPONS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.couponCodes.delete({ where: { id: parseInt(couponId) } }); -}; - -export const generateCouponForUser = async (tokenUserId: number, body: any) => { - if (!(await can(tokenUserId, Acts.WRITE, ScopesAdmin.COUPONS))) - throw new Error(INSUFFICIENT_PERMISSION); - - if (body.jwt) - return couponCodeJwt(body.amount, body.currency, body.description); - delete body.jwt; - body.code = - body.code || randomString({ length: 10, type: "distinguishable" }); - return prisma.couponCodes.create({ - data: body, - }); -}; - -export const getPaymentEventsForUser = async ( - tokenUserId: number, - body: any -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.PAYMENT_EVENTS))) - throw new Error(INSUFFICIENT_PERMISSION); - - return getEvents(body); -}; - -/** - * Get an API key - */ -export const getServerLogsForUser = async ( - tokenUserId: number, - query: { - range?: string; - from?: string; - } -) => { - if (!(await can(tokenUserId, Acts.READ, ScopesAdmin.SERVER_LOGS))) - throw new Error(INSUFFICIENT_PERMISSION); - - const range: string = query.range || "7d"; - const from = query.from ? parseInt(query.from) : 0; - const result = await elasticSearch.search({ - index: ELASTIC_LOGS_INDEX, - from, - body: { - query: { - bool: { - must: [ - { - range: { - date: { - gte: new Date(new Date().getTime() - ms(range)), - }, - }, - }, - ], - }, - }, - sort: [ - { - date: { order: "desc" }, - }, - ], - size: 10, - }, - }); - return cleanElasticSearchQueryResponse(result.body, 10); -}; diff --git a/src/_staart/rest/auth.ts b/src/_staart/rest/auth.ts deleted file mode 100644 index 006b63584..000000000 --- a/src/_staart/rest/auth.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { - backupCodes, - MembershipRole, - users, - usersCreateInput, -} from "@prisma/client"; -import { checkIfDisposableEmail } from "@staart/disposable-email"; -import { - EMAIL_EXISTS, - INSUFFICIENT_PERMISSION, - INVALID_2FA_TOKEN, - INVALID_LOGIN, - NOT_ENABLED_2FA, - RESOURCE_NOT_FOUND, - USER_NOT_FOUND, -} from "@staart/errors"; -import { compare, hash } from "@staart/text"; -import { authenticator } from "otplib"; -import { ScopesAdmin } from "../config"; -import { Acts, can } from "../helpers/authorization"; -import { deleteItemFromCache } from "../helpers/cache"; -import { - checkInvalidatedToken, - getLoginResponse, - loginLinkToken, - passwordResetToken, - postLoginTokens, - resendEmailVerificationToken, - TokenResponse, - verifyToken, -} from "../helpers/jwt"; -import { mail } from "../helpers/mail"; -import { prisma } from "../helpers/prisma"; -import { trackEvent } from "../helpers/tracking"; -import { EventType, Templates, Tokens } from "../interfaces/enum"; -import { Locals } from "../interfaces/general"; -import { getDomainByDomainName } from "../services/group.service"; -import { - addApprovedLocation, - createEmail, - createUser, - getUserByEmail, - getUserById, - resendEmailVerification, -} from "../services/user.service"; - -const ALLOW_DISPOSABLE_EMAILS = config("allowDisposableEmails"); - -export const validateRefreshToken = async ( - token: string, - locals: Locals | any -) => { - await checkInvalidatedToken(token); - const data = await verifyToken<{ id: number }>(token, Tokens.REFRESH); - if (!data.id) throw new Error(USER_NOT_FOUND); - const user = await getUserById(data.id); - if (!user) throw new Error(USER_NOT_FOUND); - return postLoginTokens(user, locals, token); -}; - -export const invalidateRefreshToken = async ( - token: string, - locals: Locals | any -) => { - const data = await verifyToken<{ id: number }>(token, Tokens.REFRESH); - if (!data.id) throw new Error(USER_NOT_FOUND); - await prisma.sessions.deleteMany({ - where: { token, userId: data.id }, - }); - return; -}; - -export const login = async ( - email: string, - password: string, - locals: Locals | any -) => { - let user: users; - try { - user = await getUserByEmail(email, true); - } catch (error) { - const hasUserWithUnverifiedEmail = - (await prisma.users.count({ - where: { - emails: { - some: { - email, - isVerified: false, - }, - }, - }, - })) !== 0; - if (hasUserWithUnverifiedEmail) throw new Error("401/unverified-email"); - throw new Error(USER_NOT_FOUND); - } - if (!user.password) { - await mail({ - template: Templates.LOGIN_LINK, - data: { ...user, token: await loginLinkToken(user) }, - to: email, - }); - return { success: true, message: "login-link-sent" }; - } - const isPasswordCorrect = await compare(password, user.password); - if (isPasswordCorrect) - return getLoginResponse(user, EventType.AUTH_LOGIN, "local", locals); - throw new Error(INVALID_LOGIN); -}; - -export const login2FA = async ( - code: number, - token: string, - locals: Locals | any -) => { - const data = await verifyToken<{ id: number }>(token, Tokens.TWO_FACTOR); - const user = await getUserById(data.id); - if (!user) throw new Error(USER_NOT_FOUND); - const secret = user.twoFactorSecret; - if (!secret) throw new Error(NOT_ENABLED_2FA); - if (authenticator.check(code.toString(), secret)) - return postLoginTokens(user, locals); - const allBackupCodes = await prisma.backupCodes.findMany({ - where: { userId: user.id }, - }); - let usedBackupCode: backupCodes | undefined = undefined; - for await (const backupCode of allBackupCodes) - if (await compare(backupCode.code, code.toString())) - usedBackupCode = backupCode; - if (usedBackupCode && !usedBackupCode.isUsed) { - await prisma.backupCodes.update({ - where: { id: usedBackupCode.id }, - data: { isUsed: true }, - }); - return postLoginTokens(user, locals); - } - throw new Error(INVALID_2FA_TOKEN); -}; - -export const register = async ( - user: usersCreateInput, - locals?: Locals | any, - email?: string, - groupId?: number, - role?: MembershipRole, - emailVerified = false -) => { - if (!config("newUserRegistrations")) - throw new Error("User registrations are not enabled"); - if (config("newUserRegistrationDomains")) { - const domains = config("newUserRegistrationDomains"); - if (!domains.includes(email?.split("@")[1] ?? "")) - throw new Error("This domain is not allowed"); - } - if (email) { - const isNewEmail = - (await prisma.emails.findMany({ where: { email, isVerified: true } })) - .length === 0; - if (!isNewEmail) throw new Error(EMAIL_EXISTS); - if (!ALLOW_DISPOSABLE_EMAILS) checkIfDisposableEmail(email); - } - if (!groupId && email) { - let domain = ""; - try { - domain = email.split("@")[1]; - const domainDetails = await getDomainByDomainName(domain); - groupId = domainDetails.groupId; - } catch (error) {} - } - const userId = (await createUser(user, locals)).id; - if (groupId) { - await prisma.memberships.create({ - data: { - user: { connect: { id: userId } }, - group: { connect: { id: groupId } }, - role, - }, - }); - } - let resendToken: string | undefined = undefined; - if (email) { - const newEmail = await createEmail(userId, email, !emailVerified); - await prisma.users.update({ - where: { id: userId }, - data: { prefersEmail: { connect: { id: newEmail.id } } }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - resendToken = await resendEmailVerificationToken(newEmail.id); - } - if (locals) await addApprovedLocation(userId, locals.ipAddress); - return { userId, resendToken }; -}; - -export const sendPasswordReset = async ( - email: string, - locals?: Locals | any -) => { - const user = await getUserByEmail(email); - const token = await passwordResetToken(user.id); - await mail({ - to: email, - template: Templates.PASSWORD_RESET, - data: { name: user.name, token }, - }); - if (locals) - trackEvent( - { - userId: user.id, - type: EventType.AUTH_PASSWORD_RESET_REQUESTED, - data: { token }, - }, - locals - ); - return; -}; - -export const sendNewPassword = async (userId: number, email: string) => { - const user = await prisma.users.findOne({ - where: { id: userId }, - include: { emails: true }, - }); - if (!user) throw new Error(USER_NOT_FOUND); - if (!user.emails.filter((userEmail) => userEmail.email === email).length) - throw new Error(RESOURCE_NOT_FOUND); - const token = await passwordResetToken(user.id); - await mail({ - to: email, - template: Templates.NEW_PASSWORD, - data: { name: user.name, token }, - }); - return; -}; - -export const verifyEmail = async (token: string, locals: Locals | any) => { - const emailId = ( - await verifyToken<{ id: number }>(token, Tokens.EMAIL_VERIFY) - ).id; - const email = await prisma.emails.findOne({ - where: { id: emailId }, - }); - if (!email) throw new Error(RESOURCE_NOT_FOUND); - trackEvent( - { - userId: email.userId, - type: EventType.EMAIL_VERIFIED, - data: { id: emailId }, - }, - locals - ); - return prisma.emails.update({ - where: { id: emailId }, - data: { isVerified: true }, - }); -}; - -export const loginLink = async (token: string, locals: Locals | any) => { - const userId = (await verifyToken<{ id: number }>(token, Tokens.LOGIN_LINK)) - .id; - const user = await prisma.users.findOne({ - where: { id: userId }, - }); - if (!user) throw new Error(RESOURCE_NOT_FOUND); - trackEvent( - { - userId, - type: EventType.AUTH_LOGIN, - data: { id: userId }, - }, - locals - ); - return postLoginTokens(user, locals); -}; - -export const updatePassword = async ( - token: string, - password: string, - locals: Locals | any -) => { - const userId = ( - await verifyToken<{ id: number }>(token, Tokens.PASSWORD_RESET) - ).id; - await prisma.users.update({ - where: { id: userId }, - data: { password: await hash(password, 8) }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - trackEvent( - { - userId, - type: EventType.AUTH_PASSWORD_CHANGED, - }, - locals - ); - return; -}; - -export const impersonate = async ( - tokenUserId: number, - impersonateUserId: number, - locals: Locals | any -) => { - if (!(await can(tokenUserId, Acts.WRITE, ScopesAdmin.USERS))) - throw new Error(INSUFFICIENT_PERMISSION); - - const user = await getUserById(impersonateUserId); - if (user) - return getLoginResponse(user, EventType.AUTH_LOGIN, "impersonate", locals); - throw new Error(USER_NOT_FOUND); -}; - -export const approveLocation = async (token: string, locals: Locals | any) => { - const tokenUser = await verifyToken( - token, - Tokens.APPROVE_LOCATION - ); - if (!tokenUser.id) throw new Error(USER_NOT_FOUND); - const user = await getUserById(tokenUser.id); - if (!user) throw new Error(USER_NOT_FOUND); - const ipAddress = tokenUser.ipAddress || locals.ipAddress; - await addApprovedLocation(user.id, ipAddress); - trackEvent( - { - userId: tokenUser.id, - type: EventType.AUTH_APPROVE_LOCATION, - }, - locals - ); - return getLoginResponse( - user, - EventType.AUTH_APPROVE_LOCATION, - ipAddress, - locals - ); -}; - -export const resendEmailVerificationWithToken = async (token: string) => { - const data = await verifyToken<{ id: number }>(token, Tokens.EMAIL_RESEND); - if (!data.id) throw new Error(USER_NOT_FOUND); - return resendEmailVerification(data.id); -}; diff --git a/src/_staart/rest/group.ts b/src/_staart/rest/group.ts deleted file mode 100644 index d6bc97c12..000000000 --- a/src/_staart/rest/group.ts +++ /dev/null @@ -1,1406 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { - apiKeysCreateInput, - apiKeysUpdateInput, - domainsCreateInput, - domainsUpdateInput, - groupsCreateInput, - groupsUpdateInput, - MembershipRole, - membershipsUpdateInput, - users, - webhooksCreateInput, - webhooksUpdateInput, -} from "@prisma/client"; -import { - CANNOT_DELETE_SOLE_MEMBER, - CANNOT_INVITE_DOMAIN, - DOMAIN_ALREADY_VERIFIED, - DOMAIN_MISSING_DNS, - DOMAIN_MISSING_FILE, - DOMAIN_UNABLE_TO_VERIFY, - INSUFFICIENT_PERMISSION, - INVALID_INPUT, - MEMBERSHIP_NOT_FOUND, - ORGANIZATION_NOT_FOUND, - RESOURCE_NOT_FOUND, - STRIPE_NO_CUSTOMER, - USER_IS_MEMBER_ALREADY, -} from "@staart/errors"; -import { - createCustomer, - createCustomerBalanceTransaction, - createSource, - createSubscription, - deleteCustomer, - deleteSource, - getCustomBalanceTransaction, - getCustomBalanceTransactions, - getCustomer, - getInvoice, - getInvoices, - getProductPricing, - getSource, - getSources, - getSubscription, - getSubscriptions, - updateCustomer, - updateSource, - updateSubscription, -} from "@staart/payments"; -import { randomString } from "@staart/text"; -import axios from "axios"; -import { ScopesGroup, ScopesUser } from "../config"; -import { Acts, can } from "../helpers/authorization"; -import { deleteItemFromCache } from "../helpers/cache"; -import { - ApiKeyResponse, - checkInvalidatedToken, - invalidateToken, - verifyToken, -} from "../helpers/jwt"; -import { mail } from "../helpers/mail"; -import { - paginatedResult, - prisma, - queryParamsToSelect, -} from "../helpers/prisma"; -import { trackEvent } from "../helpers/tracking"; -import { dnsResolve } from "../helpers/utils"; -import { fireSingleWebhook, queueWebhook } from "../helpers/webhooks"; -import { Templates, Tokens, Webhooks } from "../interfaces/enum"; -import { KeyValue, Locals } from "../interfaces/general"; -import { - checkDomainAvailability, - createGroup, - getApiKeyLogs, - getDomainByDomainName, - getGroupById, -} from "../services/group.service"; -import { getUserById } from "../services/user.service"; -import { register } from "./auth"; - -const JWT_ISSUER = config("jwtIssuer"); - -export const getGroupForUser = async ( - userId: number | ApiKeyResponse, - groupId: number -) => { - if ( - !(await can(userId, `${Acts.WRITE}${ScopesGroup.INFO}`, `group-${groupId}`)) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return getGroupById(groupId); -}; - -export const newGroupForUser = async ( - userId: number, - group: groupsCreateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesUser.MEMBERSHIPS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - if (!(group.name || "").trim()) { - const user = await getUserById(userId); - group.name = user.name; - } - return createGroup(group, userId); -}; - -export const updateGroupForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - data: groupsUpdateInput, - locals: Locals | any -) => { - if ( - !(await can(userId, `${Acts.WRITE}${ScopesGroup.INFO}`, `group-${groupId}`)) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.groups.update({ - where: { - id: groupId, - }, - data, - }); - queueWebhook(groupId, Webhooks.UPDATE_ORGANIZATION, data); - trackEvent({ groupId, type: Webhooks.UPDATE_ORGANIZATION }, locals); - return result; -}; - -export const deleteGroupForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - locals: Locals | any -) => { - if (!(await can(userId, Acts.DELETE, `group-${groupId}`))) - throw new Error(INSUFFICIENT_PERMISSION); - - const groupDetails = await getGroupById(groupId); - await deleteItemFromCache(`cache_getGroupById_${groupDetails.id}`); - if ( - typeof groupDetails.attributes === "object" && - !Array.isArray(groupDetails.attributes) && - groupDetails.attributes?.stripeCustomer === "string" - ) - await deleteCustomer(groupDetails.attributes?.stripeCustomer); - await prisma.groups.delete({ - where: { - id: groupId, - }, - }); - queueWebhook(groupId, Webhooks.DELETE_ORGANIZATION); - trackEvent({ groupId, type: Webhooks.DELETE_ORGANIZATION }, locals); - return; -}; - -export const getGroupBillingForUser = async ( - userId: number | ApiKeyResponse, - groupId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.BILLING}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getCustomer(group.attributes?.stripeCustomer); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const updateGroupBillingForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - data: any, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.BILLING}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - let result; - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - result = await updateCustomer(group.attributes?.stripeCustomer, data); - } else { - result = await createCustomer( - groupId, - data, - async (groupId: number, data: { stripeCustomerId: string }) => { - const attributes = - typeof group.attributes === "object" ? group.attributes : {}; - return prisma.groups.update({ - where: { id: groupId }, - data: { - attributes: { - ...attributes, - stripeCustomer: data.stripeCustomerId, - }, - }, - }); - } - ); - console.log(result); - } - queueWebhook(groupId, Webhooks.UPDATE_ORGANIZATION_BILLING, data); - trackEvent({ groupId, type: Webhooks.UPDATE_ORGANIZATION_BILLING }, locals); - return result; -}; - -export const getGroupInvoicesForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - params: KeyValue -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.INVOICES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getInvoices(group.attributes?.stripeCustomer, params); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupInvoiceForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - invoiceId: string -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.INVOICES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getInvoice(group.attributes?.stripeCustomer, invoiceId); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupSourcesForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - params: KeyValue -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.SOURCES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getSources(group.attributes?.stripeCustomer, params); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupSourceForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - sourceId: string -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.SOURCES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getSource(group.attributes?.stripeCustomer, sourceId); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupSubscriptionsForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - params: KeyValue -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.SUBSCRIPTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getSubscriptions(group.attributes?.stripeCustomer, params); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupSubscriptionForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - subscriptionId: string -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.SUBSCRIPTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getSubscription(group.attributes?.stripeCustomer, subscriptionId); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const updateGroupSubscriptionForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - subscriptionId: string, - data: KeyValue, - locals?: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.SUBSCRIPTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await updateSubscription( - group.attributes?.stripeCustomer, - subscriptionId, - data - ); - queueWebhook(groupId, Webhooks.UPDATE_ORGANIZATION_SUBSCRIPTION, data); - trackEvent( - { groupId, type: Webhooks.UPDATE_ORGANIZATION_SUBSCRIPTION }, - locals - ); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const createGroupSubscriptionForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - params: { plan: string; [index: string]: any }, - locals?: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.SUBSCRIPTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await createSubscription( - group.attributes?.stripeCustomer, - params - ); - queueWebhook(groupId, Webhooks.CREATE_ORGANIZATION_SUBSCRIPTION, params); - trackEvent( - { groupId, type: Webhooks.CREATE_ORGANIZATION_SUBSCRIPTION }, - locals - ); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupPricingPlansForUser = async ( - userId: number | ApiKeyResponse, - groupId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.BILLING}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return getProductPricing(); -}; - -export const deleteGroupSourceForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - sourceId: string, - locals?: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.SOURCES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await deleteSource( - group.attributes?.stripeCustomer, - sourceId - ); - queueWebhook(groupId, Webhooks.DELETE_ORGANIZATION_SOURCE, sourceId); - trackEvent({ groupId, type: Webhooks.DELETE_ORGANIZATION_SOURCE }, locals); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const updateGroupSourceForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - sourceId: string, - data: any, - locals?: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.SOURCES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await updateSource( - group.attributes?.stripeCustomer, - sourceId, - data - ); - queueWebhook(groupId, Webhooks.UPDATE_ORGANIZATION_SOURCE, data); - trackEvent({ groupId, type: Webhooks.UPDATE_ORGANIZATION_SOURCE }, locals); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const createGroupSourceForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - card: any, - locals?: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.SOURCES}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await createSource(group.attributes?.stripeCustomer, card); - queueWebhook(groupId, Webhooks.CREATE_ORGANIZATION_SOURCE, card); - trackEvent({ groupId, type: Webhooks.CREATE_ORGANIZATION_SOURCE }, locals); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getAllGroupDataForUser = async ( - userId: number | ApiKeyResponse, - groupId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.SECURITY}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await prisma.groups.findOne({ - where: { - id: groupId, - }, - include: { - apiKeys: true, - domains: true, - memberships: true, - webhooks: true, - }, - }); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - return { - ...group, - ...(typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - typeof group.attributes?.stripeCustomer === "string" - ? { - billing: await getCustomer(group.attributes?.stripeCustomer), - subscriptions: await getSubscriptions( - group.attributes?.stripeCustomer, - {} - ), - invoices: await getInvoices(group.attributes?.stripeCustomer, {}), - sources: await getSources(group.attributes?.stripeCustomer, {}), - } - : {}), - }; -}; - -export const getGroupMembershipsForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - queryParams: any -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.MEMBERSHIPS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.memberships.findMany({ - where: { groupId: groupId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getGroupMembershipForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - membershipId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.MEMBERSHIPS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.memberships.findOne({ - where: { id: membershipId }, - include: { user: true }, - }); -}; - -export const updateGroupMembershipForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - membershipId: number, - data: membershipsUpdateInput -) => { - if (!(await can(userId, Acts.WRITE, `membership-${membershipId}`))) - throw new Error(INSUFFICIENT_PERMISSION); - - if (data.role) { - const currentMembership = await prisma.memberships.findOne({ - where: { id: membershipId }, - }); - if (!currentMembership) throw new Error(MEMBERSHIP_NOT_FOUND); - if (currentMembership.role === "OWNER" && data.role !== "OWNER") { - const members = await prisma.memberships.findMany({ - where: { groupId: groupId, role: "OWNER" }, - }); - if (members.length === 1) throw new Error(CANNOT_DELETE_SOLE_MEMBER); - } - } - return prisma.memberships.update({ - where: { id: membershipId }, - data, - }); -}; - -/** - * Delete an group membership for user - * If an group has only one member, the user, - * Delete the entire group, not just the membership - */ -export const deleteGroupMembershipForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - membershipId: number, - locals: Locals | any -) => { - if (!(await can(userId, Acts.DELETE, `membership-${membershipId}`))) - throw new Error(INSUFFICIENT_PERMISSION); - - const members = await prisma.memberships.findMany({ - where: { groupId: groupId }, - }); - if (members.length === 1) return deleteGroupForUser(userId, groupId, locals); - return prisma.memberships.delete({ where: { id: membershipId } }); -}; - -export const inviteMemberToGroup = async ( - userId: number | ApiKeyResponse, - groupId: number, - newMemberName: string, - newMemberEmail: string, - role: MembershipRole, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.MEMBERSHIPS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - - /** - * Only users with emails on verified domain can join this group - * Make sure that the provided email ends with the domain - */ - if (group.onlyAllowDomain) { - const emailDomain = newMemberEmail.split("@")[1]; - try { - const domainDetails = await getDomainByDomainName(emailDomain); - if (domainDetails.groupId !== groupId) throw new Error(); - } catch (error) { - throw new Error(CANNOT_INVITE_DOMAIN); - } - } - let newUser: users | undefined = undefined; - let userExists = false; - let createdUserId: number; - - /** - * Check if a user with the email already exists - */ - const checkUser = await prisma.users.findMany({ - where: { emails: { some: { email: newMemberEmail, isVerified: true } } }, - take: 1, - }); - if (checkUser.length) { - newUser = checkUser[0]; - userExists = true; - } - - if (userExists && newUser) { - const isMemberAlready = - ( - await prisma.memberships.findMany({ - where: { - userId: newUser.id, - groupId: groupId, - }, - }) - ).length !== 0; - createdUserId = newUser.id; - if (isMemberAlready) throw new Error(USER_IS_MEMBER_ALREADY); - - await prisma.memberships.create({ - data: { - user: { connect: { id: newUser.id } }, - group: { connect: { id: groupId } }, - role, - }, - }); - } else { - const newAccount = await register( - { - name: newMemberName, - }, - locals, - newMemberEmail, - groupId, - role - ); - createdUserId = newAccount.userId; - } - if (createdUserId) { - const inviter = - typeof userId !== "object" - ? (await getUserById(userId))?.name ?? "Someone" - : "Someone"; - const userDetails = await getUserById(createdUserId); - mail({ - to: newMemberEmail, - template: Templates.INVITED_TO_TEAM, - data: { - ...userDetails, - team: group.name, - inviter, - }, - }) - .then(() => {}) - .catch(() => {}); - } - return; -}; - -export const getGroupApiKeysForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - queryParams: any -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.apiKeys.findMany({ - where: { groupId: groupId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getGroupApiKeyForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - apiKeyId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.apiKeys.findOne({ where: { id: apiKeyId } }); -}; - -export const getGroupApiKeyLogsForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - apiKeyId: number, - query: { - range?: string; - from?: string; - } -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.API_KEY_LOGS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return getApiKeyLogs(apiKeyId, query); -}; - -export const updateApiKeyForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - apiKeyId: number, - data: apiKeysUpdateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.apiKeys.update({ - where: { id: apiKeyId }, - data, - }); - queueWebhook(groupId, Webhooks.UPDATE_API_KEY, data); - trackEvent({ groupId, type: Webhooks.UPDATE_API_KEY }, locals); - return result; -}; - -export const createApiKeyForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - apiKey: apiKeysCreateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - apiKey.apiKey = randomString({ length: 32 }); - const result = await prisma.apiKeys.create({ - data: { - ...apiKey, - group: { - connect: { - id: groupId, - }, - }, - }, - }); - queueWebhook(groupId, Webhooks.CREATE_API_KEY, apiKey); - trackEvent({ groupId, type: Webhooks.CREATE_API_KEY }, locals); - return result; -}; - -export const deleteApiKeyForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - apiKeyId: number, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.apiKeys.delete({ - where: { id: apiKeyId }, - }); - queueWebhook(groupId, Webhooks.DELETE_API_KEY, apiKeyId); - trackEvent({ groupId, type: Webhooks.DELETE_API_KEY }, locals); - return result; -}; - -export const getGroupDomainsForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - queryParams: any -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.domains.findMany({ - where: { groupId: groupId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getGroupDomainForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - domainId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.domains.findOne({ where: { id: domainId } }); -}; - -export const updateDomainForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - domainId: number, - data: domainsUpdateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.domains.update({ - where: { id: domainId }, - data, - }); - queueWebhook(groupId, Webhooks.UPDATE_DOMAIN, data); - trackEvent({ groupId, type: Webhooks.UPDATE_DOMAIN }, locals); - return result; -}; - -export const createDomainForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - domain: domainsCreateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - await checkDomainAvailability(domain.domain); - const result = await prisma.domains.create({ - data: { - ...domain, - verificationCode: await randomString({ length: 25 }), - isVerified: false, - group: { - connect: { - id: groupId, - }, - }, - }, - }); - queueWebhook(groupId, Webhooks.CREATE_DOMAIN, domain); - trackEvent({ groupId, type: Webhooks.CREATE_DOMAIN }, locals); - return result; -}; - -export const deleteDomainForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - domainId: number, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.domains.delete({ - where: { id: domainId }, - }); - queueWebhook(groupId, Webhooks.DELETE_DOMAIN, domainId); - trackEvent({ groupId, type: Webhooks.DELETE_DOMAIN }, locals); - return result; -}; - -export const verifyDomainForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - domainId: number, - method: "dns" | "file", - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.DOMAINS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const domain = await prisma.domains.findOne({ - where: { id: domainId }, - }); - if (!domain) throw new Error(RESOURCE_NOT_FOUND); - if (domain.isVerified) throw new Error(DOMAIN_ALREADY_VERIFIED); - if (!domain.verificationCode) throw new Error(DOMAIN_UNABLE_TO_VERIFY); - if (method === "file") { - try { - const file: string = ( - await axios.get( - `http://${domain.domain}/.well-known/${JWT_ISSUER}-verify.txt` - ) - ).data; - if (file.replace(/\r?\n|\r/g, "").trim() === domain.verificationCode) { - const result = await prisma.domains.update({ - where: { id: domainId }, - data: { isVerified: true }, - }); - queueWebhook(groupId, Webhooks.VERIFY_DOMAIN, { - domainId, - method, - }); - trackEvent({ groupId, type: Webhooks.VERIFY_DOMAIN }, locals); - return result; - } - } catch (error) { - throw new Error(DOMAIN_MISSING_FILE); - } - } else { - const dns = await dnsResolve(domain.domain, "TXT"); - if (JSON.stringify(dns).includes(domain.verificationCode)) { - const result = await prisma.domains.update({ - where: { id: domainId }, - data: { isVerified: true }, - }); - queueWebhook(groupId, Webhooks.VERIFY_DOMAIN, { - domainId, - method, - }); - trackEvent({ groupId, type: Webhooks.VERIFY_DOMAIN }, locals); - return result; - } else { - throw new Error(DOMAIN_MISSING_DNS); - } - } - throw new Error(DOMAIN_UNABLE_TO_VERIFY); -}; - -export const getGroupWebhooksForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - queryParams: any -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.WEBHOOKS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.webhooks.findMany({ - where: { groupId: groupId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getGroupWebhookForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - webhookId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.WEBHOOKS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.webhooks.findOne({ where: { id: webhookId } }); -}; - -export const updateWebhookForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - webhookId: number, - data: webhooksUpdateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.WEBHOOKS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.webhooks.update({ - where: { id: webhookId }, - data, - }); - queueWebhook(groupId, Webhooks.UPDATE_WEBHOOK, data); - trackEvent({ groupId, type: Webhooks.UPDATE_WEBHOOK }, locals); - return result; -}; - -export const createWebhookForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - webhook: webhooksCreateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.WEBHOOKS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = await prisma.webhooks.create({ - data: { - ...webhook, - group: { - connect: { - id: groupId, - }, - }, - }, - }); - fireSingleWebhook(result, Webhooks.TEST_WEBHOOK) - .then(() => {}) - .catch(() => {}); - queueWebhook(groupId, Webhooks.CREATE_WEBHOOK, webhook); - trackEvent({ groupId, type: Webhooks.CREATE_WEBHOOK }, locals); - return result; -}; - -export const deleteWebhookForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - webhookId: number, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.WEBHOOKS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const result = prisma.webhooks.delete({ - where: { id: webhookId }, - }); - queueWebhook(groupId, Webhooks.DELETE_WEBHOOK, webhookId); - trackEvent({ groupId, type: Webhooks.DELETE_WEBHOOK }, locals); - return result; -}; - -export const applyCouponToGroupForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - coupon: string -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesGroup.TRANSACTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - let amount: number | undefined = undefined; - let currency: string | undefined = undefined; - let description: string | undefined = undefined; - try { - const result = await verifyToken<{ - amount: number; - currency: string; - description?: string; - }>(coupon, Tokens.COUPON); - await checkInvalidatedToken(coupon); - amount = result.amount; - currency = result.currency; - description = result.description; - } catch (error) { - throw new Error(INVALID_INPUT); - } - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - amount && - currency && - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) { - const result = await createCustomerBalanceTransaction( - group.attributes?.stripeCustomer, - { - amount, - currency, - description, - } - ); - await invalidateToken(coupon); - return result; - } - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupTransactionsForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - params: KeyValue -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.TRANSACTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getCustomBalanceTransactions( - group.attributes?.stripeCustomer, - params - ); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupTransactionForUser = async ( - userId: number | ApiKeyResponse, - groupId: number, - transactionId: string -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesGroup.TRANSACTIONS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const group = await getGroupById(groupId); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - group.attributes?.stripeCustomer === "string" - ) - return getCustomBalanceTransaction( - group.attributes?.stripeCustomer, - transactionId - ); - throw new Error(STRIPE_NO_CUSTOMER); -}; - -export const getGroupApiKeyScopesForUser = async ( - tokenUserId: number | ApiKeyResponse, - groupId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesGroup.API_KEYS}`, - `group-${groupId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const data: { [index: string]: any } = {}; - Object.values(ScopesGroup).forEach((scope) => { - data[scope] = []; - [Acts.READ, Acts.WRITE].forEach((act) => { - data[scope].push({ - value: `p, user-${tokenUserId}, group-${groupId}, ${act}${scope}`, - name: `${act}${scope}`, - }); - }); - }); - const memberships = await prisma.memberships.findMany({ - where: { groupId }, - }); - data["delete:data"] = [ - { - name: `${Acts.DELETE}group`, - value: `p, user-${tokenUserId}, group-${groupId}, ${Acts.DELETE}${ScopesGroup.INFO}`, - }, - ...memberships.map((membership) => ({ - value: `p, user-${tokenUserId}, membership-${membership.id}, ${Acts.DELETE}${ScopesUser.MEMBERSHIPS}`, - name: `${Acts.DELETE}membership-${membership.id}`, - })), - ]; - - return data; -}; diff --git a/src/_staart/rest/user.ts b/src/_staart/rest/user.ts deleted file mode 100644 index d53e1aae2..000000000 --- a/src/_staart/rest/user.ts +++ /dev/null @@ -1,934 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { - accessTokensCreateInput, - accessTokensUpdateInput, - identitiesCreateInput, - membershipsUpdateInput, - users, -} from "@prisma/client"; -import { checkIfDisposableEmail } from "@staart/disposable-email"; -import { - CANNOT_DELETE_SOLE_OWNER, - CANNOT_UPDATE_SOLE_OWNER, - EMAIL_CANNOT_DELETE, - EMAIL_EXISTS, - INCORRECT_PASSWORD, - INSUFFICIENT_PERMISSION, - INVALID_2FA_TOKEN, - MEMBERSHIP_NOT_FOUND, - NOT_ENABLED_2FA, - RESOURCE_NOT_FOUND, - USER_NOT_FOUND, -} from "@staart/errors"; -import { deleteCustomer } from "@staart/payments"; -import { compare, hash, randomString } from "@staart/text"; -import { authenticator } from "otplib"; -import { toDataURL } from "qrcode"; -import { ScopesGroup, ScopesUser } from "../config"; -import { Acts, can } from "../helpers/authorization"; -import { deleteItemFromCache } from "../helpers/cache"; -import { ApiKeyResponse } from "../helpers/jwt"; -import { - paginatedResult, - prisma, - queryParamsToSelect, -} from "../helpers/prisma"; -import { trackEvent } from "../helpers/tracking"; -import { PartialBy } from "../helpers/utils"; -import { EventType } from "../interfaces/enum"; -import { Locals } from "../interfaces/general"; -import { - createBackupCodes, - createEmail, - getUserById, - getUserPrimaryEmail, - resendEmailVerification, -} from "../services/user.service"; -import { deleteGroupForUser } from "./group"; - -const ALLOW_DISPOSABLE_EMAILS = config("allowDisposableEmails"); -const SERVICE_2FA = config("service_2Fa"); - -export const getUserFromIdForUser = async ( - userId: number, - tokenUserId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.INFO}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const user = await prisma.users.findOne({ - ...queryParamsToSelect(queryParams), - where: { id: userId }, - }); - if (user) return user; - throw new Error(USER_NOT_FOUND); -}; - -export const updateUserForUser = async ( - tokenUserId: number, - updateUserId: number, - _data: users, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.INFO}`, - `user-${updateUserId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const data: PartialBy = { ..._data }; - delete data.password; - const user = await prisma.users.update({ - data, - where: { id: updateUserId }, - }); - await deleteItemFromCache(`cache_getUserById_${updateUserId}`); - trackEvent( - { - userId: tokenUserId, - type: EventType.USER_UPDATED, - data: { id: updateUserId, data }, - }, - locals - ); - return user; -}; - -export const updatePasswordForUser = async ( - tokenUserId: number, - updateUserId: number, - oldPassword: string, - newPassword: string, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.SECURITY}`, - `user-${updateUserId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const user = await getUserById(updateUserId); - if (user.password) { - const correctPassword = await compare(oldPassword, user.password); - if (!correctPassword) throw new Error(INCORRECT_PASSWORD); - } - const result = await prisma.users.update({ - data: { password: await hash(newPassword, 8) }, - where: { id: updateUserId }, - }); - await deleteItemFromCache(`cache_getUserById_${updateUserId}`); - trackEvent( - { - userId: tokenUserId, - type: EventType.AUTH_PASSWORD_CHANGED, - data: { id: updateUserId }, - }, - locals - ); - return result; -}; - -export const deleteUserForUser = async ( - tokenUserId: number, - updateUserId: number, - locals: Locals | any -) => { - if (!(await can(tokenUserId, Acts.DELETE, `user-${updateUserId}`))) - throw new Error(INSUFFICIENT_PERMISSION); - - const groupsToDelete = await prisma.groups.findMany({ - select: { - attributes: true, - }, - where: { - memberships: { - every: { userId: updateUserId }, - }, - }, - }); - for await (const group of groupsToDelete) { - if ( - typeof group.attributes === "object" && - !Array.isArray(group.attributes) && - typeof group.attributes?.stripeCustomer === "string" - ) - await deleteCustomer(group.attributes?.stripeCustomer); - } - await prisma.groups.deleteMany({ - where: { - memberships: { - every: { userId: updateUserId }, - }, - }, - }); - await prisma.emails.deleteMany({ - where: { userId: updateUserId }, - }); - await prisma.memberships.deleteMany({ - where: { userId: updateUserId }, - }); - await prisma.approvedLocations.deleteMany({ - where: { userId: updateUserId }, - }); - const originalUser = await getUserById(updateUserId); - await prisma.users.delete({ where: { id: updateUserId } }); - await deleteItemFromCache(`cache_getUserById_${originalUser.id}`); - trackEvent( - { - userId: tokenUserId, - type: EventType.USER_DELETED, - data: { id: updateUserId }, - }, - locals - ); - return; -}; - -export const getMembershipsForUser = async ( - tokenUserId: number, - dataUserId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.MEMBERSHIPS}`, - `user-${dataUserId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.memberships.findMany({ - ...queryParamsToSelect(queryParams), - where: { userId: dataUserId }, - include: { group: true }, - }), - { take: queryParams.take } - ); -}; - -export const getPasswordForUser = async ( - tokenUserId: number, - dataUserId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.SECURITY}`, - `user-${dataUserId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const user = await prisma.users.findOne({ - where: { id: dataUserId }, - }); - if (!user) throw new Error(USER_NOT_FOUND); - return { hasPassword: !!user.password }; -}; - -export const getAllDataForUser = async ( - tokenUserId: number, - userId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.SECURITY}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.users.findOne({ - where: { id: userId }, - include: { - emails: true, - accessTokens: true, - approvedLocations: true, - backupCodes: true, - identities: true, - memberships: true, - sessions: true, - }, - }); -}; - -export const enable2FAForUser = async (tokenUserId: number, userId: number) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.SECURITY}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const secret = authenticator.generateSecret(); - await prisma.users.update({ - where: { id: userId }, - data: { twoFactorSecret: secret }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - const authPath = authenticator.keyuri(`user-${userId}`, SERVICE_2FA, secret); - const qrCode = await toDataURL(authPath); - return { qrCode }; -}; - -export const verify2FAForUser = async ( - tokenUserId: number, - userId: number, - verificationCode: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.SECURITY}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const secret = ( - await prisma.users.findOne({ - select: { twoFactorSecret: true }, - where: { id: userId }, - }) - )?.twoFactorSecret; - if (!secret) throw new Error(NOT_ENABLED_2FA); - if (!authenticator.check(verificationCode.toString(), secret)) - throw new Error(INVALID_2FA_TOKEN); - const codes = await createBackupCodes(userId, 10); - await prisma.users.update({ - where: { id: userId }, - data: { twoFactorEnabled: true }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - return codes; -}; - -export const disable2FAForUser = async ( - tokenUserId: number, - userId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.SECURITY}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - await prisma.backupCodes.deleteMany({ where: { userId: userId } }); - const result = prisma.users.update({ - where: { id: userId }, - data: { - twoFactorEnabled: false, - twoFactorSecret: null, - }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - return result; -}; - -export const regenerateBackupCodesForUser = async ( - tokenUserId: number, - userId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.SECURITY}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - await prisma.backupCodes.deleteMany({ where: { userId: userId } }); - return createBackupCodes(userId, 10); -}; - -export const getUserAccessTokensForUser = async ( - tokenUserId: number, - userId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.ACCESS_TOKENS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.accessTokens.findMany({ - where: { userId: userId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getUserAccessTokenScopesForUser = async (tokenUserId: number) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.ACCESS_TOKENS}`, - `user-${tokenUserId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const data: { [index: string]: any } = {}; - Object.values(ScopesUser).forEach((scope) => { - data[scope] = []; - [Acts.READ, Acts.WRITE].forEach((act) => { - data[scope].push({ - value: `p, user-${tokenUserId}, user-${tokenUserId}, ${act}${scope}`, - name: `${act}${scope}`, - }); - }); - }); - const memberships = await prisma.memberships.findMany({ - where: { userId: tokenUserId }, - }); - data["delete:data"] = [ - { - name: `${Acts.DELETE}user`, - value: `p, user-${tokenUserId}, user-${tokenUserId}, ${Acts.DELETE}${ScopesUser.INFO}`, - }, - ...memberships.map((membership) => ({ - value: `p, user-${tokenUserId}, membership-${membership.id}, ${Acts.DELETE}${ScopesUser.MEMBERSHIPS}`, - name: `${Acts.DELETE}membership-${membership.id}`, - })), - ...memberships - .filter( - (membership) => - membership.role === "ADMIN" || membership.role === "OWNER" - ) - .map((membership) => ({ - value: `p, user-${tokenUserId}, group-${membership.groupId}, ${Acts.DELETE}${ScopesGroup.INFO}`, - name: `${Acts.DELETE}group-${membership.groupId}`, - })), - ]; - - return data; -}; - -export const getUserAccessTokenForUser = async ( - tokenUserId: number, - userId: number, - accessTokenId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.ACCESS_TOKENS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.accessTokens.findOne({ - where: { id: accessTokenId }, - }); -}; - -export const updateAccessTokenForUser = async ( - tokenUserId: number, - userId: number, - accessTokenId: number, - data: accessTokensUpdateInput, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.ACCESS_TOKENS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.accessTokens.update({ - where: { id: accessTokenId }, - data, - }); -}; - -export const createAccessTokenForUser = async ( - tokenUserId: number, - userId: number, - accessToken: accessTokensCreateInput, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.ACCESS_TOKENS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - accessToken.accessToken = randomString({ length: 32 }); - return prisma.accessTokens.create({ - data: { ...accessToken, user: { connect: { id: userId } } }, - }); -}; - -export const deleteAccessTokenForUser = async ( - tokenUserId: number, - userId: number, - accessTokenId: number, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.ACCESS_TOKENS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.accessTokens.delete({ - where: { id: accessTokenId }, - }); -}; - -export const getUserSessionsForUser = async ( - tokenUserId: number, - userId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.SESSIONS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.sessions.findMany({ - where: { userId: userId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getUserSessionForUser = async ( - tokenUserId: number, - userId: number, - sessionId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.SESSIONS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.sessions.findOne({ where: { id: sessionId } }); -}; - -export const deleteSessionForUser = async ( - tokenUserId: number, - userId: number, - sessionId: number, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.SESSIONS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.sessions.delete({ where: { id: sessionId } }); -}; - -export const getUserIdentitiesForUser = async ( - tokenUserId: number, - userId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.IDENTITIES}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.identities.findMany({ - where: { userId: userId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const createUserIdentityForUser = async ( - tokenUserId: number, - userId: number, - identity: identitiesCreateInput -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.IDENTITIES}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.identities.create({ - data: { ...identity, user: { connect: { id: userId } } }, - }); -}; - -export const connectUserIdentityForUser = async ( - tokenUserId: number, - userId: number, - service: string, - url: string -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.IDENTITIES}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return true; -}; - -export const getUserIdentityForUser = async ( - tokenUserId: number, - userId: number, - identityId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.IDENTITIES}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.identities.findOne({ where: { id: identityId } }); -}; - -export const deleteIdentityForUser = async ( - tokenUserId: number, - userId: number, - identityId: number, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.IDENTITIES}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.identities.delete({ where: { id: identityId } }); -}; - -export const addInvitationCredits = async ( - invitedBy: number, - newUserId: number -) => { - // const invitedByUserId = ( - // await prisma.users.findOne({ - // select: { username: true }, - // where: { id: parseInt(invitedBy) }, - // }) - // )?.username; - // if (!invitedByUserId) return; - // const invitedByDetails = await getUserById(invitedByUserId); - // if (!invitedByDetails) return; - // const invitedByEmail = await getUserPrimaryEmail(invitedByUserId); - // const newUserEmail = await getUserBestEmail(newUserId); - // const newUserDetails = await getUserById(newUserId); - // if (!newUserDetails) return; - // const emailData = { - // invitedByName: invitedByDetails.name, - // invitedByCode: await couponCodeJwt( - // 500, - // "usd", - // `Invite credits from ${newUserDetails.name}` - // ), - // newUserName: newUserDetails.name, - // newUserCode: await couponCodeJwt( - // 500, - // "usd", - // `Invite credits from ${invitedByDetails.name}` - // ), - // }; - // await mail(invitedByEmail.email, Templates.CREDITS_INVITED_BY, emailData); - // await mail(newUserEmail.email, Templates.CREDITS_NEW_USER, emailData); -}; - -export const getAllEmailsForUser = async ( - tokenUserId: number, - userId: number, - queryParams: any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.EMAILS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return paginatedResult( - await prisma.emails.findMany({ - where: { userId: userId }, - ...queryParamsToSelect(queryParams), - }), - { take: queryParams.take } - ); -}; - -export const getEmailForUser = async ( - tokenUserId: number, - userId: number, - emailId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.EMAILS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.emails.findOne({ where: { id: emailId } }); -}; - -export const resendEmailVerificationForUser = async ( - tokenUserId: number, - userId: number, - emailId: number -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.EMAILS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return resendEmailVerification(emailId); -}; - -export const addEmailToUserForUser = async ( - tokenUserId: number, - userId: number, - email: string, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.EMAILS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - if (!ALLOW_DISPOSABLE_EMAILS) checkIfDisposableEmail(email); - const emailExistsAlready = - (await prisma.emails.findMany({ where: { email } })).length !== 0; - if (emailExistsAlready) throw new Error(EMAIL_EXISTS); - const result = await createEmail(userId, email, true); - trackEvent( - { userId, type: EventType.EMAIL_CREATED, data: { email } }, - locals - ); - return result; -}; - -export const deleteEmailFromUserForUser = async ( - tokenUserId: number, - userId: number, - emailId: number, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.WRITE}${ScopesUser.EMAILS}`, - `user-${userId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const email = await prisma.emails.findOne({ - where: { id: emailId }, - }); - if (!email) throw new Error(RESOURCE_NOT_FOUND); - if (email.userId !== userId) throw new Error(INSUFFICIENT_PERMISSION); - const verifiedEmails = await prisma.emails.findMany({ - where: { id: emailId }, - }); - if (verifiedEmails.length === 1 && email.isVerified) - throw new Error(EMAIL_CANNOT_DELETE); - const currentPrimaryEmailId = (await getUserPrimaryEmail(userId)).id; - if (currentPrimaryEmailId === emailId) { - const nextVerifiedEmail = verifiedEmails.filter( - (emailObject) => emailObject.id !== emailId - )[0]; - await prisma.users.update({ - where: { id: userId }, - data: { prefersEmail: { connect: { id: nextVerifiedEmail.id } } }, - }); - await deleteItemFromCache(`cache_getUserById_${userId}`); - } - const result = await prisma.emails.delete({ - where: { id: emailId }, - }); - trackEvent( - { userId, type: EventType.EMAIL_DELETED, data: { email: email.email } }, - locals - ); - return result; -}; - -export const getMembershipDetailsForUser = async ( - userId: number, - membershipId: number -) => { - if ( - !(await can( - userId, - `${Acts.READ}${ScopesUser.MEMBERSHIPS}`, - `membership-${membershipId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - return prisma.memberships.findOne({ - where: { id: membershipId }, - include: { user: true, group: true }, - }); -}; - -export const deleteMembershipForUser = async ( - tokenUserId: number | ApiKeyResponse, - membershipId: number, - locals: Locals | any -) => { - if ( - !(await can( - tokenUserId, - `${Acts.READ}${ScopesUser.MEMBERSHIPS}`, - `membership-${membershipId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const membership = await prisma.memberships.findOne({ - where: { id: membershipId }, - }); - if (!membership) throw new Error(MEMBERSHIP_NOT_FOUND); - const groupMembers = await prisma.memberships.findMany({ - where: { groupId: membership.groupId }, - }); - if (groupMembers.length === 1) - return deleteGroupForUser(tokenUserId, membership.groupId, locals); - if (membership.role === "OWNER") { - const currentMembers = groupMembers.filter( - (member) => member.role === "OWNER" - ); - if (currentMembers.length < 2) throw new Error(CANNOT_DELETE_SOLE_OWNER); - } - trackEvent( - { - userId: membershipId, - type: EventType.MEMBERSHIP_DELETED, - }, - locals - ); - return await prisma.memberships.delete({ where: { id: membership.id } }); -}; - -export const updateMembershipForUser = async ( - userId: number | ApiKeyResponse, - membershipId: number, - data: membershipsUpdateInput, - locals: Locals | any -) => { - if ( - !(await can( - userId, - `${Acts.WRITE}${ScopesUser.MEMBERSHIPS}`, - `membership-${membershipId}` - )) - ) - throw new Error(INSUFFICIENT_PERMISSION); - - const membership = await prisma.memberships.findOne({ - where: { id: membershipId }, - }); - if (!membership) throw new Error(MEMBERSHIP_NOT_FOUND); - if (data.role !== membership.role) { - if (membership.role === "OWNER") { - const groupMembers = await prisma.memberships.findMany({ - where: { groupId: membership.groupId }, - }); - const currentMembers = groupMembers.filter( - (member) => member.role === "OWNER" - ); - if (currentMembers.length < 2) throw new Error(CANNOT_UPDATE_SOLE_OWNER); - } - } - trackEvent( - { - userId: membershipId, - type: EventType.MEMBERSHIP_UPDATED, - }, - locals - ); - return prisma.memberships.update({ - where: { id: membershipId }, - data, - }); -}; diff --git a/src/_staart/services/group.service.ts b/src/_staart/services/group.service.ts deleted file mode 100644 index 8f6b18aeb..000000000 --- a/src/_staart/services/group.service.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { - apiKeysUpdateInput, - domainsCreateInput, - groups, - groupsCreateInput, - groupsUpdateInput, -} from "@prisma/client"; -import { - cleanElasticSearchQueryResponse, - elasticSearch, -} from "@staart/elasticsearch"; -import { - INVALID_INPUT, - ORGANIZATION_NOT_FOUND, - RESOURCE_NOT_FOUND, -} from "@staart/errors"; -import { capitalizeFirstAndLastLetter, ms, randomString } from "@staart/text"; -import axios from "axios"; -import randomColor from "randomcolor"; -import { - deleteItemFromCache, - getItemFromCache, - setItemInCache, -} from "../helpers/cache"; -import { prisma } from "../helpers/prisma"; -import { KeyValue } from "../interfaces/general"; - -const ELASTIC_LOGS_INDEX = config("elasticLogsIndex"); -const JWT_ISSUER = config("jwtIssuer"); - -/* - * Create a new group for a user - */ -export const createGroup = async ( - group: groupsCreateInput, - ownerId: number -) => { - if (!group.name) throw new Error(INVALID_INPUT); - group.name = capitalizeFirstAndLastLetter(group.name); - const backgroundColor = randomColor({ - luminosity: "dark", - format: "hex", - }).replace("#", ""); - group.profilePictureUrl = `https://ui-avatars.com/api/?name=${encodeURIComponent( - (group.name || "XX").substring(0, 2).toUpperCase() - )}&background=${backgroundColor}&color=fff`; - const result = await prisma.groups.create({ - data: group, - }); - await prisma.memberships.create({ - data: { - role: "OWNER", - user: { connect: { id: ownerId } }, - group: { connect: { id: result.id } }, - }, - }); - return result; -}; - -/* - * Update an group - */ -export const updateGroup = async (id: number, group: groupsUpdateInput) => { - const originalGroup = await getGroupById(id); - await deleteItemFromCache(`cache_getGroupById_${originalGroup.id}`); - if (!originalGroup) throw new Error(ORGANIZATION_NOT_FOUND); - return prisma.groups.update({ - data: group, - where: { id: id }, - }); -}; - -/** - * Get an API key - */ -export const getApiKeyLogs = async (apiKeyId: number, query: KeyValue) => { - const range: string = query.range || "7d"; - const from = query.from ? parseInt(query.from) : 0; - const result = await elasticSearch.search({ - index: ELASTIC_LOGS_INDEX, - from, - body: { - query: { - bool: { - must: [ - { - match: { - apiKeyId, - }, - }, - { - range: { - date: { - gte: new Date(new Date().getTime() - ms(range)), - }, - }, - }, - ], - }, - }, - sort: [ - { - date: { order: "desc" }, - }, - ], - size: 10, - }, - }); - return cleanElasticSearchQueryResponse(result.body, 10); -}; - -/** - * Update a user's details - */ -export const updateApiKey = async ( - apiKeyId: number, - data: apiKeysUpdateInput -) => { - const apiKey = await prisma.apiKeys.findOne({ - where: { id: apiKeyId }, - }); - if (!apiKey) throw new Error(RESOURCE_NOT_FOUND); - return prisma.apiKeys.update({ data, where: { id: apiKeyId } }); -}; - -/** - * Get a domain - */ -export const getDomainByDomainName = async (domain: string) => { - const domainDetails = await prisma.domains.findMany({ - where: { domain, isVerified: true }, - take: 1, - }); - if (domainDetails.length) return domainDetails[0]; - throw new Error(RESOURCE_NOT_FOUND); -}; - -export const refreshGroupProfilePicture = async (groupId: number) => { - const domains = await prisma.domains.findMany({ - where: { groupId: groupId }, - orderBy: { updatedAt: "desc" }, - }); - if (domains.length) { - const domainIcons = await axios.get<{ url?: string }>( - `https://unavatar.now.sh/${domains[0].domain}?json` - ); - if ( - domainIcons.data && - domainIcons.data.url && - domainIcons.data.url !== "http://unavatar.now.sh/fallback.png" - ) - return prisma.groups.update({ - data: { profilePictureUrl: domainIcons.data.url }, - where: { id: groupId }, - }); - } - const group = await prisma.groups.findOne({ - where: { id: groupId }, - select: { name: true }, - }); - if (!group) throw new Error(ORGANIZATION_NOT_FOUND); - const backgroundColor = randomColor({ - luminosity: "dark", - format: "hex", - }).replace("#", ""); - const profilePictureUrl = `https://ui-avatars.com/api/?name=${encodeURIComponent( - group.name || "XX" - ).replace( - /^([a-zA-Z0-9 _-]+)$/gi, - "" - )}&background=${backgroundColor}&color=fff`; - return prisma.groups.update({ - data: { profilePictureUrl }, - where: { id: groupId }, - }); -}; - -/** - * Create a domain - */ -export const createDomain = async (domain: domainsCreateInput) => { - domain.verificationCode = `${JWT_ISSUER}=${randomString({ - length: 32, - })}`; - const response = await prisma.domains.create({ data: domain }); - refreshGroupProfilePicture(response.groupId) - .then(() => {}) - .catch(() => {}); - return response; -}; - -/** - * Check if a domain is available - */ -export const checkDomainAvailability = async (domainName: string) => { - try { - const domain = await getDomainByDomainName(domainName); - if (domain && domain.id) return false; - } catch (error) {} - return true; -}; - -/** - * Get a group object from its ID - * @param id - User ID - */ -export const getGroupById = async (id: number) => { - const key = `cache_getGroupById_${id}`; - try { - return await getItemFromCache(key); - } catch (error) { - const group = await prisma.groups.findOne({ - where: { id }, - }); - if (group) { - await setItemInCache(key, group); - return group; - } - throw new Error(ORGANIZATION_NOT_FOUND); - } -}; diff --git a/src/_staart/services/user.service.ts b/src/_staart/services/user.service.ts deleted file mode 100644 index 52ee295ef..000000000 --- a/src/_staart/services/user.service.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { - accessTokens, - sessionsUpdateInput, - users, - usersCreateInput, -} from "@prisma/client"; -import { - MISSING_PRIMARY_EMAIL, - RESOURCE_NOT_FOUND, - USER_NOT_FOUND, -} from "@staart/errors"; -import { - anonymizeIpAddress, - capitalizeFirstAndLastLetter, - hash, -} from "@staart/text"; -import { createHash } from "crypto"; -import { decode } from "jsonwebtoken"; -import randomInt from "random-int"; -import { - deleteItemFromCache, - getItemFromCache, - setItemInCache, -} from "../helpers/cache"; -import { emailVerificationToken } from "../helpers/jwt"; -import { mail } from "../helpers/mail"; -import { prisma } from "../helpers/prisma"; -import { deleteSensitiveInfoUser } from "../helpers/utils"; -import { Templates } from "../interfaces/enum"; -import { KeyValue, Locals } from "../interfaces/general"; -import { config } from "@anandchowdhary/cosmic"; -import { sendNewPassword } from "../rest/auth"; -import axios from "axios"; -import { getGeolocationFromIp } from "../helpers/location"; - -/** - * Create a new user - */ -export const createUser = async (user: usersCreateInput, locals?: Locals) => { - user.name = capitalizeFirstAndLastLetter(user.name); - user.password = user.password ? await hash(user.password, 8) : undefined; - if (config("registerGenderPrediction") && !user.gender) { - try { - const { data }: { data: { gender: "male" | "female" } } = await axios.get( - `https://api.genderize.io/?name=peter` - ); - if (["male", "female"].includes(data.gender)) - user.gender = data.gender.toUpperCase() as "MALE" | "FEMALE"; - } catch (error) {} - } - if ( - locals && - config("registerLocationDetection") && - (!user.countryCode || !user.timezone) - ) { - try { - const location = await getGeolocationFromIp(locals.ipAddress); - user.countryCode = user.countryCode ?? location?.country_code; - user.timezone = user.timezone ?? location?.time_zone; - } catch (error) {} - } - user.profilePictureUrl = - user.profilePictureUrl || - `https://api.adorable.io/avatars/285/${createHash("md5") - .update(user.name) - .digest("hex")}.png`; - const result = await prisma.users.create({ - data: user, - }); - return result; -}; - -/** - * Get the details of a user by their email - */ -export const getUserByEmail = async (email: string, secureOrigin = false) => { - const users = await prisma.users.findMany({ - where: { - emails: { - some: { - email, - isVerified: true, - }, - }, - }, - }); - if (!users.length) throw new Error(USER_NOT_FOUND); - if (!secureOrigin) return deleteSensitiveInfoUser(users[0]); - return users[0]; -}; - -/** - * Update a user's details - */ -export const updateUser = async (id: number, user: KeyValue) => { - const originalUser = await getUserById(id); - await deleteItemFromCache(`cache_getUserById_${originalUser.id}`); - if (user.password) user.password = await hash(user.password, 8); - if (user.prefersEmailId) { - if ((originalUser.profilePictureUrl || "").includes("api.adorable.io")) { - const emailDetails = await prisma.emails.findOne({ - where: { id: user.prefersEmailId }, - }); - if (emailDetails) - user.profilePicture = `https://www.gravatar.com/avatar/${createHash( - "md5" - ) - .update(emailDetails.email) - .digest("hex")}?d=${encodeURIComponent( - `https://api.adorable.io/avatars/285/${createHash("md5") - .update(originalUser.name) - .digest("hex")}.png` - )}`; - } - } - const result = await prisma.users.update({ - data: user, - where: { id: id }, - }); - return result; -}; - -/** - * Add a new approved location for a user - * @param ipAddress - IP address for the new location - */ -export const addApprovedLocation = async ( - userId: number, - ipAddress: string -) => { - const subnet = anonymizeIpAddress(ipAddress); - return prisma.approvedLocations.create({ - data: { - user: { connect: { id: userId } }, - subnet, - createdAt: new Date(), - }, - }); -}; - -/** - * Check whether a location is approved for a user - * @param ipAddress - IP address for checking - */ -export const checkApprovedLocation = async ( - userId: number, - ipAddress: string -) => { - const user = await getUserById(userId); - if (!user) throw new Error(USER_NOT_FOUND); - if (!user.checkLocationOnLogin) return true; - const subnet = anonymizeIpAddress(ipAddress); - return ( - ( - await prisma.approvedLocations.findMany({ - where: { userId: userId, subnet }, - }) - ).length !== 0 - ); -}; - -/** - * Create 2FA backup codes for user - * We generate 6-digit backup codes for a user - * and save the hashed version in the database - * @param count - Number of backup codes to create - */ -export const createBackupCodes = async (userId: number, count = 1) => { - const now = new Date(); - const codes: string[] = []; - for await (const _ of Array.from(Array(count).keys())) { - const code = randomInt(100000, 999999).toString(); - codes.push(code); - await prisma.backupCodes.create({ - data: { - code: await hash(code, 8), - user: { connect: { id: userId } }, - createdAt: now, - updatedAt: now, - }, - }); - } - return codes; -}; - -/** - * Update a user's details - */ -export const updateAccessToken = async ( - accessTokenId: number, - data: accessTokens -) => { - const newAccessToken = await prisma.accessTokens.findOne({ - where: { id: accessTokenId }, - }); - if (!newAccessToken) throw new Error(RESOURCE_NOT_FOUND); - return prisma.accessTokens.update({ - data, - where: { id: accessTokenId }, - }); -}; - -/** - * Delete an API key - */ -export const deleteAccessToken = async (accessTokenId: number) => { - const currentAccessToken = await prisma.accessTokens.findOne({ - where: { id: accessTokenId }, - }); - if (!currentAccessToken) throw new Error(RESOURCE_NOT_FOUND); - return prisma.accessTokens.delete({ - where: { id: accessTokenId }, - }); -}; - -/** - * Get the primary email of a user - * @param userId - User Id - */ -export const getUserPrimaryEmail = async (userId: number) => { - const prefersEmail = ( - await prisma.users.findOne({ - select: { prefersEmail: true }, - where: { id: userId }, - }) - )?.prefersEmail; - if (!prefersEmail) throw new Error(MISSING_PRIMARY_EMAIL); - return prefersEmail; -}; - -/** - * Update a session based on JWT - * @param userId - User ID - * @param sessionJwt - Provided session JWT - * @param data - Session information to update - */ -export const updateSessionByJwt = async ( - userId: number, - sessionJwt: string, - data: sessionsUpdateInput -) => { - try { - const decoded = decode(sessionJwt); - if (decoded && typeof decoded === "object" && decoded.jti) { - sessionJwt = decoded.jti; - } - } catch (error) {} - const currentSession = await prisma.sessions.findMany({ - where: { token: sessionJwt, userId }, - }); - if (!currentSession.length) throw new Error(RESOURCE_NOT_FOUND); - return prisma.sessions.update({ where: { id: currentSession[0].id }, data }); -}; - -/** - * Create a new email for a user - * @param sendVerification Whether to send an email verification link to new email - * @param isVerified Whether this email is verified by default - */ -export const createEmail = async ( - userId: number, - email: string, - sendVerification = true, - sendPasswordSet = false -) => { - const emailSafe = email.trim().toLowerCase(); - const result = await prisma.emails.create({ - data: { email, emailSafe, user: { connect: { id: userId } } }, - }); - if (sendVerification) { - const user = await getUserById(userId); - if (!user) throw new Error(USER_NOT_FOUND); - await sendEmailVerification(result.id, email, user); - } - if (sendPasswordSet) await sendNewPassword(userId, email); - return result; -}; - -/** - * Send an email verification link - */ -export const sendEmailVerification = async ( - id: number, - email: string, - user: users -) => { - const token = await emailVerificationToken(id); - await mail({ - to: email, - template: Templates.EMAIL_VERIFY, - data: { name: user.name, email, token }, - }); - return; -}; - -/** - * Resend an email verification link - */ -export const resendEmailVerification = async (id: number) => { - const token = await emailVerificationToken(id); - const emailObject = await prisma.emails.findOne({ - where: { id: id }, - }); - if (!emailObject) throw new Error(RESOURCE_NOT_FOUND); - const email = emailObject.email; - const user = await getUserById(emailObject.userId); - if (!user) throw new Error(USER_NOT_FOUND); - await mail({ - to: email, - template: Templates.EMAIL_VERIFY, - data: { name: user.name, email, token }, - }); - return; -}; - -/** - * Get a user object from its ID - * @param id - User ID - */ -export const getUserById = async (id: number) => { - const key = `cache_getUserById_${id}`; - try { - return await getItemFromCache(key); - } catch (error) { - const user = await prisma.users.findOne({ where: { id } }); - if (user) { - await setItemInCache(key, user); - return user; - } - throw new Error(USER_NOT_FOUND); - } -}; diff --git a/src/app.module.ts b/src/app.module.ts new file mode 100644 index 000000000..e2838da5f --- /dev/null +++ b/src/app.module.ts @@ -0,0 +1,95 @@ +import { + MiddlewareConsumer, + Module, + NestModule, + RequestMethod, +} from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; +import { ScheduleModule } from '@nestjs/schedule'; +import { RateLimiterInterceptor, RateLimiterModule } from 'nestjs-rate-limiter'; +import configuration from './config/configuration'; +import { AuditLogger } from './interceptors/audit-log.interceptor'; +import { JsonBodyMiddleware } from './middleware/json-body.middleware'; +import { RawBodyMiddleware } from './middleware/raw-body.middleware'; +import { ApiKeysModule } from './modules/api-keys/api-keys.module'; +import { ApprovedSubnetsModule } from './modules/approved-subnets/approved-subnets.module'; +import { AuditLogsModule } from './modules/audit-logs/audit-logs.module'; +import { AuthModule } from './modules/auth/auth.module'; +import { ScopesGuard } from './modules/auth/scope.guard'; +import { StaartAuthGuard } from './modules/auth/staart-auth.guard'; +import { DnsModule } from './modules/dns/dns.module'; +import { DomainsModule } from './modules/domains/domains.module'; +import { EmailModule } from './modules/email/email.module'; +import { EmailsModule } from './modules/emails/emails.module'; +import { GeolocationModule } from './modules/geolocation/geolocation.module'; +import { GroupsModule } from './modules/groups/groups.module'; +import { MembershipsModule } from './modules/memberships/memberships.module'; +import { MultiFactorAuthenticationModule } from './modules/multi-factor-authentication/multi-factor-authentication.module'; +import { PrismaModule } from './modules/prisma/prisma.module'; +import { SessionsModule } from './modules/sessions/sessions.module'; +import { StripeModule } from './modules/stripe/stripe.module'; +import { TasksModule } from './modules/tasks/tasks.module'; +import { UsersModule } from './modules/users/users.module'; +import { WebhooksModule } from './modules/webhooks/webhooks.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + load: [configuration], + }), + ScheduleModule.forRoot(), + PrismaModule, + TasksModule, + UsersModule, + AuthModule, + RateLimiterModule.register({ + points: 100, + duration: 60, + }), + EmailModule, + SessionsModule, + EmailsModule, + GroupsModule, + MultiFactorAuthenticationModule, + ApiKeysModule, + ApprovedSubnetsModule, + DomainsModule, + DnsModule, + GeolocationModule, + MembershipsModule, + StripeModule, + AuditLogsModule, + WebhooksModule, + ], + providers: [ + { + provide: APP_INTERCEPTOR, + useClass: RateLimiterInterceptor, + }, + { + provide: APP_GUARD, + useClass: StaartAuthGuard, + }, + { + provide: APP_GUARD, + useClass: ScopesGuard, + }, + { + provide: APP_INTERCEPTOR, + useClass: AuditLogger, + }, + ], +}) +export class AppModule implements NestModule { + public configure(consumer: MiddlewareConsumer): void { + consumer + .apply(RawBodyMiddleware) + .forRoutes({ + path: '/webhooks/stripe', + method: RequestMethod.POST, + }) + .apply(JsonBodyMiddleware) + .forRoutes('*'); + } +} diff --git a/src/config/configuration.interface.ts b/src/config/configuration.interface.ts new file mode 100644 index 000000000..f0fda2497 --- /dev/null +++ b/src/config/configuration.interface.ts @@ -0,0 +1,54 @@ +import Stripe from 'stripe'; + +export interface Configuration { + frontendUrl: string; + + meta: { + totpServiceName: string; + domainVerificationFile: string; + }; + + caching: { + geolocationLruSize: number; + apiKeyLruSize: number; + }; + + security: { + saltRounds: number; + jwtSecret: string; + totpWindowPast: number; + totpWindowFuture: number; + mfaTokenExpiry: string; + mergeUsersTokenExpiry: string; + accessTokenExpiry: string; + passwordPwnedCheck: boolean; + unusedRefreshTokenExpiryDays: number; + }; + + email: { + name: string; + from: string; + host: string; + port: number; + secure: boolean; + auth: { + user: string; + pass: string; + }; + }; + + sms: { + smsServiceName: string; + twilioAccountSid: string; + twilioAuthToken: string; + }; + + payments: { + stripeApiKey: string; + stripeProductId: string; + stripeEndpointSecret: string; + paymentMethodTypes: Array< + Stripe.Checkout.SessionCreateParams.PaymentMethodType + >; + }; +} diff --git a/src/config/configuration.ts b/src/config/configuration.ts new file mode 100644 index 000000000..f828960ea --- /dev/null +++ b/src/config/configuration.ts @@ -0,0 +1,57 @@ +import { ConfigFactory } from '@nestjs/config/dist/interfaces'; +import { config } from 'dotenv'; +import dotenvExpand from 'dotenv-expand'; +import { Configuration } from './configuration.interface'; +dotenvExpand(config()); + +export const int = (val: string | undefined, num: number): number => + val ? (isNaN(parseInt(val)) ? num : parseInt(val)) : num; + +const configuration: Configuration = { + frontendUrl: process.env.FRONTEND_URL ?? 'http://localhost:3000', + meta: { + totpServiceName: process.env.TOPT_SERVICE_NAME ?? 'Staart', + domainVerificationFile: + process.env.DOMAIN_VERIFICATION_FILE ?? 'staart-verify.txt', + }, + caching: { + geolocationLruSize: int(process.env.GEOLOCATION_LRU_SIZE, 100), + apiKeyLruSize: int(process.env.API_KEY_LRU_SIZE, 100), + }, + security: { + saltRounds: int(process.env.SALT_ROUNDS, 10), + jwtSecret: process.env.JWT_SECRET ?? 'staart', + totpWindowPast: int(process.env.TOTP_WINDOW_PAST, 1), + totpWindowFuture: int(process.env.TOTP_WINDOW_PAST, 0), + mfaTokenExpiry: process.env.MFA_TOKEN_EXPIRY ?? '10m', + mergeUsersTokenExpiry: process.env.MERGE_USERS_TOKEN_EXPIRY ?? '30m', + accessTokenExpiry: process.env.ACCESS_TOKEN_EXPIRY ?? '1h', + passwordPwnedCheck: !!process.env.PASSWORD_PWNED_CHECK, + unusedRefreshTokenExpiryDays: int(process.env.DELETE_EXPIRED_SESSIONS, 30), + }, + email: { + name: process.env.EMAIL_NAME ?? 'Staart', + from: process.env.EMAIL_FROM ?? '', + host: process.env.EMAIL_HOST ?? '', + port: int(process.env.EMAIL_PORT, 587), + secure: !!process.env.EMAIL_SECURE, + auth: { + user: process.env.EMAIL_USER ?? process.env.EMAIL_FROM ?? '', + pass: process.env.EMAIL_PASSWORD ?? '', + }, + }, + sms: { + smsServiceName: process.env.SMS_SERVICE_NAME ?? '', + twilioAccountSid: process.env.TWILIO_ACCOUNT_SID ?? '', + twilioAuthToken: process.env.TWILIO_AUTH_TOKEN ?? '', + }, + payments: { + stripeApiKey: process.env.STRIPE_API_KEY ?? '', + stripeProductId: process.env.STRIPE_PRODUCT_ID ?? '', + stripeEndpointSecret: process.env.STRIPE_ENDPOINT_SECRET ?? '', + paymentMethodTypes: ['card'], + }, +}; + +const configFunction: ConfigFactory = () => configuration; +export default configFunction; diff --git a/src/controllers/admin/coupons.ts b/src/controllers/admin/coupons.ts deleted file mode 100644 index bab7f80eb..000000000 --- a/src/controllers/admin/coupons.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { MISSING_FIELD } from "@staart/errors"; -import { RESOURCE_CREATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi } from "@staart/validate"; -import { authHandler, validator } from "../../_staart/helpers/middleware"; -import { - deleteCouponForUser, - generateCouponForUser, - getAllCouponsForUser, - getCouponForUser, - updateCouponForUser, -} from "../../_staart/rest/admin"; -import { twtToId } from "../../_staart/helpers/utils"; - -@ClassMiddleware(authHandler) -export class AdminCouponController { - @Get() - async getCoupons(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getAllCouponsForUser(userId, req.query); - } - - @Put() - @Middleware( - validator( - { - code: Joi.string(), - teamRestrictions: Joi.string(), - amount: Joi.number().required(), - currency: Joi.string().min(3).max(3).required(), - description: Joi.string(), - jwt: Joi.boolean(), - expiresAt: Joi.any(), - maxUses: Joi.number(), - }, - "body" - ) - ) - async createCoupon(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - const added = await generateCouponForUser(userId, req.body); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Get(":id") - async getCoupon(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getCouponForUser(userId, req.params.id); - } - - @Patch(":id") - @Middleware( - validator( - { - code: Joi.string(), - amount: Joi.number(), - currency: Joi.string().min(3).max(3), - description: Joi.string().allow(null), - expiresAt: Joi.any().allow(null), - teamRestrictions: Joi.string().allow(null), - maxUses: Joi.number().allow(null), - jwt: Joi.boolean(), - }, - "body" - ) - ) - async updateCoupon(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return updateCouponForUser(userId, req.params.id, req.body); - } - - @Delete(":id") - async deleteCoupon(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return deleteCouponForUser(userId, req.params.id); - } -} diff --git a/src/controllers/admin/index.ts b/src/controllers/admin/index.ts deleted file mode 100644 index 7d2076cdd..000000000 --- a/src/controllers/admin/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MISSING_FIELD } from "@staart/errors"; -import { ClassMiddleware, Get, Request, Response } from "@staart/server"; -import { authHandler } from "../../_staart/helpers/middleware"; -import { - getAllGroupForUser, - getAllUsersForUser, - getPaymentEventsForUser, - getServerLogsForUser, -} from "../../_staart/rest/admin"; -import { twtToId } from "../../_staart/helpers/utils"; - -@ClassMiddleware(authHandler) -export class AdminController { - @Get("groups") - async getGroups(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getAllGroupForUser(userId, req.query); - } - - @Get("users") - async getUsers(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getAllUsersForUser(userId, req.query); - } - - @Get("server-logs") - async getServerLogs(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getServerLogsForUser(userId, req.query); - } - - @Get("payment-events") - async getPaymentEvents(req: Request, res: Response) { - const userId = twtToId(res.locals.token.id); - if (!userId) throw new Error(MISSING_FIELD); - return getPaymentEventsForUser(userId, req.query); - } - - @Get("info") - async info() { - return { - success: true, - message: "admin-info-success", - }; - } -} diff --git a/src/controllers/auth/index.ts b/src/controllers/auth/index.ts deleted file mode 100644 index 43695bba6..000000000 --- a/src/controllers/auth/index.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { INVALID_TOKEN } from "@staart/errors"; -import { - RESOURCE_CREATED, - RESOURCE_SUCCESS, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { Middleware, Post, Request, Response } from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { verifyToken } from "../../_staart/helpers/jwt"; -import { - authHandler, - bruteForceHandler, - validator, -} from "../../_staart/helpers/middleware"; -import { - approveLocation, - impersonate, - invalidateRefreshToken, - login, - login2FA, - register, - resendEmailVerificationWithToken, - sendPasswordReset, - updatePassword, - validateRefreshToken, - verifyEmail, - loginLink, -} from "../../_staart/rest/auth"; -import { addInvitationCredits } from "../../_staart/rest/user"; -import { twtToId } from "../../_staart/helpers/utils"; - -export class AuthController { - @Post("register") - @Middleware(bruteForceHandler) - @Middleware( - validator( - { - email: Joi.string().email().required(), - name: Joi.string() - .min(3) - .regex(/^[a-zA-Z ]*$/) - .required(), - countryCode: Joi.string().length(2), - password: Joi.string().min(6), - gender: Joi.string().length(1), - preferredLanguage: Joi.string().min(2).max(5), - timezone: Joi.string(), - invitedByUser: Joi.string().optional(), - }, - "body" - ) - ) - async register(req: Request, res: Response) { - const user = req.body; - const email = req.body.email; - const invitedByUser = req.body.invitedByUser; - delete user.groupId; - delete user.email; - delete user.invitedByUser; - if (user.role === "ADMIN") delete user.role; - delete user.membershipRole; - const { userId, resendToken } = await register( - user, - res.locals, - email, - req.body.groupId, - req.body.membershipRole - ); - if (invitedByUser) await addInvitationCredits(invitedByUser, userId); - return { ...respond(RESOURCE_CREATED), resendToken }; - } - - @Post("login") - @Middleware(bruteForceHandler) - @Middleware( - validator( - { - email: Joi.string().email().required(), - password: Joi.string().min(6).allow(""), - }, - "body" - ) - ) - async login(req: Request, res: Response) { - return login(req.body.email, req.body.password, res.locals); - } - - @Post("2fa") - @Middleware( - validator( - { - token: Joi.string().required(), - code: Joi.number().min(5).required(), - }, - "body" - ) - ) - async twoFactor(req: Request, res: Response) { - const code = req.body.code; - const token = req.body.token; - return login2FA(code, token, res.locals); - } - - @Post("verify-token") - @Middleware( - validator( - { - token: Joi.string().required(), - subject: Joi.string().required(), - }, - "body" - ) - ) - async postVerifyToken(req: Request) { - const token = - req.body.token || (req.get("Authorization") || "").replace("Bearer ", ""); - const subject = req.body.subject; - try { - const data = await verifyToken(token, subject); - return { verified: true, data }; - } catch (error) { - throw new Error(INVALID_TOKEN); - } - } - - @Post("refresh") - async postRefreshToken(req: Request, res: Response) { - const token = - req.body.token || (req.get("Authorization") || "").replace("Bearer ", ""); - joiValidate({ token: Joi.string().required() }, { token }); - return validateRefreshToken(token, res.locals); - } - - @Post("logout") - async postLogout(req: Request, res: Response) { - const token = - req.body.token || (req.get("Authorization") || "").replace("Bearer ", ""); - joiValidate({ token: Joi.string().required() }, { token }); - await invalidateRefreshToken(token, res.locals); - return respond(RESOURCE_SUCCESS); - } - - @Post("reset-password/request") - @Middleware( - validator( - { - email: Joi.string().email().required(), - }, - "body" - ) - ) - async postResetPasswordRequest(req: Request, res: Response) { - const email = req.body.email; - await sendPasswordReset(email, res.locals); - return respond(RESOURCE_SUCCESS); - } - - @Post("reset-password/recover") - async postResetPasswordRecover(req: Request, res: Response) { - const token = - req.body.token || (req.get("Authorization") || "").replace("Bearer ", ""); - const password = req.body.password; - joiValidate( - { - token: Joi.string().required(), - password: Joi.string().min(6).required(), - }, - { token, password } - ); - await updatePassword(token, password, res.locals); - return respond(RESOURCE_UPDATED); - } - @Post("resend-verification") - @Middleware( - validator( - { - token: Joi.string().required(), - }, - "body" - ) - ) - async resendEmail(req: Request, res: Response) { - const token = req.body.token; - await resendEmailVerificationWithToken(token); - return respond(RESOURCE_UPDATED); - } - - @Post("impersonate/:id") - @Middleware(authHandler) - @Middleware( - validator({ impersonateUserId: Joi.number().required() }, "params") - ) - async getImpersonate(req: Request, res: Response) { - const tokenUserId = twtToId(res.locals.token.id); - const impersonateUserId = twtToId(req.params.id); - return impersonate(tokenUserId, impersonateUserId, res.locals); - } - - @Post("approve-location") - async getApproveLocation(req: Request, res: Response) { - const token = req.body.token || req.params.token; - joiValidate({ token: Joi.string().required() }, { token }); - return approveLocation(token, res.locals); - } - - @Post("verify-email") - async postVerifyEmail(req: Request, res: Response) { - const token = req.body.token || req.params.token; - joiValidate({ token: Joi.string().required() }, { token }); - await verifyEmail(token, res.locals); - return respond(RESOURCE_SUCCESS); - } - - @Post("login-link") - async postLoginLink(req: Request, res: Response) { - const token = req.body.token || req.params.token; - joiValidate({ token: Joi.string().required() }, { token }); - return loginLink(token, res.locals); - } -} diff --git a/src/controllers/groups/_id/api-keys.ts b/src/controllers/groups/_id/api-keys.ts deleted file mode 100644 index 436607de4..000000000 --- a/src/controllers/groups/_id/api-keys.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - createApiKeyForUser, - deleteApiKeyForUser, - getGroupApiKeyForUser, - getGroupApiKeyLogsForUser, - getGroupApiKeysForUser, - updateApiKeyForUser, - getGroupApiKeyScopesForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupApiKeysController { - @Get() - async getUserApiKeys(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getGroupApiKeysForUser(localsToTokenOrKey(res), id, req.query); - } - - @Put() - @Middleware( - validator( - { - scopes: Joi.array().items(Joi.string()), - ipRestrictions: Joi.string(), - referrerRestrictions: Joi.string(), - name: Joi.string(), - description: Joi.string(), - }, - "body" - ) - ) - async putUserApiKeys(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - const added = await createApiKeyForUser( - localsToTokenOrKey(res), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Get("scopes") - async getUserApiKeyScopes(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate( - { - id: Joi.number().required(), - }, - { id } - ); - return getGroupApiKeyScopesForUser(localsToTokenOrKey(res), id); - } - - @Get(":apiKeyId") - async getUserApiKey(req: Request, res: Response) { - const id = twtToId(req.params.id); - const apiKeyId = twtToId(req.params.apiKeyId); - joiValidate( - { - id: Joi.number().required(), - apiKeyId: Joi.number().required(), - }, - { id, apiKeyId } - ); - return getGroupApiKeyForUser(localsToTokenOrKey(res), id, apiKeyId); - } - - @Patch(":apiKeyId") - @Middleware( - validator( - { - scopes: Joi.array().items(Joi.string()).allow(null), - ipRestrictions: Joi.string().allow(null), - referrerRestrictions: Joi.string().allow(null), - name: Joi.string().allow(null), - description: Joi.string().allow(null), - }, - "body" - ) - ) - async patchUserApiKey(req: Request, res: Response) { - const id = twtToId(req.params.id); - const apiKeyId = twtToId(req.params.apiKeyId); - joiValidate( - { - id: Joi.number().required(), - apiKeyId: Joi.number().required(), - }, - { id, apiKeyId } - ); - const updated = await updateApiKeyForUser( - localsToTokenOrKey(res), - id, - apiKeyId, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":apiKeyId") - async deleteUserApiKey(req: Request, res: Response) { - const id = twtToId(req.params.id); - const apiKeyId = twtToId(req.params.apiKeyId); - joiValidate( - { - id: Joi.number().required(), - apiKeyId: Joi.number().required(), - }, - { id, apiKeyId } - ); - await deleteApiKeyForUser( - localsToTokenOrKey(res), - id, - apiKeyId, - res.locals - ); - return respond(RESOURCE_DELETED); - } - - @Get(":apiKeyId/logs") - async getUserApiKeyLogs(req: Request, res: Response) { - const id = twtToId(req.params.id); - const apiKeyId = twtToId(req.params.apiKeyId); - joiValidate( - { - id: Joi.number().required(), - apiKeyId: Joi.number().required(), - }, - { id, apiKeyId } - ); - return getGroupApiKeyLogsForUser( - localsToTokenOrKey(res), - id, - apiKeyId, - req.query - ); - } -} diff --git a/src/controllers/groups/_id/billing.ts b/src/controllers/groups/_id/billing.ts deleted file mode 100644 index cc9d27207..000000000 --- a/src/controllers/groups/_id/billing.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - ClassMiddleware, - Get, - Patch, - Request, - Response, - NextFunction, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - getGroupBillingForUser, - getGroupPricingPlansForUser, - updateGroupBillingForUser, -} from "../../../_staart/rest/group"; -import { config } from "@anandchowdhary/cosmic"; -import { safeError } from "../../../_staart/helpers/errors"; - -@ClassMiddleware(authHandler) -@ClassMiddleware(async (_: Request, res: Response, next: NextFunction) => { - if (!config("enableStripePayments")) { - const error = safeError("404/billing-not-enabled"); - res.status(error.status); - return res.json(error); - } else return next(); -}) -export class GroupBillingController { - @Get() - async getBilling(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - return getGroupBillingForUser(localsToTokenOrKey(res), groupId); - } - - @Patch() - async patchBilling(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - await updateGroupBillingForUser( - localsToTokenOrKey(res), - groupId, - req.body, - res.locals - ); - return { success: true, message: "group-billing-updated" }; - } - - @Get("pricing") - async getPlans(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate( - { - groupId: Joi.number().required(), - }, - { groupId } - ); - return getGroupPricingPlansForUser(localsToTokenOrKey(res), groupId); - } -} diff --git a/src/controllers/groups/_id/domains.ts b/src/controllers/groups/_id/domains.ts deleted file mode 100644 index 936f24179..000000000 --- a/src/controllers/groups/_id/domains.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Post, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - createDomainForUser, - deleteDomainForUser, - getGroupDomainForUser, - getGroupDomainsForUser, - updateDomainForUser, - verifyDomainForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupDomainsController { - @Get() - async getUserDomains(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getGroupDomainsForUser(localsToTokenOrKey(res), id, req.query); - } - - @Put() - @Middleware( - validator( - { - domain: Joi.string(), - }, - "body" - ) - ) - async putUserDomains(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - const added = await createDomainForUser( - localsToTokenOrKey(res), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Get(":domainId") - async getUserDomain(req: Request, res: Response) { - const id = twtToId(req.params.id); - const domainId = twtToId(req.params.domainId); - joiValidate( - { - id: Joi.number().required(), - domainId: Joi.number().required(), - }, - { id, domainId } - ); - return getGroupDomainForUser(localsToTokenOrKey(res), id, domainId); - } - - @Patch(":domainId") - @Middleware( - validator( - { - domain: Joi.string(), - }, - "body" - ) - ) - async patchUserDomain(req: Request, res: Response) { - const id = twtToId(req.params.id); - const domainId = twtToId(req.params.domainId); - joiValidate( - { - id: Joi.number().required(), - domainId: Joi.number().required(), - }, - { id, domainId } - ); - const updated = await updateDomainForUser( - localsToTokenOrKey(res), - id, - domainId, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":domainId") - async deleteUserDomain(req: Request, res: Response) { - const id = twtToId(req.params.id); - const domainId = twtToId(req.params.domainId); - joiValidate( - { - id: Joi.number().required(), - domainId: Joi.number().required(), - }, - { id, domainId } - ); - await deleteDomainForUser( - localsToTokenOrKey(res), - id, - domainId, - res.locals - ); - return respond(RESOURCE_DELETED); - } - - @Post(":domainId/verify") - async verifyGroupDomain(req: Request, res: Response) { - const id = twtToId(req.params.id); - const domainId = twtToId(req.params.domainId); - const method = req.body.method || req.query.method; - joiValidate( - { - id: Joi.number().required(), - domainId: Joi.number().required(), - method: Joi.string().allow("file", "dns").only(), - }, - { id, domainId, method } - ); - return await verifyDomainForUser( - localsToTokenOrKey(res), - id, - domainId, - method, - res.locals - ); - } -} diff --git a/src/controllers/groups/_id/index.ts b/src/controllers/groups/_id/index.ts deleted file mode 100644 index 8b8f668c0..000000000 --- a/src/controllers/groups/_id/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { RESOURCE_DELETED, RESOURCE_UPDATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - deleteGroupForUser, - getAllGroupDataForUser, - getGroupForUser, - updateGroupForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupController { - @Get() - async get(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - const group = await getGroupForUser(localsToTokenOrKey(res), id); - return group; - } - - @Patch() - @Middleware( - validator( - { - name: Joi.string(), - forceTwoFactor: Joi.boolean(), - autoJoinDomain: Joi.boolean(), - onlyAllowDomain: Joi.boolean(), - ipRestrictions: Joi.string(), - profilePictureUrl: Joi.string(), - }, - "body" - ) - ) - async patch(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - const updated = await updateGroupForUser( - localsToTokenOrKey(res), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED, { resource: "Team" }), updated }; - } - - @Delete() - async delete(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - await deleteGroupForUser(twtToId(res.locals.token.id), groupId, res.locals); - return respond(RESOURCE_DELETED); - } - - @Get("data") - async getData(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - return getAllGroupDataForUser(localsToTokenOrKey(res), groupId); - } -} diff --git a/src/controllers/groups/_id/invoices.ts b/src/controllers/groups/_id/invoices.ts deleted file mode 100644 index 6ea512c3a..000000000 --- a/src/controllers/groups/_id/invoices.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ClassMiddleware, Get, Request, Response } from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - getGroupInvoiceForUser, - getGroupInvoicesForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupInvoicesController { - @Get() - async getInvoices(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - const subscriptionParams = { ...req.query }; - joiValidate( - { - start: Joi.string(), - billing: Joi.string().valid("charge_automatically", "send_invoice"), - itemsPerPage: Joi.number(), - plan: Joi.string(), - status: Joi.string(), - }, - subscriptionParams - ); - return getGroupInvoicesForUser( - localsToTokenOrKey(res), - groupId, - subscriptionParams - ); - } - - @Get(":invoiceId") - async getInvoice(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const invoiceId = req.params.invoiceId; - joiValidate( - { - groupId: Joi.number().required(), - invoiceId: Joi.number().required(), - }, - { groupId, invoiceId } - ); - return getGroupInvoiceForUser(localsToTokenOrKey(res), groupId, invoiceId); - } -} diff --git a/src/controllers/groups/_id/memberships.ts b/src/controllers/groups/_id/memberships.ts deleted file mode 100644 index 32f029080..000000000 --- a/src/controllers/groups/_id/memberships.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { MembershipRole } from "@prisma/client"; -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - deleteGroupMembershipForUser, - getGroupMembershipForUser, - getGroupMembershipsForUser, - inviteMemberToGroup, - updateGroupMembershipForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupMembershipsController { - @Get() - async getMemberships(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - return getGroupMembershipsForUser( - localsToTokenOrKey(res), - groupId, - req.query - ); - } - - @Put() - async putMemberships(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const newMemberName = req.body.name; - const newMemberEmail = req.body.email; - const role = req.body.role; - joiValidate( - { - groupId: Joi.number().required(), - newMemberName: Joi.string().min(6).required(), - newMemberEmail: Joi.string().email().required(), - role: Joi.string().allow("ADMIN", "MEMBER").only(), - }, - { - groupId, - newMemberName, - newMemberEmail, - role, - } - ); - await inviteMemberToGroup( - localsToTokenOrKey(res), - groupId, - newMemberName, - newMemberEmail, - role || MembershipRole.MEMBER, - res.locals - ); - return respond(RESOURCE_CREATED); - } - - @Get(":membershipId") - async getMembership(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - groupId: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { groupId, membershipId } - ); - return getGroupMembershipForUser( - localsToTokenOrKey(res), - groupId, - membershipId - ); - } - - @Patch(":membershipId") - @Middleware( - validator( - { - role: Joi.string().allow("ADMIN", "MEMBER").only(), - }, - "body" - ) - ) - async updateMembership(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - groupId: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { groupId, membershipId } - ); - const updated = await updateGroupMembershipForUser( - localsToTokenOrKey(res), - groupId, - membershipId, - req.body - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":membershipId") - async deleteMembership(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - groupId: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { groupId, membershipId } - ); - await deleteGroupMembershipForUser( - localsToTokenOrKey(res), - groupId, - membershipId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/groups/_id/sources.ts b/src/controllers/groups/_id/sources.ts deleted file mode 100644 index 01522534f..000000000 --- a/src/controllers/groups/_id/sources.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - createGroupSourceForUser, - deleteGroupSourceForUser, - getGroupSourceForUser, - getGroupSourcesForUser, - updateGroupSourceForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupSourcesController { - @Get() - async getSources(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - const subscriptionParams = { ...req.query }; - joiValidate( - { - start: Joi.string(), - itemsPerPage: Joi.number(), - }, - subscriptionParams - ); - return getGroupSourcesForUser( - localsToTokenOrKey(res), - groupId, - subscriptionParams - ); - } - - @Put() - async putSources(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - await createGroupSourceForUser( - localsToTokenOrKey(res), - groupId, - req.body, - res.locals - ); - return respond(RESOURCE_CREATED); - } - - @Get(":sourceId") - async getSource(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const sourceId = req.params.sourceId; - joiValidate( - { - groupId: Joi.number().required(), - sourceId: Joi.number().required(), - }, - { groupId, sourceId } - ); - return getGroupSourceForUser(localsToTokenOrKey(res), groupId, sourceId); - } - - @Patch(":sourceId") - async patchSource(req: Request, res: Response) { - const sourceId = req.params.sourceId; - const groupId = twtToId(req.params.id); - joiValidate( - { - groupId: Joi.number().required(), - sourceId: Joi.number().required(), - }, - { groupId, sourceId } - ); - const updated = await updateGroupSourceForUser( - localsToTokenOrKey(res), - groupId, - sourceId, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":sourceId") - async deleteSource(req: Request, res: Response) { - const sourceId = req.params.sourceId; - const groupId = twtToId(req.params.id); - joiValidate( - { - groupId: Joi.number().required(), - sourceId: Joi.number().required(), - }, - { groupId, sourceId } - ); - await deleteGroupSourceForUser( - localsToTokenOrKey(res), - groupId, - sourceId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/groups/_id/subscriptions.ts b/src/controllers/groups/_id/subscriptions.ts deleted file mode 100644 index f09f7f794..000000000 --- a/src/controllers/groups/_id/subscriptions.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { RESOURCE_CREATED, RESOURCE_UPDATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Get, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - createGroupSubscriptionForUser, - getGroupSubscriptionForUser, - getGroupSubscriptionsForUser, - updateGroupSubscriptionForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupSubscriptionsController { - @Get() - async getSubscriptions(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - const subscriptionParams = { ...req.query }; - joiValidate( - { - start: Joi.string(), - billing: Joi.string().valid("charge_automatically", "send_invoice"), - itemsPerPage: Joi.number(), - plan: Joi.string(), - status: Joi.string(), - }, - subscriptionParams - ); - return getGroupSubscriptionsForUser( - localsToTokenOrKey(res), - groupId, - subscriptionParams - ); - } - - @Put() - async putSubscriptions(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - const subscriptionParams = { ...req.body }; - joiValidate( - { - plan: Joi.string().required(), - billing: Joi.string().valid("charge_automatically", "send_invoice"), - tax_percent: Joi.number(), - number_of_seats: Joi.number(), - }, - subscriptionParams - ); - await createGroupSubscriptionForUser( - localsToTokenOrKey(res), - groupId, - subscriptionParams, - res.locals - ); - return respond(RESOURCE_CREATED); - } - - @Get(":subscriptionId") - async getSubscription(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const subscriptionId = req.params.subscriptionId; - joiValidate( - { - groupId: Joi.number().required(), - subscriptionId: Joi.number().required(), - }, - { groupId, subscriptionId } - ); - return getGroupSubscriptionForUser( - localsToTokenOrKey(res), - groupId, - subscriptionId - ); - } - - @Patch(":subscriptionId") - async patchSubscription(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const subscriptionId = req.params.subscriptionId; - const data = req.body; - joiValidate( - { - groupId: Joi.number().required(), - subscriptionId: Joi.number().required(), - }, - { groupId, subscriptionId } - ); - joiValidate( - { - billing: Joi.string().valid("charge_automatically", "send_invoice"), - cancel_at_period_end: Joi.boolean(), - coupon: Joi.string(), - default_source: Joi.string(), - items: Joi.array(), - proration_behavior: Joi.string(), - }, - data - ); - await updateGroupSubscriptionForUser( - localsToTokenOrKey(res), - groupId, - subscriptionId, - data, - res.locals - ); - return respond(RESOURCE_UPDATED); - } -} diff --git a/src/controllers/groups/_id/transactions.ts b/src/controllers/groups/_id/transactions.ts deleted file mode 100644 index 870ba6f75..000000000 --- a/src/controllers/groups/_id/transactions.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ClassMiddleware, Get, Put, Request, Response } from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - applyCouponToGroupForUser, - getGroupTransactionForUser, - getGroupTransactionsForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupTransactionsController { - @Get() - async getTransactions(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - joiValidate({ groupId: Joi.number().required() }, { groupId }); - const transactionParams = { ...req.query }; - joiValidate( - { - start: Joi.string(), - itemsPerPage: Joi.number(), - }, - transactionParams - ); - return getGroupTransactionsForUser( - localsToTokenOrKey(res), - groupId, - transactionParams - ); - } - - @Put() - async applyCoupon(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const couponCode = req.body.couponCode; - joiValidate( - { - groupId: Joi.number().required(), - couponCode: Joi.string().required(), - }, - { groupId, couponCode } - ); - return applyCouponToGroupForUser( - localsToTokenOrKey(res), - groupId, - couponCode - ); - } - - @Get(":transactionId") - async getTransaction(req: Request, res: Response) { - const groupId = twtToId(req.params.id); - const transactionId = req.params.transactionId; - joiValidate( - { - groupId: Joi.number().required(), - transactionId: Joi.number().required(), - }, - { groupId, transactionId } - ); - return getGroupTransactionForUser( - localsToTokenOrKey(res), - groupId, - transactionId - ); - } -} diff --git a/src/controllers/groups/_id/webhooks.ts b/src/controllers/groups/_id/webhooks.ts deleted file mode 100644 index 8233c914b..000000000 --- a/src/controllers/groups/_id/webhooks.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId, localsToTokenOrKey } from "../../../_staart/helpers/utils"; -import { - createWebhookForUser, - deleteWebhookForUser, - getGroupWebhookForUser, - getGroupWebhooksForUser, - updateWebhookForUser, -} from "../../../_staart/rest/group"; - -@ClassMiddleware(authHandler) -export class GroupWebhooksController { - @Get() - async getGroupWebhooks(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getGroupWebhooksForUser(localsToTokenOrKey(res), id, req.query); - } - - @Put() - @Middleware( - validator( - { - event: Joi.string().required(), - url: Joi.string().uri().required(), - contentType: Joi.string(), - secret: Joi.string().allow(), - isActive: Joi.boolean(), - }, - "body" - ) - ) - async putGroupWebhooks(req: Request, res: Response) { - const id = twtToId(req.params.id); - joiValidate({ id: Joi.number().required() }, { id }); - const added = await createWebhookForUser( - localsToTokenOrKey(res), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Get(":webhookId") - async getGroupWebhook(req: Request, res: Response) { - const id = twtToId(req.params.id); - const webhookId = twtToId(req.params.webhookId); - joiValidate( - { - id: Joi.number().required(), - webhookId: Joi.number().required(), - }, - { id, webhookId } - ); - return getGroupWebhookForUser(localsToTokenOrKey(res), id, webhookId); - } - - @Patch(":webhookId") - @Middleware( - validator( - { - event: Joi.string(), - url: Joi.string().uri(), - contentType: Joi.string(), - secret: Joi.string(), - isActive: Joi.boolean(), - }, - "body" - ) - ) - async patchGroupWebhook(req: Request, res: Response) { - const id = twtToId(req.params.id); - const webhookId = twtToId(req.params.webhookId); - joiValidate( - { - id: Joi.number().required(), - webhookId: Joi.number().required(), - }, - { id, webhookId } - ); - const updated = await updateWebhookForUser( - localsToTokenOrKey(res), - id, - webhookId, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":webhookId") - async deleteGroupWebhook(req: Request, res: Response) { - const id = twtToId(req.params.id); - const webhookId = twtToId(req.params.webhookId); - joiValidate( - { - id: Joi.number().required(), - webhookId: Joi.number().required(), - }, - { id, webhookId } - ); - await deleteWebhookForUser( - localsToTokenOrKey(res), - id, - webhookId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/groups/index.ts b/src/controllers/groups/index.ts deleted file mode 100644 index 6a338a7d0..000000000 --- a/src/controllers/groups/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { RESOURCE_CREATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Middleware, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi } from "@staart/validate"; -import { authHandler, validator } from "../../_staart/helpers/middleware"; -import { newGroupForUser } from "../../_staart/rest/group"; -import { twtToId } from "../../_staart/helpers/utils"; - -@ClassMiddleware(authHandler) -export class GroupController { - @Put() - @Middleware( - validator( - { - name: Joi.string().required(), - }, - "body" - ) - ) - async put(req: Request, res: Response) { - const added = await newGroupForUser( - twtToId(res.locals.token.id), - req.body, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } -} diff --git a/src/controllers/users/_id/access-tokens.ts b/src/controllers/users/_id/access-tokens.ts deleted file mode 100644 index 79962fb17..000000000 --- a/src/controllers/users/_id/access-tokens.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_UPDATED, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - createAccessTokenForUser, - deleteAccessTokenForUser, - getUserAccessTokenForUser, - getUserAccessTokensForUser, - updateAccessTokenForUser, - getUserAccessTokenScopesForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserAccessTokensController { - @Get() - async getUserAccessTokens(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getUserAccessTokensForUser( - twtToId(res.locals.token.id), - id, - req.query - ); - } - - @Put() - @Middleware( - validator( - { - scopes: Joi.array().items(Joi.string()), - name: Joi.string(), - description: Joi.string(), - }, - "body" - ) - ) - async putUserAccessTokens(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - try { - const added = await createAccessTokenForUser( - twtToId(res.locals.token.id), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } catch (error) { - console.log(error); - return {}; - } - } - - @Get(":accessTokenId") - async getUserAccessToken(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const accessTokenId = twtToId(req.params.accessTokenId); - joiValidate( - { - id: Joi.number().required(), - accessTokenId: Joi.number().required(), - }, - { id, accessTokenId } - ); - return getUserAccessTokenForUser( - twtToId(res.locals.token.id), - id, - accessTokenId - ); - } - - @Patch(":accessTokenId") - @Middleware( - validator( - { - scopes: Joi.array().items(Joi.string()).allow(null), - name: Joi.string().allow(null), - description: Joi.string().allow(null), - }, - "body" - ) - ) - async patchUserAccessToken(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const accessTokenId = twtToId(req.params.accessTokenId); - joiValidate( - { - id: Joi.number().required(), - accessTokenId: Joi.number().required(), - }, - { id, accessTokenId } - ); - const updated = await updateAccessTokenForUser( - twtToId(res.locals.token.id), - id, - accessTokenId, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete(":accessTokenId") - async deleteUserAccessToken(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const accessTokenId = twtToId(req.params.accessTokenId); - joiValidate( - { - id: Joi.number().required(), - accessTokenId: Joi.number().required(), - }, - { id, accessTokenId } - ); - await deleteAccessTokenForUser( - twtToId(res.locals.token.id), - id, - accessTokenId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/users/_id/emails.ts b/src/controllers/users/_id/emails.ts deleted file mode 100644 index 354ef1b44..000000000 --- a/src/controllers/users/_id/emails.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_SUCCESS, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Post, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - addEmailToUserForUser, - deleteEmailFromUserForUser, - getAllEmailsForUser, - getEmailForUser, - resendEmailVerificationForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserEmailsController { - @Get() - async getEmails(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getAllEmailsForUser(twtToId(res.locals.token.id), id, req.query); - } - - @Put() - async putEmails(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const email = req.body.email; - joiValidate( - { - id: Joi.number().required(), - email: Joi.string().email().required(), - }, - { id, email } - ); - const added = await addEmailToUserForUser( - twtToId(res.locals.token.id), - id, - email, - res.locals - ); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Get(":emailId") - async getEmail(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const emailId = twtToId(req.params.emailId); - joiValidate( - { - id: Joi.number().required(), - emailId: Joi.number().required(), - }, - { id, emailId } - ); - return getEmailForUser(twtToId(res.locals.token.id), id, emailId); - } - - @Post(":emailId/resend") - async postResend(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const emailId = twtToId(req.params.emailId); - joiValidate( - { - id: Joi.number().required(), - emailId: Joi.number().required(), - }, - { id, emailId } - ); - await resendEmailVerificationForUser( - twtToId(res.locals.token.id), - id, - emailId - ); - return respond(RESOURCE_SUCCESS); - } - - @Delete(":emailId") - async deleteEmail(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const emailId = twtToId(req.params.emailId); - joiValidate( - { - id: Joi.number().required(), - emailId: Joi.number().required(), - }, - { id, emailId } - ); - await deleteEmailFromUserForUser( - twtToId(res.locals.token.id), - id, - emailId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/users/_id/identities.ts b/src/controllers/users/_id/identities.ts deleted file mode 100644 index db9e08396..000000000 --- a/src/controllers/users/_id/identities.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - RESOURCE_CREATED, - RESOURCE_DELETED, - RESOURCE_SUCCESS, - respond, -} from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Post, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - connectUserIdentityForUser, - createUserIdentityForUser, - deleteIdentityForUser, - getUserIdentitiesForUser, - getUserIdentityForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserIdentitiesController { - @Get() - async getUserIdentities(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getUserIdentitiesForUser( - twtToId(res.locals.token.id), - id, - req.query - ); - } - - @Put() - async createUserIdentity(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - const added = await createUserIdentityForUser( - twtToId(res.locals.token.id), - id, - req.body - ); - return { ...respond(RESOURCE_CREATED), added }; - } - - @Post(":service") - async connectUserIdentity(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - const service = req.params.service; - const url = req.body.url; - joiValidate( - { service: Joi.string().required(), url: Joi.string().required() }, - { service, url } - ); - await connectUserIdentityForUser( - twtToId(res.locals.token.id), - id, - service, - url - ); - return respond(RESOURCE_SUCCESS); - } - - @Get(":identityId") - async getUserIdentity(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const identityId = twtToId(req.params.identityId); - joiValidate( - { - id: Joi.number().required(), - identityId: Joi.number().required(), - }, - { id, identityId } - ); - return getUserIdentityForUser(twtToId(res.locals.token.id), id, identityId); - } - - @Delete(":identityId") - async deleteUserIdentity(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const identityId = twtToId(req.params.identityId); - joiValidate( - { - id: Joi.number().required(), - identityId: Joi.number().required(), - }, - { id, identityId } - ); - await deleteIdentityForUser( - twtToId(res.locals.token.id), - id, - identityId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/users/_id/index.ts b/src/controllers/users/_id/index.ts deleted file mode 100644 index d888ba177..000000000 --- a/src/controllers/users/_id/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { RESOURCE_DELETED, RESOURCE_UPDATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Patch, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - deleteUserForUser, - getUserFromIdForUser, - updateUserForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserController { - @Get() - async get(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getUserFromIdForUser(id, twtToId(res.locals.token.id), req.query); - } - - @Patch() - @Middleware( - validator( - { - name: Joi.string() - .min(3) - .regex(/^[a-zA-Z ]*$/), - nickname: Joi.string(), - prefersEmailId: [Joi.string(), Joi.number()], - countryCode: Joi.string().length(2), - password: Joi.string().min(6), - gender: Joi.string() - .allow("MALE", "FEMALE", "NONBINARY", "UNKNOWN") - .only(), - timezone: Joi.string(), - notificationEmails: Joi.string() - .allow("ACCOUNT", "UPDATES", "PROMOTIONS") - .only(), - prefersLanguage: Joi.string().min(2).max(5), - prefersReducedMotion: Joi.string() - .allow("NO_PREFERENCE", "REDUCE") - .only(), - prefersColorScheme: Joi.string() - .allow("NO_PREFERENCE", "LIGHT", "DARK") - .only(), - profilePictureUrl: Joi.string(), - checkLocationOnLogin: Joi.boolean(), - }, - "body" - ) - ) - async patch(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - const updated = await updateUserForUser( - twtToId(res.locals.token.id), - id, - req.body, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } - - @Delete() - async delete(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - await deleteUserForUser(twtToId(res.locals.token.id), id, res.locals); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/users/_id/memberships.ts b/src/controllers/users/_id/memberships.ts deleted file mode 100644 index ede4657fb..000000000 --- a/src/controllers/users/_id/memberships.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { RESOURCE_DELETED, RESOURCE_UPDATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Patch, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - deleteMembershipForUser, - getMembershipDetailsForUser, - getMembershipsForUser, - updateMembershipForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserMembershipsController { - @Get() - async getMemberships(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getMembershipsForUser(twtToId(res.locals.token.id), id, req.query); - } - - @Get(":membershipId") - async getMembership(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - id: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { id, membershipId } - ); - return getMembershipDetailsForUser(id, membershipId); - } - - @Delete(":membershipId") - async deleteMembership(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - id: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { id, membershipId } - ); - await deleteMembershipForUser(id, membershipId, res.locals); - return respond(RESOURCE_DELETED); - } - - @Patch(":membershipId") - async updateMembership(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const membershipId = twtToId(req.params.membershipId); - joiValidate( - { - id: Joi.number().required(), - membershipId: Joi.number().required(), - }, - { id, membershipId } - ); - const data = req.body; - delete req.body.id; - const updated = await updateMembershipForUser( - id, - membershipId, - data, - res.locals - ); - return { ...respond(RESOURCE_UPDATED), updated }; - } -} diff --git a/src/controllers/users/_id/security.ts b/src/controllers/users/_id/security.ts deleted file mode 100644 index fc82794ff..000000000 --- a/src/controllers/users/_id/security.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { RESOURCE_SUCCESS, RESOURCE_UPDATED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Middleware, - Post, - Put, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler, validator } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - disable2FAForUser, - enable2FAForUser, - getAllDataForUser, - regenerateBackupCodesForUser, - updatePasswordForUser, - verify2FAForUser, - getPasswordForUser, - getUserAccessTokenScopesForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserSecurityController { - @Put("password") - @Middleware( - validator( - { - oldPassword: Joi.string().allow("").optional(), - newPassword: Joi.string().min(6).required(), - }, - "body" - ) - ) - async updatePassword(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const oldPassword = req.body.oldPassword; - const newPassword = req.body.newPassword; - joiValidate( - { - id: Joi.number().required(), - }, - { id } - ); - await updatePasswordForUser( - twtToId(res.locals.token.id), - id, - oldPassword, - newPassword, - res.locals - ); - return respond(RESOURCE_UPDATED); - } - - @Get("password") - async getPassword(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getPasswordForUser(twtToId(res.locals.token.id), id); - } - - @Get("data") - async getUserData(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getAllDataForUser(twtToId(res.locals.token.id), id); - } - - @Get("2fa/enable") - async getEnable2FA(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return enable2FAForUser(twtToId(res.locals.token.id), id); - } - - @Post("2fa/verify") - async postVerify2FA(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const code = req.body.code; - joiValidate( - { - id: Joi.number().required(), - code: Joi.number().min(5).required(), - }, - { id, code } - ); - const backupCodes = await verify2FAForUser( - twtToId(res.locals.token.id), - id, - code - ); - return { ...respond(RESOURCE_SUCCESS), backupCodes }; - } - - @Delete("2fa") - async delete2FA(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - await disable2FAForUser(twtToId(res.locals.token.id), id); - return respond(RESOURCE_SUCCESS); - } - - @Get("backup-codes/regenerate") - async getRegenerateBackupCodes(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - const backupCodes = await regenerateBackupCodesForUser( - twtToId(res.locals.token.id), - id - ); - return { ...respond(RESOURCE_SUCCESS), backupCodes }; - } - - @Get("access-token-scopes") - async getUserAccessTokenScopes(req: Request, res: Response) { - return getUserAccessTokenScopesForUser(twtToId(res.locals.token.id)); - } -} diff --git a/src/controllers/users/_id/sessions.ts b/src/controllers/users/_id/sessions.ts deleted file mode 100644 index 2855e2aaf..000000000 --- a/src/controllers/users/_id/sessions.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { RESOURCE_DELETED, respond } from "@staart/messages"; -import { - ClassMiddleware, - Delete, - Get, - Request, - Response, -} from "@staart/server"; -import { Joi, joiValidate } from "@staart/validate"; -import { authHandler } from "../../../_staart/helpers/middleware"; -import { twtToId } from "../../../_staart/helpers/utils"; -import { - deleteSessionForUser, - getUserSessionForUser, - getUserSessionsForUser, -} from "../../../_staart/rest/user"; - -@ClassMiddleware(authHandler) -export class UserSessionsController { - @Get() - async getUserSessions(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - joiValidate({ id: Joi.number().required() }, { id }); - return getUserSessionsForUser(twtToId(res.locals.token.id), id, req.query); - } - - @Get(":sessionId") - async getUserSession(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const sessionId = twtToId(req.params.sessionId); - joiValidate( - { - id: Joi.number().required(), - sessionId: Joi.number().required(), - }, - { id, sessionId } - ); - return getUserSessionForUser(twtToId(res.locals.token.id), id, sessionId); - } - - @Delete(":sessionId") - async deleteUserSession(req: Request, res: Response) { - const id = twtToId(req.params.id, res.locals.token.id); - const sessionId = twtToId(req.params.sessionId); - joiValidate( - { - id: Joi.number().required(), - sessionId: Joi.number().required(), - }, - { id, sessionId } - ); - await deleteSessionForUser( - twtToId(res.locals.token.id), - id, - sessionId, - res.locals - ); - return respond(RESOURCE_DELETED); - } -} diff --git a/src/controllers/webhooks/index.ts b/src/controllers/webhooks/index.ts deleted file mode 100644 index a947cb5c3..000000000 --- a/src/controllers/webhooks/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Get, Middleware, Request, Response } from "@staart/server"; -import { stripeWebhookAuthHandler } from "../../_staart/helpers/middleware"; -import { StripeLocals } from "../../_staart/interfaces/general"; - -export class WebhooksController { - @Get("stripe") - @Middleware(stripeWebhookAuthHandler) - async stripeWebhook(req: Request, res: Response) { - const locals = res.locals as StripeLocals; - console.log("Received Stripe event", locals.stripeEvent); - return { hello: "world" }; - } -} diff --git a/src/crons/daily.ts b/src/crons/daily.ts deleted file mode 100644 index 63c34f57b..000000000 --- a/src/crons/daily.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { elasticSearch, elasticSearchEnabled } from "@staart/elasticsearch"; -import { ms } from "@staart/text"; -import { CronJob } from "cron"; -const ELASTIC_LOGS_INDEX = config("elasticLogsIndex"); - -export default () => { - new CronJob( - "0 0 * * *", - async () => { - await deleteOldLogs(); - }, - undefined, - true - ); -}; - -const deleteOldLogs = async () => { - if (elasticSearchEnabled) - return ( - await elasticSearch.deleteByQuery({ - index: ELASTIC_LOGS_INDEX, - body: { - query: { - bool: { - must: [ - { - range: { - date: { - lte: new Date(new Date().getTime() - ms("92 days")), - }, - }, - }, - ], - }, - }, - }, - }) - ).body; -}; diff --git a/src/crons/hourly.ts b/src/crons/hourly.ts deleted file mode 100644 index 63c2b10e1..000000000 --- a/src/crons/hourly.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { config } from "@anandchowdhary/cosmic"; -import { ms } from "@staart/text"; -import { CronJob } from "cron"; -import { prisma } from "../_staart/helpers/prisma"; -const TOKEN_EXPIRY_REFRESH = config("tokenExpiryRefresh"); - -export default () => { - new CronJob( - "0 * * * *", - async () => { - await deleteExpiredSessions(); - }, - undefined, - true - ); -}; - -const deleteExpiredSessions = async () => { - await prisma.sessions.deleteMany({ - where: { - createdAt: { - lte: new Date(new Date().getTime() - ms(TOKEN_EXPIRY_REFRESH)), - }, - }, - }); -}; diff --git a/src/crons/minute.ts b/src/crons/minute.ts deleted file mode 100644 index 036996a7a..000000000 --- a/src/crons/minute.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { error } from "@staart/errors"; -import { CronJob } from "cron"; -import { - elasticSearchIndex, - receiveElasticSearchMessage, -} from "../_staart/helpers/elasticsearch"; -import { receiveEmailMessage } from "../_staart/helpers/mail"; -import { - clearSecurityEventsData, - clearTrackingData, - getSecurityEvents, - getTrackingData, -} from "../_staart/helpers/tracking"; -import { IdValues } from "../_staart/helpers/utils"; -import { receiveWebhookMessage } from "../_staart/helpers/webhooks"; -import { config } from "@anandchowdhary/cosmic"; - -const ELASTIC_EVENTS_INDEX = config("elasticEventsIndex"); -const ELASTIC_LOGS_INDEX = config("elasticLogsIndex"); - -/** - * We run this cron job every minute in production - * but every 10 seconds in development - */ -export default () => { - new CronJob( - config("nodeEnv") === "production" - ? "* * * * *" - : config("devCronMinute") ?? "*/10 * * * * *", - async () => { - await receiveEmailMessage(); - await receiveElasticSearchMessage(); - await receiveWebhookMessage(); - await storeTrackingLogs(); - await storeSecurityEvents(); - }, - undefined, - true - ); -}; - -const storeSecurityEvents = async () => { - if (!config("trackAuditLogData")) return; - const data = getSecurityEvents(); - if (!data.length) return; - for await (const body of data) { - if (typeof body === "object") { - Object.keys(body).forEach((key) => { - if (IdValues.includes(key)) body[key] = body[key]; - }); - if (body.data && typeof body.data === "object") { - Object.keys(body.data).forEach((key) => { - if (IdValues.includes(key)) body.data[key] = body.data[key]; - }); - } - } - try { - await elasticSearchIndex({ - index: ELASTIC_EVENTS_INDEX, - body, - }); - } catch (err) { - error("Got error in saving to ElasticSearch", JSON.stringify(err)); - } - } - clearSecurityEventsData(); -}; - -const storeTrackingLogs = async () => { - if (!config("trackRequestData")) return; - const data = getTrackingData(); - if (!data.length) return; - for await (const body of data) { - try { - if (typeof body === "object") { - Object.keys(body).forEach((key) => { - if (IdValues.includes(key)) body[key] = body[key]; - }); - if (body.data && typeof body.data === "object") { - Object.keys(body.data).forEach((key) => { - if (IdValues.includes(key)) body.data[key] = body.data[key]; - }); - } - } - await elasticSearchIndex({ - index: ELASTIC_LOGS_INDEX, - body, - }); - } catch (err) { - error("Got error in saving to ElasticSearch", JSON.stringify(err)); - } - } - clearTrackingData(); -}; diff --git a/src/errors/errors.constants.ts b/src/errors/errors.constants.ts new file mode 100644 index 000000000..3acfecb26 --- /dev/null +++ b/src/errors/errors.constants.ts @@ -0,0 +1,51 @@ +export const USER_NOT_FOUND = '404001: User not found'; +export const GROUP_NOT_FOUND = '404002: Group not found'; +export const SESSION_NOT_FOUND = '404003: Session not found'; +export const EMAIL_NOT_FOUND = '404004: Email not found'; +export const API_KEY_NOT_FOUND = '404005: API key not found'; +export const APPROVED_SUBNET_NOT_FOUND = '404006: Approved subnet not found'; +export const AUDIT_LOG_NOT_FOUND = '404007: Audit log not found'; +export const DOMAIN_NOT_FOUND = '404008: Domain not found'; +export const MEMBERSHIP_NOT_FOUND = '404009: Membership not found'; +export const BILLING_NOT_FOUND = '404010: Billing not found'; +export const CUSTOMER_NOT_FOUND = '404011: Customer not found'; +export const INVOICE_NOT_FOUND = '404012: Invoice not found'; +export const SUBSCRIPTION_NOT_FOUND = '404013: Subscription not found'; +export const SOURCE_NOT_FOUND = '404014: Source not found'; +export const WEBHOOK_NOT_FOUND = '404015: Webhook not found'; + +export const UNAUTHORIZED_RESOURCE = '401000: Insufficient permission'; +export const INVALID_CREDENTIALS = '401001: Invalid credentials'; +export const INVALID_MFA_CODE = '401002: Invalid one-time code'; +export const INVALID_TOKEN = '401003: Invalid token'; +export const UNVERIFIED_EMAIL = '401004: Email is not verified'; +export const UNVERIFIED_LOCATION = '401005: Location is not verified'; +export const MFA_BACKUP_CODE_USED = '401007: Backup code is already used'; + +export const NO_TOKEN_PROVIDED = '400001: No token provided'; +export const DOMAIN_NOT_VERIFIED = '400002: Domain not verified'; +export const MFA_PHONE_NOT_FOUND = '400003: Phone number not found'; +export const MFA_PHONE_OR_TOKEN_REQUIRED = + '400004: Phone number or token is required'; +export const MFA_NOT_ENABLED = + '400005: Multi-factor authentication is not enabled'; +export const NO_EMAILS = '400006: User has no email attached to it'; + +export const EMAIL_USER_CONFLICT = + '409001: User with this email already exists'; +export const EMAIL_VERIFIED_CONFLICT = '409002: This email is already verified'; +export const BILLING_ACCOUNT_CREATED_CONFLICT = + '409003: Billing account is already created'; +export const MFA_ENABLED_CONFLICT = + '409004: Multi-factor authentication is already enabled'; +export const CURRENT_PASSWORD_REQUIRED = '409005: Current password is required'; +export const COMPROMISED_PASSWORD = + '409006: This password has been compromised in a data breach.'; +export const CANNOT_DELETE_SOLE_MEMBER = + '409007: Cannot remove the only member'; +export const CANNOT_DELETE_SOLE_OWNER = '409008: Cannot remove the only owner'; +export const ORDER_BY_ASC_DESC = '409009: Invalid sorting order'; +export const ORDER_BY_FORMAT = '409010: Invalid ordering format'; +export const WHERE_PIPE_FORMAT = '409011: Invalid query format'; +export const OPTIONAL_INT_PIPE_NUMBER = '409012: $key should be a number'; +export const CURSOR_PIPE_FORMAT = '409013: Invalid cursor format'; diff --git a/src/helpers/parse-object-literal.ts b/src/helpers/parse-object-literal.ts new file mode 100644 index 000000000..11200619b --- /dev/null +++ b/src/helpers/parse-object-literal.ts @@ -0,0 +1,81 @@ +/** + * Parse a string like "a: 1, b: 2" to { a: 1, b: 2 } + * @param objectLiteralString - String to parse + * @source https://github.com/mbest/js-object-literal-parse + */ +export const parseObjectLiteral = ( + objectLiteralString: string, +): [string, string | undefined][] => { + const stringDouble = '"(?:[^"\\\\]|\\\\.)*"'; + const stringSingle = "'(?:[^'\\\\]|\\\\.)*'"; + const stringRegexp = '/(?:[^/\\\\]|\\\\.)*/w*'; + const specials = ',"\'{}()/:[\\]'; + const everyThingElse = '[^\\s:,/][^' + specials + ']*[^\\s' + specials + ']'; + const oneNotSpace = '[^\\s]'; + const token = RegExp( + stringDouble + + '|' + + stringSingle + + '|' + + stringRegexp + + '|' + + everyThingElse + + '|' + + oneNotSpace, + 'g', + ); + const divisionLookBehind = /[\])"'A-Za-z0-9_$]+$/; + const keywordRegexLookBehind: Record = { + in: 1, + return: 1, + typeof: 1, + }; + let str = objectLiteralString.trim(); + if (str.charCodeAt(0) === 123) str = str.slice(1, -1); + const result: [string, string | undefined][] = []; + let toks = str.match(token) as RegExpMatchArray; + if (!toks) return result; + let key: string | undefined = undefined; + let values = []; + let depth = 0; + toks.push(','); + for (let i = 0, tok: string; (tok = toks[i]); ++i) { + const c = tok.charCodeAt(0); + if (c === 44) { + if (depth <= 0) { + if (!key && values.length === 1) { + key = values.pop(); + } + if (key) + result.push([key, values.length ? values.join('') : undefined]); + key = undefined; + values = []; + depth = 0; + continue; + } + } else if (c === 58) { + if (!depth && !key && values.length === 1) { + key = values.pop(); + continue; + } + } else if (c === 47 && i && tok.length > 1) { + const match = toks[i - 1].match(divisionLookBehind); + if (match && !keywordRegexLookBehind[match[0]]) { + str = str.substr(str.indexOf(tok) + 1); + const result = str.match(token); + if (result) toks = result; + toks.push(','); + i = -1; + tok = '/'; + } + } else if (c === 40 || c === 123 || c === 91) { + ++depth; + } else if (c === 41 || c === 125 || c === 93) { + --depth; + } else if (!key && !values.length && (c === 34 || c === 39)) { + tok = tok.slice(1, -1); + } + values.push(tok); + } + return result; +}; diff --git a/src/helpers/safe-email.ts b/src/helpers/safe-email.ts new file mode 100644 index 000000000..d598f0af7 --- /dev/null +++ b/src/helpers/safe-email.ts @@ -0,0 +1,9 @@ +import normalize from 'normalize-email'; + +/** + * Converts an email address to a unqiue, safe email + * @param email - Valid email address + */ +export const safeEmail = (input: string) => { + return normalize(input.toLowerCase().trim()); +}; diff --git a/src/init-tests.ts b/src/init-tests.ts deleted file mode 100644 index 6d017c4cb..000000000 --- a/src/init-tests.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { logError, success, warn, info } from "@staart/errors"; -import { sendMail, setupTransporter } from "@staart/mail"; -import { elasticSearchIndex } from "./_staart/helpers/elasticsearch"; -import { receiveEmailMessage } from "./_staart/helpers/mail"; -import { prisma } from "./_staart/helpers/prisma"; -import { elasticSearchEnabled } from "@staart/elasticsearch"; -import { getProductPricing } from "@staart/payments"; -import { redis } from "@staart/redis"; -import { init } from "@sentry/node"; -import pkg from "../package.json"; -import { config } from "@anandchowdhary/cosmic"; - -const ELASTIC_INSTANCES_INDEX = config("elasticInstancesIndex"); -const TEST_EMAIL = config("testEmail"); - -if (config("sentryDsn")) init({ dsn: config("sentryDsn") }); - -let numberOfFailedTests = 0; -interface Test { - name: string; - test(): Promise; -} - -class Redis implements Test { - name = "Redis"; - async test() { - await redis.set(pkg.name, "redis"); - await redis.del(pkg.name); - } -} -class RedisQueue implements Test { - name = "Redis Message Queue"; - async test() { - await receiveEmailMessage(); - } -} - -class Database implements Test { - name = "Database connection"; - async test() { - await prisma.users.findMany({ take: 1 }); - } -} - -class Stripe implements Test { - name = "Stripe"; - async test() { - if (!config("enableStripePayments")) return info("Skipped"); - const prices = await getProductPricing(); - success(`Got ${prices.data.length} pricing plans`); - } -} - -class Email implements Test { - name = "Email"; - async test() { - setupTransporter(); - await sendMail({ - to: TEST_EMAIL, - subject: "Test from Staart", - message: `This is an example email to test your Staart email configuration.\n\n${JSON.stringify( - { - package: { - name: pkg.name, - version: pkg.version, - repository: pkg.repository, - author: pkg.author, - "staart-version": pkg["staart-version"], - }, - } - )}`, - }); - } -} - -class ElasticSearch implements Test { - name = "ElasticSearch"; - async test() { - if (!elasticSearchEnabled) { - warn("ElasticSearch is disabled"); - return; - } - await elasticSearchIndex({ - index: ELASTIC_INSTANCES_INDEX, - body: { - name: pkg.name, - version: pkg.version, - repository: pkg.repository, - author: pkg.author, - "staart-version": pkg["staart-version"], - }, - }); - } -} - -const runTests = async () => { - for await (const TestClass of [ - Redis, - RedisQueue, - Database, - Email, - Stripe, - ElasticSearch, - ]) { - const testClass = new TestClass(); - try { - await testClass.test(); - success(testClass.name, "Test passed"); - } catch (error) { - numberOfFailedTests += 1; - logError(testClass.name, "Test failed", 1); - console.log(error); - } - } -}; - -console.log(); -runTests() - .then(() => - numberOfFailedTests === 0 - ? success("All service tests passed") - : logError("Service tests", "All service tests passed", 1) - ) - .catch((error) => console.log("ERROR", error)); diff --git a/src/interceptors/audit-log.interceptor.ts b/src/interceptors/audit-log.interceptor.ts new file mode 100644 index 000000000..57b8e1658 --- /dev/null +++ b/src/interceptors/audit-log.interceptor.ts @@ -0,0 +1,80 @@ +import { + BadGatewayException, + CallHandler, + ExecutionContext, + Injectable, + Logger, + NestInterceptor, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { auditLogsCreateInput } from '@prisma/client'; +import { getClientIp } from 'request-ip'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { GROUP_NOT_FOUND } from 'src/errors/errors.constants'; +import { STAART_AUDIT_LOG_DATA } from 'src/modules/audit-logs/audit-log.constants'; +import { UserRequest } from 'src/modules/auth/auth.interface'; +import { GeolocationService } from 'src/modules/geolocation/geolocation.service'; +import { PrismaService } from 'src/modules/prisma/prisma.service'; +import { WebhooksService } from 'src/modules/webhooks/webhooks.service'; +import { UAParser } from 'ua-parser-js'; + +@Injectable() +export class AuditLogger implements NestInterceptor { + logger = new Logger(AuditLogger.name); + + constructor( + private readonly reflector: Reflector, + private prisma: PrismaService, + private geolocationService: GeolocationService, + private webhooksService: WebhooksService, + ) {} + + intercept(context: ExecutionContext, next: CallHandler): Observable { + let auditLog = this.reflector.get( + STAART_AUDIT_LOG_DATA, + context.getHandler(), + ); + return next.handle().pipe( + tap(() => { + (async () => { + if (auditLog) { + if (typeof auditLog === 'string') auditLog = [auditLog]; + const request = context.switchToHttp().getRequest() as UserRequest; + const groupId = parseInt(request.params.id); + if (isNaN(groupId)) throw new BadGatewayException(GROUP_NOT_FOUND); + const ip = getClientIp(request); + const location = await this.geolocationService.getLocation(ip); + const userAgent = request.get('user-agent'); + const ua = new UAParser(userAgent); + for await (const event of auditLog) { + const data: auditLogsCreateInput = { + event, + city: location?.city?.names?.en, + region: location?.subdivisions?.pop()?.names?.en, + timezone: location?.location?.time_zone, + countryCode: location?.country?.iso_code, + userAgent, + browser: + `${ua.getBrowser().name ?? ''} ${ + ua.getBrowser().version ?? '' + }`.trim() || undefined, + operatingSystem: + `${ua.getOS().name ?? ''} ${ + ua.getOS().version ?? '' + }`.trim() || undefined, + }; + if (request.user.id && request.user.type === 'user') + data.user = { connect: { id: request.user.id } }; + if (groupId) data.group = { connect: { id: groupId } }; + await this.prisma.auditLogs.create({ data }); + this.webhooksService.triggerWebhook(groupId, event); + } + } + })() + .then(() => {}) + .catch((err) => this.logger.error('Unable to save audit log', err)); + }), + ); + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 000000000..27c406a7d --- /dev/null +++ b/src/main.ts @@ -0,0 +1,35 @@ +import { ValidationPipe } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { promises } from 'fs'; +import helmet from 'helmet'; +import { join } from 'path'; +import responseTime from 'response-time'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + + app.useGlobalPipes(new ValidationPipe()); + app.use(helmet()); + + const pkg = JSON.parse( + await promises.readFile(join('.', 'package.json'), 'utf8'), + ); + + const options = new DocumentBuilder() + .setTitle('API') + .setDescription('API description') + .setVersion(pkg.version) + .build(); + const document = SwaggerModule.createDocument(app, options); + SwaggerModule.setup('api', app, document); + + app.setGlobalPrefix('v1'); + app.use(responseTime()); + app.useStaticAssets(join(__dirname, '..', 'static')); + + await app.listen(3000); +} +bootstrap(); diff --git a/src/middleware/json-body.middleware.ts b/src/middleware/json-body.middleware.ts new file mode 100644 index 000000000..a4239dece --- /dev/null +++ b/src/middleware/json-body.middleware.ts @@ -0,0 +1,10 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import * as bodyParser from 'body-parser'; +import { NextFunction, Request, Response } from 'express'; + +@Injectable() +export class JsonBodyMiddleware implements NestMiddleware { + use(req: Request, res: Response, next: NextFunction) { + bodyParser.json()(req, res, next); + } +} diff --git a/src/middleware/raw-body.middleware.ts b/src/middleware/raw-body.middleware.ts new file mode 100644 index 000000000..8b00e380b --- /dev/null +++ b/src/middleware/raw-body.middleware.ts @@ -0,0 +1,10 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import * as bodyParser from 'body-parser'; +import { NextFunction, Request, Response } from 'express'; + +@Injectable() +export class RawBodyMiddleware implements NestMiddleware { + use(req: Request, res: Response, next: NextFunction) { + bodyParser.raw({ type: '*/*' })(req, res, next); + } +} diff --git a/src/modules/api-keys/api-keys-group.controller.ts b/src/modules/api-keys/api-keys-group.controller.ts new file mode 100644 index 000000000..4363c7fe5 --- /dev/null +++ b/src/modules/api-keys/api-keys-group.controller.ts @@ -0,0 +1,109 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Put, + Query, +} from '@nestjs/common'; +import { apiKeys } from '@prisma/client'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { Expose } from '../prisma/prisma.interface'; +import { + CreateApiKeyDto, + ReplaceApiKeyDto, + UpdateApiKeyDto, +} from './api-keys.dto'; +import { ApiKeysService } from './api-keys.service'; + +@Controller('groups/:groupId/api-keys') +export class ApiKeyGroupController { + constructor(private apiKeysService: ApiKeysService) {} + + @Post() + @AuditLog('create-api-key') + @Scopes('group-{groupId}:write-api-key-*') + async create( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: CreateApiKeyDto, + ): Promise> { + return this.apiKeysService.createApiKeyForGroup(groupId, data); + } + + @Get() + @Scopes('group-{groupId}:read-api-key-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.apiKeysService.getApiKeysForGroup(groupId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get('scopes') + @Scopes('group-{groupId}:write-api-key-*') + async scopes( + @Param('groupId', ParseIntPipe) groupId: number, + ): Promise> { + return this.apiKeysService.getApiKeyScopesForGroup(groupId); + } + + @Get(':id') + @Scopes('group-{groupId}:read-api-key-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.getApiKeyForGroup(groupId, Number(id)); + } + + @Patch(':id') + @AuditLog('update-api-key') + @Scopes('group-{groupId}:write-api-key-{id}') + async update( + @Body() data: UpdateApiKeyDto, + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.updateApiKeyForGroup(groupId, Number(id), data); + } + + @Put(':id') + @AuditLog('update-api-key') + @Scopes('group-{groupId}:write-api-key-{id}') + async replace( + @Body() data: ReplaceApiKeyDto, + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.updateApiKeyForGroup(groupId, Number(id), data); + } + + @Delete(':id') + @AuditLog('delete-api-key') + @Scopes('group-{groupId}:delete-api-key-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.deleteApiKeyForGroup(groupId, Number(id)); + } +} diff --git a/src/modules/api-keys/api-keys-user.controller.ts b/src/modules/api-keys/api-keys-user.controller.ts new file mode 100644 index 000000000..4c380c2ab --- /dev/null +++ b/src/modules/api-keys/api-keys-user.controller.ts @@ -0,0 +1,109 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Put, + Query, +} from '@nestjs/common'; +import { apiKeys } from '@prisma/client'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { Expose } from '../prisma/prisma.interface'; +import { + CreateApiKeyDto, + ReplaceApiKeyDto, + UpdateApiKeyDto, +} from './api-keys.dto'; +import { ApiKeysService } from './api-keys.service'; + +@Controller('users/:userId/api-keys') +export class ApiKeyUserController { + constructor(private apiKeysService: ApiKeysService) {} + + @Post() + @AuditLog('create-api-key') + @Scopes('user-{userId}:write-api-key-*') + async create( + @Param('userId', ParseIntPipe) userId: number, + @Body() data: CreateApiKeyDto, + ): Promise> { + return this.apiKeysService.createApiKeyForUser(userId, data); + } + + @Get() + @Scopes('user-{userId}:read-api-key-*') + async getAll( + @Param('userId', ParseIntPipe) userId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.apiKeysService.getApiKeysForUser(userId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get('scopes') + @Scopes('user-{userId}:write-api-key-*') + async scopes( + @Param('userId', ParseIntPipe) userId: number, + ): Promise> { + return this.apiKeysService.getApiKeyScopesForUser(userId); + } + + @Get(':id') + @Scopes('user-{userId}:read-api-key-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.getApiKeyForUser(userId, Number(id)); + } + + @Patch(':id') + @AuditLog('update-api-key') + @Scopes('user-{userId}:write-api-key-{id}') + async update( + @Body() data: UpdateApiKeyDto, + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.updateApiKeyForUser(userId, Number(id), data); + } + + @Put(':id') + @AuditLog('update-api-key') + @Scopes('user-{userId}:write-api-key-{id}') + async replace( + @Body() data: ReplaceApiKeyDto, + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.updateApiKeyForUser(userId, Number(id), data); + } + + @Delete(':id') + @AuditLog('delete-api-key') + @Scopes('user-{userId}:delete-api-key-{id}') + async remove( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.apiKeysService.deleteApiKeyForUser(userId, Number(id)); + } +} diff --git a/src/modules/api-keys/api-keys.dto.ts b/src/modules/api-keys/api-keys.dto.ts new file mode 100644 index 000000000..efc98f61a --- /dev/null +++ b/src/modules/api-keys/api-keys.dto.ts @@ -0,0 +1,76 @@ +import { IsArray, IsNotEmpty, IsOptional, IsString } from 'class-validator'; + +export class CreateApiKeyDto { + @IsString() + @IsOptional() + description?: string; + + @IsString() + @IsOptional() + name?: string; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + scopes?: string[]; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + ipRestrictions?: string[]; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + referrerRestrictions?: string[]; +} + +export class UpdateApiKeyDto { + @IsString() + @IsOptional() + description?: string; + + @IsString() + @IsOptional() + name?: string; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + scopes?: string[]; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + ipRestrictions?: string[]; + + @IsArray() + @IsString({ each: true }) + @IsOptional() + referrerRestrictions?: string[]; +} + +export class ReplaceApiKeyDto { + @IsString() + @IsNotEmpty() + description!: string; + + @IsString() + @IsNotEmpty() + name!: string; + + @IsArray() + @IsString({ each: true }) + @IsNotEmpty() + scopes!: string[]; + + @IsArray() + @IsString({ each: true }) + @IsNotEmpty() + ipRestrictions!: string[]; + + @IsArray() + @IsString({ each: true }) + @IsNotEmpty() + referrerRestrictions!: string[]; +} diff --git a/src/modules/api-keys/api-keys.module.ts b/src/modules/api-keys/api-keys.module.ts new file mode 100644 index 000000000..32e012247 --- /dev/null +++ b/src/modules/api-keys/api-keys.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from '../prisma/prisma.module'; +import { StripeModule } from '../stripe/stripe.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { ApiKeyGroupController } from './api-keys-group.controller'; +import { ApiKeyUserController } from './api-keys-user.controller'; +import { ApiKeysService } from './api-keys.service'; + +@Module({ + imports: [PrismaModule, TokensModule, StripeModule, ConfigModule], + controllers: [ApiKeyGroupController, ApiKeyUserController], + providers: [ApiKeysService], + exports: [ApiKeysService], +}) +export class ApiKeysModule {} diff --git a/src/modules/api-keys/api-keys.service.ts b/src/modules/api-keys/api-keys.service.ts new file mode 100644 index 000000000..a61525428 --- /dev/null +++ b/src/modules/api-keys/api-keys.service.ts @@ -0,0 +1,443 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + apiKeys, + apiKeysCreateInput, + apiKeysOrderByInput, + apiKeysUpdateInput, + apiKeysWhereInput, + apiKeysWhereUniqueInput, + InputJsonValue, + JsonValue, +} from '@prisma/client'; +import QuickLRU from 'quick-lru'; +import { + API_KEY_NOT_FOUND, + UNAUTHORIZED_RESOURCE, +} from '../../errors/errors.constants'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; +import { StripeService } from '../stripe/stripe.service'; +import { TokensService } from '../tokens/tokens.service'; + +@Injectable() +export class ApiKeysService { + private lru = new QuickLRU({ + maxSize: this.configService.get('caching.apiKeyLruSize') ?? 100, + }); + + constructor( + private prisma: PrismaService, + private tokensService: TokensService, + private stripeService: StripeService, + private configService: ConfigService, + ) {} + + async createApiKeyForGroup( + groupId: number, + data: Omit, 'group'>, + ): Promise { + const apiKey = this.tokensService.generateUuid(); + data.scopes = this.cleanScopesForGroup(groupId, data.scopes); + return this.prisma.apiKeys.create({ + data: { ...data, apiKey, group: { connect: { id: groupId } } }, + }); + } + async createApiKeyForUser( + userId: number, + data: Omit, 'user'>, + ): Promise { + const apiKey = this.tokensService.generateUuid(); + data.scopes = this.cleanScopesForUser(userId, data.scopes); + return this.prisma.apiKeys.create({ + data: { ...data, apiKey, user: { connect: { id: userId } } }, + }); + } + + async getApiKeysForGroup( + groupId: number, + params: { + skip?: number; + take?: number; + cursor?: apiKeysWhereUniqueInput; + where?: apiKeysWhereInput; + orderBy?: apiKeysOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const apiKeys = await this.prisma.apiKeys.findMany({ + skip, + take, + cursor, + where: { ...where, group: { id: groupId } }, + orderBy, + }); + return apiKeys.map((group) => this.prisma.expose(group)); + } + async getApiKeysForUser( + userId: number, + params: { + skip?: number; + take?: number; + cursor?: apiKeysWhereUniqueInput; + where?: apiKeysWhereInput; + orderBy?: apiKeysOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const apiKeys = await this.prisma.apiKeys.findMany({ + skip, + take, + cursor, + where: { ...where, user: { id: userId } }, + orderBy, + }); + return apiKeys.map((user) => this.prisma.expose(user)); + } + + async getApiKeyForGroup( + groupId: number, + id: number, + ): Promise> { + const apiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!apiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (apiKey.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(apiKey); + } + async getApiKeyForUser(userId: number, id: number): Promise> { + const apiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!apiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (apiKey.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(apiKey); + } + + async getApiKeyFromKey(key: string): Promise> { + const apiKey = await this.prisma.apiKeys.findFirst({ + where: { apiKey: key }, + }); + if (!apiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (this.lru.has(key)) return this.lru.get(key); + this.lru.set(key, apiKey); + return this.prisma.expose(apiKey); + } + + async updateApiKeyForGroup( + groupId: number, + id: number, + data: apiKeysUpdateInput, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + data.scopes = this.cleanScopesForGroup(groupId, data.scopes); + const apiKey = await this.prisma.apiKeys.update({ + where: { id }, + data, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + async updateApiKeyForUser( + userId: number, + id: number, + data: apiKeysUpdateInput, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + data.scopes = this.cleanScopesForUser(userId, data.scopes); + const apiKey = await this.prisma.apiKeys.update({ + where: { id }, + data, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + + async replaceApiKeyForGroup( + groupId: number, + id: number, + data: apiKeysCreateInput, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + data.scopes = this.cleanScopesForGroup(groupId, data.scopes); + const apiKey = await this.prisma.apiKeys.update({ + where: { id }, + data, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + async replaceApiKeyForUser( + userId: number, + id: number, + data: apiKeysCreateInput, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + data.scopes = this.cleanScopesForUser(userId, data.scopes); + const apiKey = await this.prisma.apiKeys.update({ + where: { id }, + data, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + + async deleteApiKeyForGroup( + groupId: number, + id: number, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const apiKey = await this.prisma.apiKeys.delete({ + where: { id }, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + async deleteApiKeyForUser( + userId: number, + id: number, + ): Promise> { + const testApiKey = await this.prisma.apiKeys.findOne({ + where: { id }, + }); + if (!testApiKey) throw new NotFoundException(API_KEY_NOT_FOUND); + if (testApiKey.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const apiKey = await this.prisma.apiKeys.delete({ + where: { id }, + }); + this.lru.delete(testApiKey.apiKey); + return this.prisma.expose(apiKey); + } + + private cleanScopesForGroup( + groupId: number, + scopes: InputJsonValue, + ): JsonValue[] { + if (!Array.isArray(scopes)) return []; + return scopes + .map((scope) => { + if (typeof scope === 'string') { + if (!scope.startsWith(`group-${groupId}:`)) + scope = `group-${groupId}:${scope}`; + return scope; + } + }) + .filter((scope) => !!scope); + } + private cleanScopesForUser( + userId: number, + scopes: InputJsonValue, + ): JsonValue[] { + if (!Array.isArray(scopes)) return []; + return scopes + .map((scope) => { + if (typeof scope === 'string') { + if (!scope.startsWith(`user-${userId}:`)) + scope = `user-${userId}:${scope}`; + return scope; + } + }) + .filter((scope) => !!scope); + } + + async getApiKeyScopesForGroup( + groupId: number, + ): Promise> { + const scopes: Record = {}; + scopes[`read-info`] = 'Read group details'; + scopes[`write-info`] = 'Update group details'; + scopes[`delete`] = 'Delete group'; + + scopes[`write-membership-*`] = 'Invite and update members'; + scopes[`read-membership-*`] = 'Read members'; + for await (const membership of await this.prisma.memberships.findMany({ + where: { group: { id: groupId } }, + select: { id: true, user: true }, + })) { + scopes[ + `read-membership-${membership.id}` + ] = `Read membership: ${membership.user.name}`; + scopes[ + `write-membership-${membership.id}` + ] = `Update membership: ${membership.user.name}`; + scopes[ + `delete-membership-${membership.id}` + ] = `Delete membership: ${membership.user.name}`; + } + + scopes[`write-api-key-*`] = 'Create and update API keys'; + scopes[`read-api-key-*`] = 'Read API keys'; + for await (const apiKey of await this.prisma.apiKeys.findMany({ + where: { group: { id: groupId } }, + select: { id: true, name: true, apiKey: true }, + })) { + scopes[`read-api-key-${apiKey.id}`] = `Read API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + scopes[`write-api-key-${apiKey.id}`] = `Write API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + scopes[`delete-api-key-${apiKey.id}`] = `Delete API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + } + + scopes[`write-webhook-*`] = 'Create and update webhooks'; + scopes[`read-webhook-*`] = 'Read webhooks'; + for await (const webhook of await this.prisma.webhooks.findMany({ + where: { group: { id: groupId } }, + select: { id: true, url: true }, + })) { + scopes[`read-webhook-${webhook.id}`] = `Read webhook: ${webhook.url}`; + scopes[`write-webhook-${webhook.id}`] = `Write webhook: ${webhook.url}`; + scopes[`delete-webhook-${webhook.id}`] = `Delete webhook: ${webhook.url}`; + } + + scopes[`write-billing`] = 'Write billing details'; + scopes[`read-billing`] = 'Read billing details'; + scopes[`delete-billing`] = 'Delete billing details'; + + scopes[`read-invoice-*`] = 'Read invoices'; + for await (const invoice of await this.stripeService.getInvoices( + groupId, + {}, + )) { + scopes[`read-invoice-${invoice.id}`] = `Read invoice: ${invoice.number}`; + } + + scopes[`write-source-*`] = 'Write payment methods'; + scopes[`read-source-*`] = 'Read payment methods'; + for await (const source of await this.stripeService.getSources( + groupId, + {}, + )) { + scopes[`read-source-${source.id}`] = `Read payment method: ${source.id}`; + scopes[ + `delete-source-${source.id}` + ] = `Delete payment method: ${source.id}`; + } + + scopes[`read-audit-log-*`] = 'Read audit logs'; + return scopes; + } + + async getApiKeyScopesForUser( + userId: number, + ): Promise> { + const scopes: Record = {}; + scopes[`read-info`] = 'Read user details'; + scopes[`write-info`] = 'Update user details'; + scopes[`delete`] = 'Delete user'; + + scopes[`write-membership-*`] = 'Create new groups'; + scopes[`read-membership-*`] = 'Read group memberships'; + for await (const membership of await this.prisma.memberships.findMany({ + where: { user: { id: userId } }, + select: { id: true, group: true }, + })) { + scopes[ + `read-membership-${membership.id}` + ] = `Read membership: ${membership.group.name}`; + scopes[ + `write-membership-${membership.id}` + ] = `Update membership: ${membership.group.name}`; + scopes[ + `delete-membership-${membership.id}` + ] = `Delete membership: ${membership.group.name}`; + } + + scopes[`write-email-*`] = 'Create and update emails'; + scopes[`read-email-*`] = 'Read emails'; + for await (const email of await this.prisma.emails.findMany({ + where: { user: { id: userId } }, + select: { id: true, email: true }, + })) { + scopes[`read-email-${email.id}`] = `Read email: ${email.email}`; + scopes[`delete-email-${email.id}`] = `Delete email: ${email.email}`; + } + + scopes[`read-session-*`] = 'Read sessions'; + for await (const session of await this.prisma.sessions.findMany({ + where: { user: { id: userId } }, + select: { id: true, browser: true }, + })) { + scopes[`read-session-${session.id}`] = `Read session: ${ + session.browser ?? session.id + }`; + scopes[`delete-session-${session.id}`] = `Delete session: ${ + session.browser ?? session.id + }`; + } + + scopes[`read-approved-subnet-*`] = 'Read approvedSubnets'; + for await (const subnet of await this.prisma.approvedSubnets.findMany({ + where: { user: { id: userId } }, + select: { id: true, subnet: true }, + })) { + scopes[ + `read-approved-subnet-${subnet.id}` + ] = `Read subnet: ${subnet.subnet}`; + scopes[ + `delete-approved-subnet-${subnet.id}` + ] = `Delete subnet: ${subnet.subnet}`; + } + + scopes[`write-api-key-*`] = 'Create and update API keys'; + scopes[`read-api-key-*`] = 'Read API keys'; + for await (const apiKey of await this.prisma.apiKeys.findMany({ + where: { user: { id: userId } }, + select: { id: true, name: true, apiKey: true }, + })) { + scopes[`read-api-key-${apiKey.id}`] = `Read API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + scopes[`write-api-key-${apiKey.id}`] = `Write API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + scopes[`delete-api-key-${apiKey.id}`] = `Delete API key: ${ + apiKey.name ?? apiKey.apiKey + }`; + } + + scopes[`delete-mfa-*`] = 'Disable multi-factor authentication'; + scopes[`write-mfa-regenerate`] = 'Regenerate MFA backup codes'; + scopes[`write-mfa-totp`] = 'Enable TOTP-based MFA'; + scopes[`write-mfa-sms`] = 'Enable SMS-based MFA'; + scopes[`write-mfa-email`] = 'Enable email-based MFA'; + + return scopes; + } +} diff --git a/src/modules/approved-subnets/approved-subnets.controller.ts b/src/modules/approved-subnets/approved-subnets.controller.ts new file mode 100644 index 000000000..dee8ea19e --- /dev/null +++ b/src/modules/approved-subnets/approved-subnets.controller.ts @@ -0,0 +1,58 @@ +import { + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Query, +} from '@nestjs/common'; +import { approvedSubnets } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { ApprovedSubnetsService } from './approved-subnets.service'; + +@Controller('users/:userId/approved-subnets') +export class ApprovedSubnetController { + constructor(private approvedSubnetsService: ApprovedSubnetsService) {} + + @Get() + @Scopes('user-{userId}:read-approved-subnet-*') + async getAll( + @Param('userId', ParseIntPipe) userId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.approvedSubnetsService.getApprovedSubnets(userId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('user-{userId}:read-approved-subnet-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.approvedSubnetsService.getApprovedSubnet(userId, Number(id)); + } + + @Delete(':id') + @Scopes('user-{userId}:delete-approved-subnet-{id}') + async remove( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.approvedSubnetsService.deleteApprovedSubnet(userId, Number(id)); + } +} diff --git a/src/modules/approved-subnets/approved-subnets.module.ts b/src/modules/approved-subnets/approved-subnets.module.ts new file mode 100644 index 000000000..2b076e3b9 --- /dev/null +++ b/src/modules/approved-subnets/approved-subnets.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { GeolocationModule } from '../geolocation/geolocation.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { ApprovedSubnetController } from './approved-subnets.controller'; +import { ApprovedSubnetsService } from './approved-subnets.service'; + +@Module({ + imports: [PrismaModule, ConfigModule, GeolocationModule], + controllers: [ApprovedSubnetController], + providers: [ApprovedSubnetsService], +}) +export class ApprovedSubnetsModule {} diff --git a/src/modules/approved-subnets/approved-subnets.service.ts b/src/modules/approved-subnets/approved-subnets.service.ts new file mode 100644 index 000000000..3bc9c42b7 --- /dev/null +++ b/src/modules/approved-subnets/approved-subnets.service.ts @@ -0,0 +1,122 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + approvedSubnets, + approvedSubnetsOrderByInput, + approvedSubnetsWhereInput, + approvedSubnetsWhereUniqueInput, +} from '@prisma/client'; +import { compare, hash } from 'bcrypt'; +import anonymize from 'ip-anonymize'; +import { + APPROVED_SUBNET_NOT_FOUND, + UNAUTHORIZED_RESOURCE, +} from 'src/errors/errors.constants'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { GeolocationService } from '../geolocation/geolocation.service'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class ApprovedSubnetsService { + constructor( + private prisma: PrismaService, + private configService: ConfigService, + private geolocationService: GeolocationService, + ) {} + + async getApprovedSubnets( + userId: number, + params: { + skip?: number; + take?: number; + cursor?: approvedSubnetsWhereUniqueInput; + where?: approvedSubnetsWhereInput; + orderBy?: approvedSubnetsOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const approvedSubnets = await this.prisma.approvedSubnets.findMany({ + skip, + take, + cursor, + where: { ...where, user: { id: userId } }, + orderBy, + }); + return approvedSubnets.map((user) => + this.prisma.expose(user), + ); + } + + async getApprovedSubnet( + userId: number, + id: number, + ): Promise> { + const approvedSubnet = await this.prisma.approvedSubnets.findOne({ + where: { id }, + }); + if (!approvedSubnet) throw new NotFoundException(APPROVED_SUBNET_NOT_FOUND); + if (approvedSubnet.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + if (!approvedSubnet) throw new NotFoundException(APPROVED_SUBNET_NOT_FOUND); + return this.prisma.expose(approvedSubnet); + } + + async deleteApprovedSubnet( + userId: number, + id: number, + ): Promise> { + const testApprovedSubnet = await this.prisma.approvedSubnets.findOne({ + where: { id }, + }); + if (!testApprovedSubnet) + throw new NotFoundException(APPROVED_SUBNET_NOT_FOUND); + if (testApprovedSubnet.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const approvedSubnet = await this.prisma.approvedSubnets.delete({ + where: { id }, + }); + return this.prisma.expose(approvedSubnet); + } + + async approveNewSubnet(userId: number, ipAddress: string) { + const subnet = await hash( + anonymize(ipAddress), + this.configService.get('security.saltRounds') ?? 10, + ); + const location = await this.geolocationService.getLocation(ipAddress); + const approved = await this.prisma.approvedSubnets.create({ + data: { + user: { connect: { id: userId } }, + subnet, + city: location?.city?.names?.en, + region: location?.subdivisions?.pop()?.names?.en, + timezone: location?.location?.time_zone, + countryCode: location?.country?.iso_code, + }, + }); + return this.prisma.expose(approved); + } + + /** + * Upsert a new subnet + * If this subnet already exists, skip; otherwise add it + */ + async upsertNewSubnet( + userId: number, + ipAddress: string, + ): Promise> { + const subnet = anonymize(ipAddress); + const previousSubnets = await this.prisma.approvedSubnets.findMany({ + where: { user: { id: userId } }, + }); + for await (const item of previousSubnets) { + if (await compare(subnet, item.subnet)) + return this.prisma.expose(item); + } + return this.approveNewSubnet(userId, ipAddress); + } +} diff --git a/src/modules/audit-logs/audit-log.constants.ts b/src/modules/audit-logs/audit-log.constants.ts new file mode 100644 index 000000000..09540b313 --- /dev/null +++ b/src/modules/audit-logs/audit-log.constants.ts @@ -0,0 +1 @@ +export const STAART_AUDIT_LOG_DATA = 'STAART_AUDIT_LOG_DATA'; diff --git a/src/modules/audit-logs/audit-log.decorator.ts b/src/modules/audit-logs/audit-log.decorator.ts new file mode 100644 index 000000000..b6ecbe58a --- /dev/null +++ b/src/modules/audit-logs/audit-log.decorator.ts @@ -0,0 +1,5 @@ +import { SetMetadata } from '@nestjs/common'; +import { STAART_AUDIT_LOG_DATA } from './audit-log.constants'; + +export const AuditLog = (...value: string[]) => + SetMetadata(STAART_AUDIT_LOG_DATA, value); diff --git a/src/modules/audit-logs/audit-logs.controller.ts b/src/modules/audit-logs/audit-logs.controller.ts new file mode 100644 index 000000000..0cc29b399 --- /dev/null +++ b/src/modules/audit-logs/audit-logs.controller.ts @@ -0,0 +1,42 @@ +import { Controller, Get, Param, ParseIntPipe, Query } from '@nestjs/common'; +import { auditLogs } from '@prisma/client'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { Expose } from '../prisma/prisma.interface'; +import { AuditLogsService } from './audit-logs.service'; + +@Controller('groups/:groupId/audit-logs') +export class AuditLogController { + constructor(private auditLogsService: AuditLogsService) {} + + @Get() + @Scopes('group-{groupId}:read-audit-log-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.auditLogsService.getAuditLogs(groupId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-audit-log-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.auditLogsService.getAuditLog(groupId, Number(id)); + } +} diff --git a/src/modules/audit-logs/audit-logs.module.ts b/src/modules/audit-logs/audit-logs.module.ts new file mode 100644 index 000000000..375f43d08 --- /dev/null +++ b/src/modules/audit-logs/audit-logs.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from '../prisma/prisma.module'; +import { AuditLogController } from './audit-logs.controller'; +import { AuditLogsService } from './audit-logs.service'; + +@Module({ + imports: [PrismaModule], + controllers: [AuditLogController], + providers: [AuditLogsService], +}) +export class AuditLogsModule {} diff --git a/src/modules/audit-logs/audit-logs.service.ts b/src/modules/audit-logs/audit-logs.service.ts new file mode 100644 index 000000000..6f7a1b2e0 --- /dev/null +++ b/src/modules/audit-logs/audit-logs.service.ts @@ -0,0 +1,50 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { + auditLogs, + auditLogsOrderByInput, + auditLogsWhereInput, + auditLogsWhereUniqueInput, +} from '@prisma/client'; +import { UNAUTHORIZED_RESOURCE } from 'src/errors/errors.constants'; +import { Expose } from '../prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class AuditLogsService { + constructor(private prisma: PrismaService) {} + + async getAuditLogs( + groupId: number, + params: { + skip?: number; + take?: number; + cursor?: auditLogsWhereUniqueInput; + where?: auditLogsWhereInput; + orderBy?: auditLogsOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const auditLogs = await this.prisma.auditLogs.findMany({ + skip, + take, + cursor, + where: { ...where, group: { id: groupId } }, + orderBy, + }); + return auditLogs.map((group) => this.prisma.expose(group)); + } + + async getAuditLog(groupId: number, id: number): Promise> { + const auditLog = await this.prisma.auditLogs.findOne({ + where: { id }, + }); + if (!auditLog) throw new NotFoundException(UNAUTHORIZED_RESOURCE); + if (auditLog.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(auditLog); + } +} diff --git a/src/modules/auth/auth.constants.ts b/src/modules/auth/auth.constants.ts new file mode 100644 index 000000000..372811616 --- /dev/null +++ b/src/modules/auth/auth.constants.ts @@ -0,0 +1 @@ +export const STAART_PUBLIC_ENDPOINT = 'STAART_PUBLIC_ENDPOINT'; diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts new file mode 100644 index 000000000..a4f5e5c65 --- /dev/null +++ b/src/modules/auth/auth.controller.ts @@ -0,0 +1,166 @@ +import { Body, Controller, Headers, Ip, Post } from '@nestjs/common'; +import { users } from '@prisma/client'; +import { RateLimit } from 'nestjs-rate-limiter'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { + ForgotPasswordDto, + LoginDto, + RegisterDto, + ResendEmailVerificationDto, + ResetPasswordDto, + TotpLoginDto, + VerifyEmailDto, +} from './auth.dto'; +import { TokenResponse, TotpTokenResponse } from './auth.interface'; +import { AuthService } from './auth.service'; +import { Public } from './public.decorator'; + +@Controller('auth') +@Public() +export class AuthController { + constructor(private authService: AuthService) {} + + @Post('login') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to login again', + }) + async login( + @Body() data: LoginDto, + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + ): Promise { + return this.authService.login( + ip, + userAgent, + data.email, + data.password, + data.code, + ); + } + + @Post('register') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to create an account', + }) + async register( + @Ip() ip: string, + @Body() data: RegisterDto, + ): Promise> { + return this.authService.register(ip, data); + } + + @Post('refresh') + @RateLimit({ + points: 5, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to login again', + }) + async refresh( + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + @Body('token') refreshToken: string, + ): Promise { + return this.authService.refresh(ip, userAgent, refreshToken); + } + + @Post('logout') + @RateLimit({ + points: 5, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to logout again', + }) + async logout(@Body('token') refreshToken: string): Promise { + return this.authService.logout(refreshToken); + } + + @Post('approve-subnet') + @RateLimit({ + points: 5, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to logout again', + }) + async approveSubnet( + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + @Body('token') token: string, + ): Promise { + return this.authService.approveSubnet(ip, userAgent, token); + } + + @Post('resend-email-verification') + @RateLimit({ + points: 1, + duration: 60, + errorMessage: 'Wait for 60 seconds before requesting another email', + }) + async resendVerify(@Body() data: ResendEmailVerificationDto) { + return this.authService.sendEmailVerification(data.email, true); + } + + @Post('verify-email') + async verifyEmail(@Body() data: VerifyEmailDto) { + return this.authService.verifyEmail(data.token); + } + + @Post('forgot-password') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before resetting another password', + }) + async forgotPassword(@Body() data: ForgotPasswordDto) { + return this.authService.requestPasswordReset(data.email); + } + + @Post('reset-password') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before resetting another password', + }) + async resetPassword( + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + @Body() data: ResetPasswordDto, + ) { + return this.authService.resetPassword( + ip, + userAgent, + data.token, + data.password, + data.ignorePwnedPassword, + ); + } + + @Post('login/totp') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to login again', + }) + async totpLogin( + @Body() data: TotpLoginDto, + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + ): Promise { + return this.authService.loginWithTotp(ip, userAgent, data.token, data.code); + } + + @Post('login/token') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to login again', + }) + async emailTokenLoginPost( + @Body('token') token: string, + @Ip() ip: string, + @Headers('User-Agent') userAgent: string, + ): Promise { + return this.authService.loginWithEmailToken(ip, userAgent, token); + } +} diff --git a/src/modules/auth/auth.dto.ts b/src/modules/auth/auth.dto.ts new file mode 100644 index 000000000..995eb49ac --- /dev/null +++ b/src/modules/auth/auth.dto.ts @@ -0,0 +1,136 @@ +import { + IsBoolean, + IsEmail, + IsIn, + IsLocale, + IsNotEmpty, + IsObject, + IsOptional, + IsString, + IsUrl, + Length, + MinLength, +} from 'class-validator'; + +export class RegisterDto { + @IsString() + @IsNotEmpty() + @MinLength(3) + name!: string; + + @IsEmail() + @IsNotEmpty() + email!: string; + + @IsBoolean() + @IsOptional() + checkLocationOnLogin?: boolean; + + @IsString() + @Length(2, 2) + @IsOptional() + countryCode?: string; + + @IsString() + @IsIn(['MALE', 'FEMALE', 'NONBINARY', 'UNKNOWN']) + @IsOptional() + gender?: 'MALE' | 'FEMALE' | 'NONBINARY' | 'UNKNOWN'; + + @IsIn(['ACCOUNT', 'UPDATES', 'PROMOTIONS']) + @IsOptional() + notificationEmails?: 'ACCOUNT' | 'UPDATES' | 'PROMOTIONS'; + + @IsString() + @IsOptional() + password?: string | null; + + @IsLocale() + @IsOptional() + prefersLanguage?: string; + + @IsString() + @IsIn(['NO_PREFERENCE', 'LIGHT', 'DARK']) + @IsOptional() + prefersColorScheme?: 'NO_PREFERENCE' | 'LIGHT' | 'DARK'; + + @IsString() + @IsIn(['NO_PREFERENCE', 'REDUCE']) + @IsOptional() + prefersReducedMotion?: 'NO_PREFERENCE' | 'REDUCE'; + + @IsUrl() + @IsOptional() + profilePictureUrl?: string; + + @IsString() + @IsOptional() + timezone?: string; + + @IsObject() + @IsOptional() + attributes?: Record; + + @IsBoolean() + @IsOptional() + ignorePwnedPassword?: boolean; +} + +export class ResendEmailVerificationDto { + @IsEmail() + @IsNotEmpty() + email!: string; +} + +export class ForgotPasswordDto { + @IsEmail() + @IsNotEmpty() + email!: string; +} + +export class ResetPasswordDto { + @IsString() + @IsNotEmpty() + token!: string; + + @IsString() + @MinLength(8) + @IsNotEmpty() + password!: string; + + @IsBoolean() + @IsOptional() + ignorePwnedPassword?: boolean; +} + +export class LoginDto { + @IsEmail() + @IsNotEmpty() + email!: string; + + @IsString() + @MinLength(8) + @IsOptional() + password?: string; + + @IsString() + @Length(6) + @IsOptional() + code?: string; +} + +export class TotpLoginDto { + @IsString() + @IsNotEmpty() + token!: string; + + @IsString() + @Length(6) + @IsNotEmpty() + code!: string; +} + +export class VerifyEmailDto { + @IsString() + @IsNotEmpty() + token!: string; +} diff --git a/src/modules/auth/auth.interface.ts b/src/modules/auth/auth.interface.ts new file mode 100644 index 000000000..8af708cf8 --- /dev/null +++ b/src/modules/auth/auth.interface.ts @@ -0,0 +1,36 @@ +import { Request as NestRequest } from '@nestjs/common'; +import { MfaMethod } from '@prisma/client'; +import { Request as ExpressRequest } from 'express'; + +export interface AccessTokenClaims { + sub: string; + id: number; + scopes: string[]; +} + +export interface TokenResponse { + accessToken: string; + refreshToken: string; +} + +export interface TotpTokenResponse { + totpToken: string; + type: MfaMethod; + multiFactorRequired: true; +} + +export interface AccessTokenParsed { + id: number; + scopes: string[]; + type: 'user' | 'api-key'; +} + +export interface MfaTokenPayload { + id: number; + type: MfaMethod; +} + +type CombinedRequest = ExpressRequest & typeof NestRequest; +export interface UserRequest extends CombinedRequest { + user: AccessTokenParsed; +} diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts new file mode 100644 index 000000000..9946f29f4 --- /dev/null +++ b/src/modules/auth/auth.module.ts @@ -0,0 +1,38 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import { ApiKeysModule } from '../api-keys/api-keys.module'; +import { ApprovedSubnetsModule } from '../approved-subnets/approved-subnets.module'; +import { ApprovedSubnetsService } from '../approved-subnets/approved-subnets.service'; +import { EmailModule } from '../email/email.module'; +import { GeolocationModule } from '../geolocation/geolocation.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { PwnedModule } from '../pwned/pwned.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { TwilioModule } from '../twilio/twilio.module'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { StaartStrategy } from './staart.strategy'; + +@Module({ + imports: [ + PassportModule.register({ defaultStrategy: 'jwt' }), + PrismaModule, + EmailModule, + TokensModule, + ConfigModule, + PwnedModule, + ApiKeysModule, + TwilioModule, + GeolocationModule, + ApprovedSubnetsModule, + JwtModule.register({ + secret: process.env.JWT_SECRET ?? 'staart', + }), + ], + controllers: [AuthController], + exports: [AuthService], + providers: [AuthService, StaartStrategy, ApprovedSubnetsService], +}) +export class AuthModule {} diff --git a/src/modules/auth/auth.service.ts b/src/modules/auth/auth.service.ts new file mode 100644 index 000000000..7f3e0b3e1 --- /dev/null +++ b/src/modules/auth/auth.service.ts @@ -0,0 +1,624 @@ +import { + BadRequestException, + ConflictException, + Injectable, + NotFoundException, + UnauthorizedException, + UnprocessableEntityException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import { Authenticator } from '@otplib/core'; +import { emails, MfaMethod, users } from '@prisma/client'; +import { compare, hash } from 'bcrypt'; +import { createHash } from 'crypto'; +import got from 'got/dist/source'; +import anonymize from 'ip-anonymize'; +import { authenticator } from 'otplib'; +import qrcode from 'qrcode'; +import randomColor from 'randomcolor'; +import { + COMPROMISED_PASSWORD, + EMAIL_USER_CONFLICT, + EMAIL_VERIFIED_CONFLICT, + INVALID_CREDENTIALS, + INVALID_MFA_CODE, + MFA_BACKUP_CODE_USED, + MFA_ENABLED_CONFLICT, + MFA_NOT_ENABLED, + MFA_PHONE_NOT_FOUND, + NO_EMAILS, + NO_TOKEN_PROVIDED, + SESSION_NOT_FOUND, + UNVERIFIED_EMAIL, + UNVERIFIED_LOCATION, + USER_NOT_FOUND, +} from 'src/errors/errors.constants'; +import { safeEmail } from '../../helpers/safe-email'; +import { ApprovedSubnetsService } from '../approved-subnets/approved-subnets.service'; +import { EmailService } from '../email/email.service'; +import { GeolocationService } from '../geolocation/geolocation.service'; +import { Expose } from '../prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; +import { PwnedService } from '../pwned/pwned.service'; +import { + APPROVE_SUBNET_TOKEN, + EMAIL_MFA_TOKEN, + EMAIL_VERIFY_TOKEN, + LOGIN_ACCESS_TOKEN, + MULTI_FACTOR_TOKEN, + PASSWORD_RESET_TOKEN, +} from '../tokens/tokens.constants'; +import { TokensService } from '../tokens/tokens.service'; +import { TwilioService } from '../twilio/twilio.service'; +import { RegisterDto } from './auth.dto'; +import { + AccessTokenClaims, + MfaTokenPayload, + TokenResponse, + TotpTokenResponse, +} from './auth.interface'; + +@Injectable() +export class AuthService { + authenticator: Authenticator; + + constructor( + private prisma: PrismaService, + private email: EmailService, + private configService: ConfigService, + private jwtService: JwtService, + private pwnedService: PwnedService, + private tokensService: TokensService, + private geolocationService: GeolocationService, + private approvedSubnetsService: ApprovedSubnetsService, + private twilioService: TwilioService, + ) { + this.authenticator = authenticator.create({ + window: [ + this.configService.get('security.totpWindowPast') ?? 0, + this.configService.get('security.totpWindowFuture') ?? 0, + ], + }); + } + + async login( + ipAddress: string, + userAgent: string, + email: string, + password?: string, + code?: string, + ): Promise { + const emailSafe = safeEmail(email); + const user = await this.prisma.users.findFirst({ + where: { emails: { some: { emailSafe } } }, + include: { + emails: true, + prefersEmail: true, + }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + if (!user.emails.find((i) => i.emailSafe === emailSafe)?.isVerified) + throw new UnauthorizedException(UNVERIFIED_EMAIL); + if (!password || !user.password) return this.mfaResponse(user, 'EMAIL'); + if (!user.prefersEmail) throw new BadRequestException(NO_EMAILS); + if (!(await compare(password, user.password))) + throw new UnauthorizedException(INVALID_CREDENTIALS); + if (code) + return this.loginUserWithTotpCode(ipAddress, userAgent, user.id, code); + if (user.twoFactorMethod !== 'NONE') return this.mfaResponse(user); + await this.checkLoginSubnet( + ipAddress, + userAgent, + user.checkLocationOnLogin, + user.id, + ); + return this.loginResponse(ipAddress, userAgent, user); + } + + async register( + ipAddress: string, + _data: RegisterDto, + ): Promise> { + const { email, ...data } = _data; + const emailSafe = safeEmail(email); + const testUser = await this.prisma.users.findFirst({ + where: { emails: { some: { emailSafe } } }, + }); + if (testUser) throw new ConflictException(EMAIL_USER_CONFLICT); + const ignorePwnedPassword = !!data.ignorePwnedPassword; + delete data.ignorePwnedPassword; + + if (data.name) + data.name = data.name + .split(' ') + .map((word, index) => + index === 0 || index === data.name.split(' ').length + ? (word.charAt(0) ?? '').toUpperCase() + + (word.slice(1) ?? '').toLowerCase() + : word, + ) + .join(' '); + if (data.password) + data.password = await this.hashAndValidatePassword( + data.password, + ignorePwnedPassword, + ); + let initials = data.name.trim().substr(0, 2).toUpperCase(); + if (data.name.includes(' ')) + initials = data.name + .split(' ') + .map((i) => i.trim().substr(0, 1)) + .join('') + .toUpperCase(); + data.profilePictureUrl = + data.profilePictureUrl ?? + `https://ui-avatars.com/api/?name=${initials}&background=${randomColor({ + luminosity: 'light', + })}&color=000000`; + + for await (const emailString of [email, emailSafe]) { + const md5Email = createHash('md5').update(emailString).digest('hex'); + try { + const img = await got( + `https://www.gravatar.com/avatar/${md5Email}?d=404`, + { responseType: 'buffer' }, + ); + if (img.body.byteLength > 1) + data.profilePictureUrl = `https://www.gravatar.com/avatar/${md5Email}?d=mp`; + } catch (error) {} + } + + const user = await this.prisma.users.create({ + data: { + ...data, + emails: { + create: { email: email, emailSafe }, + }, + }, + include: { emails: { select: { id: true } } }, + }); + if (user.emails[0]?.id) + await this.prisma.users.update({ + where: { id: user.id }, + data: { prefersEmail: { connect: { id: user.emails[0].id } } }, + }); + await this.sendEmailVerification(email); + await this.approvedSubnetsService.approveNewSubnet(user.id, ipAddress); + return this.prisma.expose(user); + } + + async sendEmailVerification(email: string, resend = false) { + const emailSafe = safeEmail(email); + const emailDetails = await this.prisma.emails.findFirst({ + where: { emailSafe }, + include: { user: true }, + }); + if (!emailDetails) throw new NotFoundException(USER_NOT_FOUND); + if (emailDetails.isVerified) + throw new ConflictException(EMAIL_VERIFIED_CONFLICT); + this.email.send({ + to: `"${emailDetails.user.name}" <${email}>`, + template: resend + ? 'auth/resend-email-verification' + : 'auth/email-verification', + data: { + name: emailDetails.user.name, + days: 7, + link: `${this.configService.get( + 'frontendUrl', + )}/auth/verify-email?token=${this.tokensService.signJwt( + EMAIL_VERIFY_TOKEN, + { id: emailDetails.user.id }, + '7d', + )}`, + }, + }); + return { queued: true }; + } + + async refresh( + ipAddress: string, + userAgent: string, + token: string, + ): Promise { + if (!token) throw new UnprocessableEntityException(NO_TOKEN_PROVIDED); + const session = await this.prisma.sessions.findFirst({ + where: { token }, + include: { user: true }, + }); + if (!session) throw new NotFoundException(SESSION_NOT_FOUND); + await this.prisma.sessions.updateMany({ + where: { token }, + data: { ipAddress, userAgent }, + }); + return { + accessToken: await this.getAccessToken(session.user), + refreshToken: token, + }; + } + + async logout(token: string): Promise { + if (!token) throw new UnprocessableEntityException(NO_TOKEN_PROVIDED); + const session = await this.prisma.sessions.findFirst({ + where: { token }, + select: { id: true, user: { select: { id: true } } }, + }); + if (!session) throw new NotFoundException(SESSION_NOT_FOUND); + await this.prisma.sessions.delete({ + where: { id: session.id }, + }); + } + + async approveSubnet( + ipAddress: string, + userAgent: string, + token: string, + ): Promise { + if (!token) throw new UnprocessableEntityException(NO_TOKEN_PROVIDED); + const { id } = this.tokensService.verify<{ id: number }>( + APPROVE_SUBNET_TOKEN, + token, + ); + const user = await this.prisma.users.findOne({ where: { id } }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + await this.approvedSubnetsService.approveNewSubnet(id, ipAddress); + return this.loginResponse(ipAddress, userAgent, user); + } + + /** + * Get the two-factor authentication QR code + * @returns Data URI string with QR code image + */ + async getTotpQrCode(userId: number): Promise { + const secret = this.tokensService.generateUuid(); + await this.prisma.users.update({ + where: { id: userId }, + data: { twoFactorSecret: secret }, + }); + const otpauth = this.authenticator.keyuri( + userId.toString(), + this.configService.get('meta.totpServiceName') ?? '', + secret, + ); + return qrcode.toDataURL(otpauth); + } + + /** Enable two-factor authentication */ + async enableMfaMethod( + method: MfaMethod, + userId: number, + code: string, + ): Promise> { + const user = await this.prisma.users.findOne({ + where: { id: userId }, + select: { twoFactorSecret: true, twoFactorMethod: true }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + if (user.twoFactorMethod !== 'NONE') + throw new ConflictException(MFA_ENABLED_CONFLICT); + if (!user.twoFactorSecret) + user.twoFactorSecret = this.tokensService.generateUuid(); + if (!this.authenticator.check(code, user.twoFactorSecret)) + throw new UnauthorizedException(INVALID_MFA_CODE); + const result = await this.prisma.users.update({ + where: { id: userId }, + data: { twoFactorMethod: method, twoFactorSecret: user.twoFactorSecret }, + }); + return this.prisma.expose(result); + } + + async loginWithTotp( + ipAddress: string, + userAgent: string, + token: string, + code: string, + ): Promise { + const { id } = this.tokensService.verify( + MULTI_FACTOR_TOKEN, + token, + ); + return this.loginUserWithTotpCode(ipAddress, userAgent, id, code); + } + + async loginWithEmailToken( + ipAddress: string, + userAgent: string, + token: string, + ): Promise { + const { id } = this.tokensService.verify( + EMAIL_MFA_TOKEN, + token, + ); + const user = await this.prisma.users.findOne({ where: { id } }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + await this.approvedSubnetsService.upsertNewSubnet(id, ipAddress); + return this.loginResponse(ipAddress, userAgent, user); + } + + async requestPasswordReset(email: string) { + const emailSafe = safeEmail(email); + const emailDetails = await this.prisma.emails.findFirst({ + where: { emailSafe }, + include: { user: true }, + }); + if (!emailDetails) throw new NotFoundException(USER_NOT_FOUND); + this.email.send({ + to: `"${emailDetails.user.name}" <${email}>`, + template: 'auth/password-reset', + data: { + name: emailDetails.user.name, + minutes: 30, + link: `${this.configService.get( + 'frontendUrl', + )}/auth/reset-password?token=${this.tokensService.signJwt( + PASSWORD_RESET_TOKEN, + { id: emailDetails.user.id }, + '30m', + )}`, + }, + }); + return { queued: true }; + } + + async resetPassword( + ipAddress: string, + userAgent: string, + token: string, + password: string, + ignorePwnedPassword?: boolean, + ): Promise { + const { id } = this.tokensService.verify<{ id: number }>( + PASSWORD_RESET_TOKEN, + token, + ); + const user = await this.prisma.users.findOne({ where: { id } }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + password = await this.hashAndValidatePassword( + password, + !!ignorePwnedPassword, + ); + await this.prisma.users.update({ where: { id }, data: { password } }); + await this.approvedSubnetsService.upsertNewSubnet(id, ipAddress); + return this.loginResponse(ipAddress, userAgent, user); + } + + async verifyEmail(token: string): Promise> { + const { id } = this.tokensService.verify<{ id: number }>( + EMAIL_VERIFY_TOKEN, + token, + ); + const result = await this.prisma.emails.update({ + where: { id }, + data: { isVerified: true }, + }); + return this.prisma.expose(result); + } + + getOneTimePassword(secret: string): string { + return this.authenticator.generate(secret); + } + + private async loginUserWithTotpCode( + ipAddress: string, + userAgent: string, + id: number, + code: string, + ): Promise { + const user = await this.prisma.users.findOne({ + where: { id }, + include: { prefersEmail: true }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + if (user.twoFactorMethod === 'NONE' || !user.twoFactorSecret) + throw new BadRequestException(MFA_NOT_ENABLED); + if (this.authenticator.check(code, user.twoFactorSecret)) + return this.loginResponse(ipAddress, userAgent, user); + const backupCodes = await this.prisma.backupCodes.findMany({ + where: { user: { id } }, + }); + let usedBackupCode = false; + for await (const backupCode of backupCodes) { + if (await compare(code, backupCode.code)) { + if (!usedBackupCode) { + if (backupCode.isUsed) + throw new UnauthorizedException(MFA_BACKUP_CODE_USED); + usedBackupCode = true; + await this.prisma.backupCodes.update({ + where: { id: backupCode.id }, + data: { isUsed: true }, + }); + const location = await this.geolocationService.getLocation(ipAddress); + const locationName = + [ + location?.city?.names?.en, + (location?.subdivisions ?? [])[0]?.names?.en, + location?.country?.names?.en, + ] + .filter((i) => i) + .join(', ') || 'Unknown location'; + if (user.prefersEmail) + this.email.send({ + to: `"${user.name}" <${user.prefersEmail.emailSafe}>`, + template: 'auth/used-backup-code', + data: { + name: user.name, + locationName, + link: `${this.configService.get( + 'frontendUrl', + )}/users/${id}/sessions`, + }, + }); + } + } + } + if (!usedBackupCode) throw new UnauthorizedException(INVALID_MFA_CODE); + return this.loginResponse(ipAddress, userAgent, user); + } + + private async getAccessToken(user: users): Promise { + const scopes = await this.getScopes(user); + const payload: AccessTokenClaims = { + sub: LOGIN_ACCESS_TOKEN, + id: user.id, + scopes, + }; + return this.jwtService.sign(payload, { + expiresIn: this.configService.get('security.accessTokenExpiry'), + }); + } + + private async loginResponse( + ipAddress: string, + userAgent: string, + user: users, + ): Promise { + const token = this.tokensService.generateUuid(); + await this.prisma.sessions.create({ + data: { token, ipAddress, userAgent, user: { connect: { id: user.id } } }, + }); + return { + accessToken: await this.getAccessToken(user), + refreshToken: token, + }; + } + + private async mfaResponse( + user: users & { + prefersEmail: emails; + }, + forceMethod?: MfaMethod, + ): Promise { + const mfaTokenPayload: MfaTokenPayload = { + type: user.twoFactorMethod, + id: user.id, + }; + const totpToken = this.tokensService.signJwt( + MULTI_FACTOR_TOKEN, + mfaTokenPayload, + this.configService.get('security.mfaTokenExpiry'), + ); + if (user.twoFactorMethod === 'EMAIL' || forceMethod === 'EMAIL') { + this.email.send({ + to: `"${user.name}" <${user.prefersEmail.email}>`, + template: 'auth/mfa-code', + data: { + name: user.name, + minutes: parseInt( + this.configService.get('security.mfaTokenExpiry') ?? '', + ), + link: `${this.configService.get( + 'frontendUrl', + )}/auth/token-login?token=${this.tokensService.signJwt( + EMAIL_MFA_TOKEN, + { id: user.id }, + '30m', + )}`, + }, + }); + } else if (user.twoFactorMethod === 'SMS' || forceMethod === 'SMS') { + if (!user.twoFactorPhone) + throw new BadRequestException(MFA_PHONE_NOT_FOUND); + this.twilioService.send({ + to: user.twoFactorPhone, + body: `${this.getOneTimePassword(user.twoFactorSecret)} is your ${ + this.configService.get('sms.smsServiceName') ?? '' + } verification code.`, + }); + } + return { totpToken, type: user.twoFactorMethod, multiFactorRequired: true }; + } + + private async checkLoginSubnet( + ipAddress: string, + _: string, // userAgent + checkLocationOnLogin: boolean, + id: number, + ): Promise { + if (!checkLocationOnLogin) return; + const subnet = anonymize(ipAddress); + const previousSubnets = await this.prisma.approvedSubnets.findMany({ + where: { user: { id } }, + }); + let isApproved = false; + for await (const item of previousSubnets) { + if (!isApproved) + if (await compare(subnet, item.subnet)) isApproved = true; + } + if (!isApproved) { + const user = await this.prisma.users.findOne({ + where: { id }, + select: { name: true, prefersEmail: true }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + const location = await this.geolocationService.getLocation(ipAddress); + const locationName = + [ + location?.city?.names?.en, + (location?.subdivisions ?? [])[0]?.names?.en, + location?.country?.names?.en, + ] + .filter((i) => i) + .join(', ') || 'Unknown location'; + if (user.prefersEmail) + this.email.send({ + to: `"${user.name}" <${user.prefersEmail.emailSafe}>`, + template: 'auth/approve-subnets', + data: { + name: user.name, + locationName, + minutes: 30, + link: `${this.configService.get( + 'frontendUrl', + )}/auth/reset-password?token=${this.tokensService.signJwt( + APPROVE_SUBNET_TOKEN, + { id }, + '30m', + )}`, + }, + }); + throw new UnauthorizedException(UNVERIFIED_LOCATION); + } + } + + async hashAndValidatePassword( + password: string, + ignorePwnedPassword: boolean, + ): Promise { + if (!ignorePwnedPassword) { + if (!this.configService.get('security.passwordPwnedCheck')) + return await hash( + password, + this.configService.get('security.saltRounds') ?? 10, + ); + if (!(await this.pwnedService.isPasswordSafe(password))) + throw new BadRequestException(COMPROMISED_PASSWORD); + } + return await hash( + password, + this.configService.get('security.saltRounds') ?? 10, + ); + } + + async getScopes(user: users): Promise { + const scopes: string[] = [`user-${user.id}:*`]; + const memberships = await this.prisma.memberships.findMany({ + where: { user: { id: user.id } }, + select: { id: true, role: true, group: { select: { id: true } } }, + }); + memberships.forEach((membership) => { + scopes.push(`membership-${membership.id}:*`); + if (membership.role === 'OWNER') + scopes.push(`group-${membership.group.id}:*`); + + // Admins cannot delete a group, but they can read/write + if (membership.role === 'ADMIN') + scopes.push(`group-${membership.group.id}:write-*`); + + // Non-owners (admins and regular members) can also read + if (membership.role !== 'OWNER') + scopes.push(`group-${membership.group.id}:read-*`); + }); + return scopes; + } +} diff --git a/src/modules/auth/public.decorator.ts b/src/modules/auth/public.decorator.ts new file mode 100644 index 000000000..5446e1768 --- /dev/null +++ b/src/modules/auth/public.decorator.ts @@ -0,0 +1,16 @@ +import { STAART_PUBLIC_ENDPOINT } from './auth.constants'; + +export function Public() { + return ( + target: any, + _?: string | symbol, + descriptor?: TypedPropertyDescriptor, + ) => { + if (descriptor) { + Reflect.defineMetadata(STAART_PUBLIC_ENDPOINT, true, descriptor.value); + return descriptor; + } + Reflect.defineMetadata(STAART_PUBLIC_ENDPOINT, true, target); + return target; + }; +} diff --git a/src/modules/auth/scope.decorator.ts b/src/modules/auth/scope.decorator.ts new file mode 100644 index 000000000..437bffc6b --- /dev/null +++ b/src/modules/auth/scope.decorator.ts @@ -0,0 +1,3 @@ +import { SetMetadata } from '@nestjs/common'; + +export const Scopes = (...scopes: string[]) => SetMetadata('scopes', scopes); diff --git a/src/modules/auth/scope.guard.ts b/src/modules/auth/scope.guard.ts new file mode 100644 index 000000000..9e868c52d --- /dev/null +++ b/src/modules/auth/scope.guard.ts @@ -0,0 +1,26 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import minimatch from 'minimatch'; +import { AccessTokenParsed, UserRequest } from './auth.interface'; + +@Injectable() +export class ScopesGuard implements CanActivate { + constructor(private reflector: Reflector) {} + + canActivate(context: ExecutionContext): boolean { + const scopes = this.reflector.get('scopes', context.getHandler()); + const request = context.switchToHttp().getRequest(); + if (!scopes) return true; + const user: AccessTokenParsed = request.user; + let authorized = false; + for (const userScope of user.scopes) { + for (let scope of scopes) { + for (const key in request.params) + scope = scope.replace(`{${key}}`, request.params[key]); + authorized = authorized || minimatch(scope, userScope); + if (authorized) return true; + } + } + return authorized; + } +} diff --git a/src/modules/auth/staart-auth.guard.ts b/src/modules/auth/staart-auth.guard.ts new file mode 100644 index 000000000..88fd51a40 --- /dev/null +++ b/src/modules/auth/staart-auth.guard.ts @@ -0,0 +1,19 @@ +import { ExecutionContext, Injectable } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { AuthGuard } from '@nestjs/passport'; +import { STAART_PUBLIC_ENDPOINT } from './auth.constants'; + +@Injectable() +export class StaartAuthGuard extends AuthGuard('staart') { + constructor(private readonly reflector: Reflector) { + super(); + } + + public canActivate(context: ExecutionContext) { + const decoratorSkip = + this.reflector.get(STAART_PUBLIC_ENDPOINT, context.getClass()) || + this.reflector.get(STAART_PUBLIC_ENDPOINT, context.getHandler()); + if (decoratorSkip) return true; + return super.canActivate(context); + } +} diff --git a/src/modules/auth/staart.strategy.ts b/src/modules/auth/staart.strategy.ts new file mode 100644 index 000000000..e7d9e9cf5 --- /dev/null +++ b/src/modules/auth/staart.strategy.ts @@ -0,0 +1,87 @@ +import { Injectable } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { Request } from 'express'; +import ipRangeCheck from 'ip-range-check'; +import minimatch from 'minimatch'; +import { Strategy } from 'passport-strategy'; +import { getClientIp } from 'request-ip'; +import { ApiKeysService } from '../api-keys/api-keys.service'; +import { LOGIN_ACCESS_TOKEN } from '../tokens/tokens.constants'; +import { TokensService } from '../tokens/tokens.service'; +import { AccessTokenClaims, AccessTokenParsed } from './auth.interface'; + +class StaartStrategyName extends Strategy { + name = 'staart'; +} + +@Injectable() +export class StaartStrategy extends PassportStrategy(StaartStrategyName) { + constructor( + private apiKeyService: ApiKeysService, + private tokensService: TokensService, + ) { + super(); + } + + private safeSuccess(result: AccessTokenParsed) { + return this.success(result); + } + + async authenticate(request: Request) { + /** API key authorization */ + let apiKey = + request.query['api_key'] ?? + request.headers['x-api-key'] ?? + request.headers.authorization; + if (typeof apiKey === 'string') { + if (apiKey.startsWith('Bearer ')) apiKey = apiKey.replace('Bearer ', ''); + try { + const apiKeyDetails = await this.apiKeyService.getApiKeyFromKey(apiKey); + const referer = request.headers.referer; + if (Array.isArray(apiKeyDetails.referrerRestrictions) && referer) { + let referrerRestrictionsMet = !apiKeyDetails.referrerRestrictions + .length; + apiKeyDetails.referrerRestrictions.forEach((restriction) => { + referrerRestrictionsMet = + referrerRestrictionsMet || + minimatch(referer, restriction as string); + }); + if (!referrerRestrictionsMet) + return this.fail('Referrer restrictions not met', 401); + } + if ( + Array.isArray(apiKeyDetails.ipRestrictions) && + apiKeyDetails.ipRestrictions.length + ) { + const ipAddress = getClientIp(request); + if ( + !ipRangeCheck(ipAddress, apiKeyDetails.ipRestrictions as string[]) + ) + return this.fail('IP address restrictions not met', 401); + } + return this.safeSuccess({ + type: 'api-key', + id: apiKeyDetails.id, + scopes: apiKeyDetails.scopes as string[], + }); + } catch (error) {} + } + + /** Bearer JWT authorization */ + let bearerToken = request.headers.authorization; + if (typeof bearerToken !== 'string') + return this.fail('No token found', 401); + if (bearerToken.startsWith('Bearer ')) + bearerToken = bearerToken.replace('Bearer ', ''); + try { + const payload = this.tokensService.verify( + LOGIN_ACCESS_TOKEN, + bearerToken, + ) as AccessTokenClaims; + const { id, scopes } = payload; + return this.safeSuccess({ type: 'user', id, scopes }); + } catch (error) {} + + return this.fail('Invalid token', 401); + } +} diff --git a/src/modules/dns/dns.interface.ts b/src/modules/dns/dns.interface.ts new file mode 100644 index 000000000..4e9cae6e4 --- /dev/null +++ b/src/modules/dns/dns.interface.ts @@ -0,0 +1,23 @@ +import { AnyRecord, MxRecord, NaptrRecord, SoaRecord, SrvRecord } from 'dns'; + +export type RecordType = + | 'A' + | 'AAAA' + | 'ANY' + | 'CNAME' + | 'MX' + | 'NAPTR' + | 'NS' + | 'PTR' + | 'SOA' + | 'SRV' + | 'TXT'; + +export type RecordResult = + | Array + | Array + | Array + | SoaRecord + | Array + | Array> + | Array; diff --git a/src/modules/dns/dns.module.ts b/src/modules/dns/dns.module.ts new file mode 100644 index 000000000..7b9f72948 --- /dev/null +++ b/src/modules/dns/dns.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { DnsService } from './dns.service'; + +@Module({ + providers: [DnsService], + exports: [DnsService], +}) +export class DnsModule {} diff --git a/src/modules/dns/dns.service.ts b/src/modules/dns/dns.service.ts new file mode 100644 index 000000000..d52f4227b --- /dev/null +++ b/src/modules/dns/dns.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common'; +import dns from 'dns'; +import { RecordResult, RecordType } from './dns.interface'; + +@Injectable() +export class DnsService { + async lookup( + hostname: string, + recordType: RecordType, + ): Promise { + try { + return await this.unsafeLookup(hostname, recordType); + } catch (error) { + return []; + } + } + + private unsafeLookup( + hostname: string, + recordType: RecordType, + ): Promise { + return new Promise((resolve, reject) => { + dns.resolve(hostname, recordType, (error, records) => { + if (error) return reject(error); + resolve(records); + }); + }); + } +} diff --git a/src/modules/domains/domains.constants.ts b/src/modules/domains/domains.constants.ts new file mode 100644 index 000000000..842894c6f --- /dev/null +++ b/src/modules/domains/domains.constants.ts @@ -0,0 +1,2 @@ +export const DOMAIN_VERIFICATION_TXT = 'DOMAIN_VERIFICATION_TXT'; +export const DOMAIN_VERIFICATION_HTML = 'DOMAIN_VERIFICATION_HTML'; diff --git a/src/modules/domains/domains.controller.ts b/src/modules/domains/domains.controller.ts new file mode 100644 index 000000000..49530d99c --- /dev/null +++ b/src/modules/domains/domains.controller.ts @@ -0,0 +1,105 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from '@nestjs/common'; +import { domains } from '@prisma/client'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { Expose } from '../prisma/prisma.interface'; +import { + DOMAIN_VERIFICATION_HTML, + DOMAIN_VERIFICATION_TXT, +} from './domains.constants'; +import { CreateDomainDto } from './domains.dto'; +import { DomainsService } from './domains.service'; + +@Controller('groups/:groupId/domains') +export class DomainController { + constructor(private domainsService: DomainsService) {} + + @Post() + @AuditLog('create-domain') + @Scopes('group-{groupId}:write-domain-*') + async create( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: CreateDomainDto, + ): Promise> { + return this.domainsService.createDomain(groupId, data); + } + + @Get() + @Scopes('group-{groupId}:read-domain-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.domainsService.getDomains(groupId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-domain-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.domainsService.getDomain(groupId, Number(id)); + } + + @Delete(':id') + @AuditLog('delete-domain') + @Scopes('group-{groupId}:delete-domain-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.domainsService.deleteDomain(groupId, Number(id)); + } + + @Post(':id/verify/txt') + @AuditLog('verify-domain-txt') + @Scopes('group-{groupId}:write-domain-{id}') + async verifyTxt( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.domainsService.verifyDomain( + groupId, + Number(id), + DOMAIN_VERIFICATION_TXT, + ); + } + + @Post(':id/verify/html') + @AuditLog('verify-domain-html') + @Scopes('group-{groupId}:write-domain-{id}') + async verifyHtml( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.domainsService.verifyDomain( + groupId, + Number(id), + DOMAIN_VERIFICATION_HTML, + ); + } +} diff --git a/src/modules/domains/domains.dto.ts b/src/modules/domains/domains.dto.ts new file mode 100644 index 000000000..148cfbbb7 --- /dev/null +++ b/src/modules/domains/domains.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class CreateDomainDto { + @IsString() + @IsNotEmpty() + domain: string; +} diff --git a/src/modules/domains/domains.interface.ts b/src/modules/domains/domains.interface.ts new file mode 100644 index 000000000..f4ce18aa7 --- /dev/null +++ b/src/modules/domains/domains.interface.ts @@ -0,0 +1,8 @@ +import { + DOMAIN_VERIFICATION_HTML, + DOMAIN_VERIFICATION_TXT, +} from './domains.constants'; + +export type DomainVerificationMethods = + | typeof DOMAIN_VERIFICATION_TXT + | typeof DOMAIN_VERIFICATION_HTML; diff --git a/src/modules/domains/domains.module.ts b/src/modules/domains/domains.module.ts new file mode 100644 index 000000000..efb865f48 --- /dev/null +++ b/src/modules/domains/domains.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { DnsModule } from '../dns/dns.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { DomainController } from './domains.controller'; +import { DomainsService } from './domains.service'; + +@Module({ + imports: [PrismaModule, TokensModule, DnsModule, ConfigModule], + controllers: [DomainController], + providers: [DomainsService], +}) +export class DomainsModule {} diff --git a/src/modules/domains/domains.service.ts b/src/modules/domains/domains.service.ts new file mode 100644 index 000000000..790cfdfb6 --- /dev/null +++ b/src/modules/domains/domains.service.ts @@ -0,0 +1,158 @@ +import { + BadRequestException, + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + domains, + domainsCreateInput, + domainsOrderByInput, + domainsWhereInput, + domainsWhereUniqueInput, +} from '@prisma/client'; +import got from 'got'; +import { + DOMAIN_NOT_FOUND, + DOMAIN_NOT_VERIFIED, + UNAUTHORIZED_RESOURCE, +} from 'src/errors/errors.constants'; +import { URL } from 'url'; +import { DnsService } from '../dns/dns.service'; +import { Expose } from '../prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; +import { TokensService } from '../tokens/tokens.service'; +import { DOMAIN_VERIFICATION_TXT } from './domains.constants'; +import { DomainVerificationMethods } from './domains.interface'; + +@Injectable() +export class DomainsService { + constructor( + private prisma: PrismaService, + private tokensService: TokensService, + private dnsService: DnsService, + private configService: ConfigService, + ) {} + + async createDomain( + groupId: number, + data: Omit, 'verificationCode'>, + ): Promise { + const fullUrl = new URL(data.domain); + data.domain = fullUrl.hostname; + const verificationCode = this.tokensService.generateUuid(); + const currentProfilePicture = await this.prisma.groups.findOne({ + where: { id: groupId }, + select: { profilePictureUrl: true }, + }); + if ( + currentProfilePicture.profilePictureUrl.startsWith( + 'https://ui-avatars.com', + ) + ) + try { + const img = await got('https://logo.clearbit.com/${data.domain}', { + responseType: 'buffer', + }); + if (img.body.byteLength > 1) + await this.prisma.groups.update({ + where: { id: groupId }, + data: { + profilePictureUrl: `https://logo.clearbit.com/${data.domain}`, + }, + }); + } catch (error) {} + + return this.prisma.domains.create({ + data: { + ...data, + verificationCode, + group: { connect: { id: groupId } }, + }, + }); + } + + async getDomains( + groupId: number, + params: { + skip?: number; + take?: number; + cursor?: domainsWhereUniqueInput; + where?: domainsWhereInput; + orderBy?: domainsOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const domains = await this.prisma.domains.findMany({ + skip, + take, + cursor, + where: { ...where, group: { id: groupId } }, + orderBy, + }); + return domains.map((group) => this.prisma.expose(group)); + } + + async getDomain(groupId: number, id: number): Promise> { + const domain = await this.prisma.domains.findOne({ + where: { id }, + }); + if (!domain) throw new NotFoundException(DOMAIN_NOT_FOUND); + if (domain.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(domain); + } + + async verifyDomain( + groupId: number, + id: number, + method: DomainVerificationMethods, + ): Promise> { + const domain = await this.prisma.domains.findOne({ + where: { id }, + }); + if (!domain) throw new NotFoundException(DOMAIN_NOT_FOUND); + if (domain.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + if (method === DOMAIN_VERIFICATION_TXT) { + const txtRecords = await this.dnsService.lookup(domain.domain, 'TXT'); + if (JSON.stringify(txtRecords).includes(domain.verificationCode)) { + await this.prisma.domains.update({ + where: { id }, + data: { isVerified: true }, + }); + } else throw new BadRequestException(DOMAIN_NOT_VERIFIED); + } else { + let verified = false; + try { + const { body } = await got( + `http://${domain.domain}/.well-known/${this.configService.get( + 'meta.domainVerificationFile' ?? 'staart-verify.txt', + )}`, + ); + verified = body.includes(domain.verificationCode); + } catch (error) {} + if (verified) { + await this.prisma.domains.update({ + where: { id }, + data: { isVerified: true }, + }); + } else throw new BadRequestException(DOMAIN_NOT_VERIFIED); + } + return domain; + } + + async deleteDomain(groupId: number, id: number): Promise> { + const testDomain = await this.prisma.domains.findOne({ + where: { id }, + }); + if (!testDomain) throw new NotFoundException(DOMAIN_NOT_FOUND); + if (testDomain.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const domain = await this.prisma.domains.delete({ + where: { id }, + }); + return this.prisma.expose(domain); + } +} diff --git a/src/modules/email/email.interface.ts b/src/modules/email/email.interface.ts new file mode 100644 index 000000000..f5cf6f138 --- /dev/null +++ b/src/modules/email/email.interface.ts @@ -0,0 +1,17 @@ +export interface EmailConfig { + name: string; + from: string; + host: string; + port: number; + secure: boolean; + auth: { + user: string; + pass: string; + }; +} + +export interface EmailOptions { + template?: string; + data?: Record; + noLayout?: boolean; +} diff --git a/src/modules/email/email.module.ts b/src/modules/email/email.module.ts new file mode 100644 index 000000000..ea91e132c --- /dev/null +++ b/src/modules/email/email.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { EmailService } from './email.service'; + +@Module({ + imports: [ConfigModule], + providers: [EmailService], + exports: [EmailService], +}) +export class EmailModule {} diff --git a/src/modules/email/email.service.ts b/src/modules/email/email.service.ts new file mode 100644 index 000000000..d7b9938b5 --- /dev/null +++ b/src/modules/email/email.service.ts @@ -0,0 +1,82 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { render } from '@staart/mustache-markdown'; +import { promises as fs } from 'fs'; +import mem from 'mem'; +import nodemailer from 'nodemailer'; +import Mail from 'nodemailer/lib/mailer'; +import PQueue from 'p-queue'; +import pRetry from 'p-retry'; +import { join } from 'path'; +import { EmailConfig, EmailOptions } from './email.interface'; + +@Injectable() +export class EmailService { + private readonly logger = new Logger(EmailService.name); + private transport: Mail; + private config: EmailConfig; + private queue = new PQueue({ concurrency: 1 }); + private readTemplate = mem(this.readTemplateUnmemoized); + + constructor(private configService: ConfigService) { + const emailConfig = this.configService.get('email'); + if (emailConfig) this.config = emailConfig; + this.transport = nodemailer.createTransport(this.config); + } + + send(options: Mail.Options & EmailOptions) { + this.queue + .add(() => + pRetry( + () => + this.sendEmail({ + ...options, + from: + options.from ?? `"${this.config.name}" <${this.config.from}>`, + }), + { + retries: 3, + onFailedAttempt: (error) => { + this.logger.error( + `Email to ${options.to} failed, retrying (${error.retriesLeft} attempts left)`, + error.name, + ); + }, + }, + ), + ) + .then(() => {}) + .catch(() => {}); + } + + private async sendEmail(options: Mail.Options & EmailOptions) { + if (options.template) { + const layout = await this.readTemplate('layout.html'); + let template = await this.readTemplate(options.template); + if (template.startsWith('#')) { + const subject = template.split('\n', 1)[0].replace('#', '').trim(); + if (subject) { + options.subject = options.subject ?? subject; + template = template.replace(`# ${template.split('\n', 1)[0]}`, ''); + } + } + const [markdown, html] = render(template, options.data); + options.html = options.noLayout + ? html + : render(layout, { content: html })[1]; + options.text = markdown; + options.alternatives = [ + { + contentType: 'text/x-web-markdown', + content: markdown, + }, + ]; + } + return this.transport.sendMail(options); + } + + private async readTemplateUnmemoized(name: string) { + if (!name.endsWith('.html')) name = `${name}.md`; + return fs.readFile(join('.', 'src', 'templates', name), 'utf8'); + } +} diff --git a/src/modules/emails/emails.controller.ts b/src/modules/emails/emails.controller.ts new file mode 100644 index 000000000..5500ba217 --- /dev/null +++ b/src/modules/emails/emails.controller.ts @@ -0,0 +1,70 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from '@nestjs/common'; +import { emails } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { CreateEmailDto } from './emails.dto'; +import { EmailsService } from './emails.service'; + +@Controller('users/:userId/emails') +export class EmailController { + constructor(private emailsService: EmailsService) {} + + @Post() + @Scopes('user-{userId}:write-email-*') + async create( + @Param('userId', ParseIntPipe) userId: number, + @Body() data: CreateEmailDto, + ): Promise> { + return this.emailsService.createEmail(userId, data); + } + + @Get() + @Scopes('user-{userId}:read-email-*') + async getAll( + @Param('userId', ParseIntPipe) userId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.emailsService.getEmails(userId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('user-{userId}:read-email-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.emailsService.getEmail(userId, Number(id)); + } + + @Delete(':id') + @Scopes('user-{userId}:delete-email-{id}') + async remove( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.emailsService.deleteEmail(userId, Number(id)); + } +} diff --git a/src/modules/emails/emails.dto.ts b/src/modules/emails/emails.dto.ts new file mode 100644 index 000000000..c95fc7313 --- /dev/null +++ b/src/modules/emails/emails.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class CreateEmailDto { + @IsString() + @IsNotEmpty() + email!: string; +} diff --git a/src/modules/emails/emails.module.ts b/src/modules/emails/emails.module.ts new file mode 100644 index 000000000..339be135b --- /dev/null +++ b/src/modules/emails/emails.module.ts @@ -0,0 +1,37 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { JwtModule } from '@nestjs/jwt'; +import { ApprovedSubnetsService } from '../approved-subnets/approved-subnets.service'; +import { AuthService } from '../auth/auth.service'; +import { EmailModule } from '../email/email.module'; +import { GeolocationService } from '../geolocation/geolocation.service'; +import { PrismaModule } from '../prisma/prisma.module'; +import { PwnedModule } from '../pwned/pwned.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { TwilioModule } from '../twilio/twilio.module'; +import { UsersService } from '../users/users.service'; +import { EmailController } from './emails.controller'; +import { EmailsService } from './emails.service'; + +@Module({ + imports: [ + PrismaModule, + EmailModule, + ConfigModule, + TwilioModule, + PwnedModule, + TokensModule, + JwtModule.register({ + secret: process.env.JWT_SECRET ?? 'staart', + }), + ], + controllers: [EmailController], + providers: [ + EmailsService, + UsersService, + AuthService, + GeolocationService, + ApprovedSubnetsService, + ], +}) +export class EmailsModule {} diff --git a/src/modules/emails/emails.service.ts b/src/modules/emails/emails.service.ts new file mode 100644 index 000000000..a497065c8 --- /dev/null +++ b/src/modules/emails/emails.service.ts @@ -0,0 +1,86 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { + emails, + emailsCreateInput, + emailsOrderByInput, + emailsWhereInput, + emailsWhereUniqueInput, +} from '@prisma/client'; +import { + EMAIL_NOT_FOUND, + UNAUTHORIZED_RESOURCE, +} from 'src/errors/errors.constants'; +import { safeEmail } from '../../helpers/safe-email'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { AuthService } from '../auth/auth.service'; +import { PrismaService } from '../prisma/prisma.service'; +import { UsersService } from '../users/users.service'; + +@Injectable() +export class EmailsService { + constructor( + private prisma: PrismaService, + private users: UsersService, + private auth: AuthService, + ) {} + + async createEmail( + userId: number, + data: Omit, 'user'>, + ): Promise { + const emailSafe = safeEmail(data.email); + const result = await this.prisma.emails.create({ + data: { ...data, emailSafe, user: { connect: { id: userId } } }, + }); + await this.auth.sendEmailVerification(data.email); + return result; + } + + async getEmails( + userId: number, + params: { + skip?: number; + take?: number; + cursor?: emailsWhereUniqueInput; + where?: emailsWhereInput; + orderBy?: emailsOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const emails = await this.prisma.emails.findMany({ + skip, + take, + cursor, + where: { ...where, user: { id: userId } }, + orderBy, + }); + return emails.map((user) => this.prisma.expose(user)); + } + + async getEmail(userId: number, id: number): Promise> { + const email = await this.prisma.emails.findOne({ + where: { id }, + }); + if (!email) throw new NotFoundException(EMAIL_NOT_FOUND); + if (email.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(email); + } + + async deleteEmail(userId: number, id: number): Promise> { + const testEmail = await this.prisma.emails.findOne({ + where: { id }, + }); + if (!testEmail) throw new NotFoundException(EMAIL_NOT_FOUND); + if (testEmail.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const email = await this.prisma.emails.delete({ + where: { id }, + }); + return this.prisma.expose(email); + } +} diff --git a/src/modules/geolocation/geolocation.module.ts b/src/modules/geolocation/geolocation.module.ts new file mode 100644 index 000000000..fb715da2a --- /dev/null +++ b/src/modules/geolocation/geolocation.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { GeolocationService } from './geolocation.service'; + +@Module({ + imports: [ConfigModule], + providers: [GeolocationService], + exports: [GeolocationService], +}) +export class GeolocationModule {} diff --git a/src/modules/geolocation/geolocation.service.ts b/src/modules/geolocation/geolocation.service.ts new file mode 100644 index 000000000..c874dc2c7 --- /dev/null +++ b/src/modules/geolocation/geolocation.service.ts @@ -0,0 +1,51 @@ +import { Injectable, OnModuleDestroy } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import geolite2 from 'geolite2-redist'; +import maxmind, { CityResponse, Reader } from 'maxmind'; +import QuickLRU from 'quick-lru'; + +@Injectable() +export class GeolocationService implements OnModuleDestroy { + constructor(private configService: ConfigService) {} + + private lookup: Reader | null = null; + private lru = new QuickLRU>({ + maxSize: + this.configService.get('caching.geolocationLruSize') ?? 100, + }); + + onModuleDestroy() { + if (this.lookup) this.lookup = null; + } + + /** Get the geolocation from an IP address */ + async getLocation(ipAddress: string): Promise> { + if (this.lru.has(ipAddress)) return this.lru.get(ipAddress) ?? {}; + const result = await this.getSafeLocation(ipAddress); + this.lru.set(ipAddress, result); + return result; + } + + private async getSafeLocation( + ipAddress: string, + ): Promise> { + try { + return this.getUnsafeLocation(ipAddress); + } catch (error) { + return {}; + } + } + + private async getUnsafeLocation( + ipAddress: string, + ): Promise> { + if (!this.lookup) + this.lookup = await geolite2.open( + 'GeoLite2-City', + (path) => { + return maxmind.open(path); + }, + ); + return this.lookup.get(ipAddress) ?? {}; + } +} diff --git a/src/modules/groups/groups.controller.ts b/src/modules/groups/groups.controller.ts new file mode 100644 index 000000000..7f859a92f --- /dev/null +++ b/src/modules/groups/groups.controller.ts @@ -0,0 +1,77 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Put, + Query, +} from '@nestjs/common'; +import { groups } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { ReplaceGroupDto, UpdateGroupDto } from './groups.dto'; +import { GroupsService } from './groups.service'; + +@Controller('groups') +export class GroupController { + constructor(private groupsService: GroupsService) {} + + @Get() + @Scopes('group-*:read-info') + async getAll( + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.groupsService.getGroups({ + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('group-{id}:read-info') + async get(@Param('id', ParseIntPipe) id: number): Promise> { + return this.groupsService.getGroup(Number(id)); + } + + @Patch(':id') + @AuditLog('update-info') + @Scopes('group-{id}:write-info') + async update( + @Body() data: UpdateGroupDto, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.groupsService.updateGroup(Number(id), data); + } + + @Put(':id') + @AuditLog('update-info') + @Scopes('group-{id}:write-info') + async replace( + @Body() data: ReplaceGroupDto, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.groupsService.updateGroup(Number(id), data); + } + + @Delete(':id') + @AuditLog('delete') + @Scopes('group-{id}:delete') + async remove(@Param('id', ParseIntPipe) id: number): Promise> { + return this.groupsService.deleteGroup(Number(id)); + } +} diff --git a/src/modules/groups/groups.dto.ts b/src/modules/groups/groups.dto.ts new file mode 100644 index 000000000..99098b8c8 --- /dev/null +++ b/src/modules/groups/groups.dto.ts @@ -0,0 +1,98 @@ +import { + IsArray, + IsBoolean, + IsNotEmpty, + IsObject, + IsOptional, + IsString, +} from 'class-validator'; + +export class CreateGroupDto { + @IsBoolean() + @IsOptional() + autoJoinDomain?: boolean; + + @IsBoolean() + @IsOptional() + forceTwoFactor?: boolean; + + @IsArray() + @IsOptional() + ipRestrictions?: string; + + @IsString() + @IsNotEmpty() + name!: string; + + @IsBoolean() + @IsOptional() + onlyAllowDomain?: boolean; + + @IsString() + @IsOptional() + profilePictureUrl?: string; + + @IsObject() + @IsOptional() + attributes?: Record; +} + +export class UpdateGroupDto { + @IsBoolean() + @IsOptional() + autoJoinDomain?: boolean; + + @IsBoolean() + @IsOptional() + forceTwoFactor?: boolean; + + @IsArray() + @IsOptional() + ipRestrictions?: string; + + @IsString() + @IsOptional() + name?: string; + + @IsBoolean() + @IsOptional() + onlyAllowDomain?: boolean; + + @IsString() + @IsOptional() + profilePictureUrl?: string; + + @IsObject() + @IsOptional() + attributes?: Record; +} + +export class ReplaceGroupDto { + @IsBoolean() + @IsNotEmpty() + autoJoinDomain!: boolean; + + @IsBoolean() + @IsNotEmpty() + forceTwoFactor!: boolean; + + @IsArray() + @IsNotEmpty() + ipRestrictions!: string; + + @IsString() + @IsNotEmpty() + name!: string; + + @IsBoolean() + @IsNotEmpty() + onlyAllowDomain!: boolean; + + @IsString() + @IsNotEmpty() + profilePictureUrl!: string; + + @IsObject() + @IsNotEmpty() + attributes!: Record; +} diff --git a/src/modules/groups/groups.module.ts b/src/modules/groups/groups.module.ts new file mode 100644 index 000000000..8479c8625 --- /dev/null +++ b/src/modules/groups/groups.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from '../prisma/prisma.module'; +import { GroupController } from './groups.controller'; +import { GroupsService } from './groups.service'; + +@Module({ + imports: [PrismaModule], + controllers: [GroupController], + providers: [GroupsService], +}) +export class GroupsModule {} diff --git a/src/modules/groups/groups.service.ts b/src/modules/groups/groups.service.ts new file mode 100644 index 000000000..ce36c889b --- /dev/null +++ b/src/modules/groups/groups.service.ts @@ -0,0 +1,111 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { + groups, + groupsCreateInput, + groupsOrderByInput, + groupsUpdateInput, + groupsWhereInput, + groupsWhereUniqueInput, +} from '@prisma/client'; +import randomColor from 'randomcolor'; +import { GROUP_NOT_FOUND } from 'src/errors/errors.constants'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class GroupsService { + constructor(private prisma: PrismaService) {} + + async createGroup( + userId: number, + data: Omit, 'user'>, + ): Promise { + let initials = data.name.trim().substr(0, 2).toUpperCase(); + if (data.name.includes(' ')) + initials = data.name + .split(' ') + .map((i) => i.trim().substr(0, 1)) + .join('') + .toUpperCase(); + data.profilePictureUrl = + data.profilePictureUrl ?? + `https://ui-avatars.com/api/?name=${initials}&background=${randomColor({ + luminosity: 'light', + })}&color=000000`; + return this.prisma.groups.create({ + data: { + ...data, + memberships: { + create: { role: 'OWNER', user: { connect: { id: userId } } }, + }, + }, + }); + } + + async getGroups(params: { + skip?: number; + take?: number; + cursor?: groupsWhereUniqueInput; + where?: groupsWhereInput; + orderBy?: groupsOrderByInput; + }): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const groups = await this.prisma.groups.findMany({ + skip, + take, + cursor, + where, + orderBy, + }); + return groups.map((user) => this.prisma.expose(user)); + } + + async getGroup(id: number): Promise> { + const group = await this.prisma.groups.findOne({ + where: { id }, + }); + if (!group) throw new NotFoundException(GROUP_NOT_FOUND); + return this.prisma.expose(group); + } + + async updateGroup( + id: number, + data: groupsUpdateInput, + ): Promise> { + const testGroup = await this.prisma.groups.findOne({ + where: { id }, + }); + if (!testGroup) throw new NotFoundException(GROUP_NOT_FOUND); + const group = await this.prisma.groups.update({ + where: { id }, + data, + }); + return this.prisma.expose(group); + } + + async replaceGroup( + id: number, + data: groupsCreateInput, + ): Promise> { + const testGroup = await this.prisma.groups.findOne({ + where: { id }, + }); + if (!testGroup) throw new NotFoundException(GROUP_NOT_FOUND); + const group = await this.prisma.groups.update({ + where: { id }, + data, + }); + return this.prisma.expose(group); + } + + async deleteGroup(id: number): Promise> { + const testGroup = await this.prisma.groups.findOne({ + where: { id }, + }); + if (!testGroup) throw new NotFoundException(GROUP_NOT_FOUND); + const group = await this.prisma.groups.delete({ + where: { id }, + }); + return this.prisma.expose(group); + } +} diff --git a/src/modules/memberships/memberships-group.controller.ts b/src/modules/memberships/memberships-group.controller.ts new file mode 100644 index 000000000..a7585cde8 --- /dev/null +++ b/src/modules/memberships/memberships-group.controller.ts @@ -0,0 +1,94 @@ +import { + Body, + Controller, + Delete, + Get, + Ip, + Param, + ParseIntPipe, + Patch, + Post, + Query, +} from '@nestjs/common'; +import { memberships } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { + CreateGroupMembershipDto, + UpdateMembershipDto, +} from './memberships.dto'; +import { MembershipsService } from './memberships.service'; + +@Controller('groups/:groupId/memberships') +export class GroupMembershipController { + constructor(private membershipsService: MembershipsService) {} + + @Post() + @AuditLog('add-membership') + @Scopes('group-{groupId}:write-membership-*') + async create( + @Ip() ip: string, + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: CreateGroupMembershipDto, + ): Promise> { + return this.membershipsService.createGroupMembership(ip, groupId, data); + } + + @Get() + @Scopes('group-{groupId}:read-membership-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.membershipsService.getMemberships({ + skip, + take, + orderBy, + cursor, + where: { ...where, group: { id: groupId } }, + }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-membership-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.membershipsService.getGroupMembership(groupId, Number(id)); + } + + @Patch(':id') + @AuditLog('update-membership') + @Scopes('group-{groupId}:write-membership-{id}') + async update( + @Body() data: UpdateMembershipDto, + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.membershipsService.updateGroupMembership( + groupId, + Number(id), + data, + ); + } + + @Delete(':id') + @AuditLog('delete-membership') + @Scopes('group-{groupId}:delete-membership-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.membershipsService.deleteGroupMembership(groupId, Number(id)); + } +} diff --git a/src/modules/memberships/memberships-user.controller.ts b/src/modules/memberships/memberships-user.controller.ts new file mode 100644 index 000000000..8d917d1c8 --- /dev/null +++ b/src/modules/memberships/memberships-user.controller.ts @@ -0,0 +1,70 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from '@nestjs/common'; +import { memberships } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { CreateGroupDto } from '../groups/groups.dto'; +import { MembershipsService } from './memberships.service'; + +@Controller('users/:userId/memberships') +export class UserMembershipController { + constructor(private membershipsService: MembershipsService) {} + + @Post() + @Scopes('user-{userId}:write-membership') + async create( + @Param('userId', ParseIntPipe) userId: number, + @Body() data: CreateGroupDto, + ): Promise> { + return this.membershipsService.createUserMembership(userId, data); + } + + @Get() + @Scopes('user-{userId}:read-membership') + async getAll( + @Param('userId', ParseIntPipe) userId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.membershipsService.getMemberships({ + skip, + take, + orderBy, + cursor, + where: { ...where, user: { id: userId } }, + }); + } + + @Get(':id') + @Scopes('user-{userId}:read-membership-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.membershipsService.getUserMembership(userId, Number(id)); + } + + @Delete(':id') + @Scopes('user-{userId}:delete-membership-{id}') + async remove( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.membershipsService.deleteUserMembership(userId, Number(id)); + } +} diff --git a/src/modules/memberships/memberships.dto.ts b/src/modules/memberships/memberships.dto.ts new file mode 100644 index 000000000..b4af63f1c --- /dev/null +++ b/src/modules/memberships/memberships.dto.ts @@ -0,0 +1,31 @@ +import { + IsEmail, + IsIn, + IsNotEmpty, + IsOptional, + IsString, + MinLength, +} from 'class-validator'; + +export class UpdateMembershipDto { + @IsString() + @IsIn(['OWNER', 'ADMIN', 'MEMBER']) + @IsOptional() + role?: 'OWNER' | 'ADMIN' | 'MEMBER'; +} + +export class CreateGroupMembershipDto { + @IsEmail() + @IsNotEmpty() + email!: string; + + @IsString() + @IsOptional() + @MinLength(3) + name?: string; + + @IsString() + @IsIn(['OWNER', 'ADMIN', 'MEMBER']) + @IsOptional() + role?: 'OWNER' | 'ADMIN' | 'MEMBER'; +} diff --git a/src/modules/memberships/memberships.interface.ts b/src/modules/memberships/memberships.interface.ts new file mode 100644 index 000000000..1f2a7d3f1 --- /dev/null +++ b/src/modules/memberships/memberships.interface.ts @@ -0,0 +1,7 @@ +import { MembershipRole } from '@prisma/client'; + +export interface CreateMembershipInput { + email: string; + name?: string; + role?: MembershipRole; +} diff --git a/src/modules/memberships/memberships.module.ts b/src/modules/memberships/memberships.module.ts new file mode 100644 index 000000000..41111f691 --- /dev/null +++ b/src/modules/memberships/memberships.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { AuthModule } from '../auth/auth.module'; +import { EmailModule } from '../email/email.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { GroupMembershipController } from './memberships-group.controller'; +import { UserMembershipController } from './memberships-user.controller'; +import { MembershipsService } from './memberships.service'; + +@Module({ + imports: [PrismaModule, EmailModule, ConfigModule, AuthModule], + controllers: [UserMembershipController, GroupMembershipController], + providers: [MembershipsService], +}) +export class MembershipsModule {} diff --git a/src/modules/memberships/memberships.service.ts b/src/modules/memberships/memberships.service.ts new file mode 100644 index 000000000..e9ce87947 --- /dev/null +++ b/src/modules/memberships/memberships.service.ts @@ -0,0 +1,204 @@ +import { + BadRequestException, + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + groupsCreateInput, + memberships, + membershipsOrderByInput, + membershipsUpdateInput, + membershipsWhereInput, + membershipsWhereUniqueInput, + users, +} from '@prisma/client'; +import { + CANNOT_DELETE_SOLE_MEMBER, + CANNOT_DELETE_SOLE_OWNER, + MEMBERSHIP_NOT_FOUND, + UNAUTHORIZED_RESOURCE, +} from 'src/errors/errors.constants'; +import { safeEmail } from '../../helpers/safe-email'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { AuthService } from '../auth/auth.service'; +import { EmailService } from '../email/email.service'; +import { PrismaService } from '../prisma/prisma.service'; +import { CreateMembershipInput } from './memberships.interface'; + +@Injectable() +export class MembershipsService { + constructor( + private prisma: PrismaService, + private auth: AuthService, + private email: EmailService, + private configService: ConfigService, + ) {} + + async getMemberships(params: { + skip?: number; + take?: number; + cursor?: membershipsWhereUniqueInput; + where?: membershipsWhereInput; + orderBy?: membershipsOrderByInput; + }): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const memberships = await this.prisma.memberships.findMany({ + skip, + take, + cursor, + where, + orderBy, + include: { group: true }, + }); + return memberships.map((user) => this.prisma.expose(user)); + } + + async getUserMembership( + userId: number, + id: number, + ): Promise> { + const membership = await this.prisma.memberships.findOne({ + where: { id }, + include: { group: true }, + }); + if (!membership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if (membership.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(membership); + } + + async getGroupMembership( + groupId: number, + id: number, + ): Promise> { + const membership = await this.prisma.memberships.findOne({ + where: { id }, + include: { group: true }, + }); + if (!membership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if (membership.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(membership); + } + + async deleteUserMembership( + userId: number, + id: number, + ): Promise> { + const testMembership = await this.prisma.memberships.findOne({ + where: { id }, + }); + if (!testMembership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if (testMembership.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + await this.verifyDeleteMembership(testMembership.groupId, id); + const membership = await this.prisma.memberships.delete({ + where: { id }, + }); + return this.prisma.expose(membership); + } + + async updateGroupMembership( + groupId: number, + id: number, + data: membershipsUpdateInput, + ): Promise> { + const testMembership = await this.prisma.memberships.findOne({ + where: { id }, + }); + if (!testMembership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if (testMembership.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const membership = await this.prisma.memberships.update({ + where: { id }, + data, + }); + return this.prisma.expose(membership); + } + + async deleteGroupMembership( + groupId: number, + id: number, + ): Promise> { + const testMembership = await this.prisma.memberships.findOne({ + where: { id }, + }); + if (!testMembership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if (testMembership.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + await this.verifyDeleteMembership(testMembership.groupId, id); + const membership = await this.prisma.memberships.delete({ + where: { id }, + }); + return this.prisma.expose(membership); + } + + async createUserMembership(userId: number, data: groupsCreateInput) { + return this.prisma.memberships.create({ + data: { + role: 'OWNER', + user: { connect: { id: userId } }, + group: { create: data }, + }, + }); + } + + async createGroupMembership( + ipAddress: string, + groupId: number, + data: CreateMembershipInput, + ) { + const emailSafe = safeEmail(data.email); + const userResult = await this.prisma.users.findFirst({ + where: { emails: { some: { emailSafe } } }, + }); + let user: Expose | null = userResult + ? this.prisma.expose(userResult) + : null; + if (!user) + user = await this.auth.register(ipAddress, { name: data.email, ...data }); + const result = await this.prisma.memberships.create({ + data: { + role: data.role, + group: { connect: { id: groupId } }, + user: { connect: { id: user.id } }, + }, + include: { group: { select: { name: true } } }, + }); + this.email.send({ + to: `"${user.name}" <${emailSafe}>`, + template: 'groups/invitation', + data: { + name: user.name, + group: result.group.name, + link: `${this.configService.get( + 'frontendUrl', + )}/groups/${groupId}`, + }, + }); + return this.prisma.expose(result); + } + + /** Verify whether a group membership can be deleted */ + private async verifyDeleteMembership( + groupId: number, + membershipId: number, + ): Promise { + const memberships = await this.prisma.memberships.findMany({ + where: { group: { id: groupId } }, + }); + if (memberships.length === 1) + throw new BadRequestException(CANNOT_DELETE_SOLE_MEMBER); + const membership = await this.prisma.memberships.findOne({ + where: { id: membershipId }, + }); + if (!membership) throw new NotFoundException(MEMBERSHIP_NOT_FOUND); + if ( + membership.role === 'OWNER' && + memberships.filter((i) => i.role === 'OWNER').length === 1 + ) + throw new BadRequestException(CANNOT_DELETE_SOLE_OWNER); + } +} diff --git a/src/modules/multi-factor-authentication/multi-factor-authentication.controller.ts b/src/modules/multi-factor-authentication/multi-factor-authentication.controller.ts new file mode 100644 index 000000000..3d5c20431 --- /dev/null +++ b/src/modules/multi-factor-authentication/multi-factor-authentication.controller.ts @@ -0,0 +1,91 @@ +import { + BadRequestException, + Body, + Controller, + Delete, + Param, + ParseIntPipe, + Post, +} from '@nestjs/common'; +import { users } from '@prisma/client'; +import { MFA_PHONE_OR_TOKEN_REQUIRED } from '../../errors/errors.constants'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { Scopes } from '../auth/scope.decorator'; +import { + EnableSmsMfaDto, + EnableTotpMfaDto, +} from './multi-factor-authentication.dto'; +import { MultiFactorAuthenticationService } from './multi-factor-authentication.service'; + +@Controller('users/:userId/multi-factor-authentication') +export class MultiFactorAuthenticationController { + constructor( + private multiFactorAuthenticationService: MultiFactorAuthenticationService, + ) {} + + @Post('regenerate') + @Scopes('user-{userId}:write-mfa-regenerate') + async regenerateBackupCodes( + @Param('userId', ParseIntPipe) userId: number, + ): Promise { + return this.multiFactorAuthenticationService.regenerateBackupCodes(userId); + } + + @Delete() + @Scopes('user-{userId}:delete-mfa-*') + async disable2FA( + @Param('userId', ParseIntPipe) userId: number, + ): Promise> { + return this.multiFactorAuthenticationService.disableMfa(userId); + } + + @Post('totp') + @Scopes('user-{userId}:write-mfa-totp') + async enableTotp( + @Param('userId', ParseIntPipe) userId: number, + @Body() body: EnableTotpMfaDto, + ): Promise { + if (body.token) + return this.multiFactorAuthenticationService.enableMfa( + 'TOTP', + userId, + body.token, + ); + return this.multiFactorAuthenticationService.requestTotpMfa(userId); + } + + @Post('sms') + @Scopes('user-{userId}:write-mfa-sms') + async enableSms( + @Param('userId', ParseIntPipe) userId: number, + @Body() body: EnableSmsMfaDto, + ): Promise { + if (body.token) + return this.multiFactorAuthenticationService.enableMfa( + 'SMS', + userId, + body.token, + ); + if (body.phone) + return this.multiFactorAuthenticationService.requestSmsMfa( + userId, + body.phone, + ); + throw new BadRequestException(MFA_PHONE_OR_TOKEN_REQUIRED); + } + + @Post('email') + @Scopes('user-{userId}:write-mfa-email') + async enableEmail( + @Param('userId', ParseIntPipe) userId: number, + @Body() body: EnableTotpMfaDto, + ): Promise { + if (body.token) + return this.multiFactorAuthenticationService.enableMfa( + 'EMAIL', + userId, + body.token, + ); + return this.multiFactorAuthenticationService.requestEmailMfa(userId); + } +} diff --git a/src/modules/multi-factor-authentication/multi-factor-authentication.dto.ts b/src/modules/multi-factor-authentication/multi-factor-authentication.dto.ts new file mode 100644 index 000000000..c956bfb08 --- /dev/null +++ b/src/modules/multi-factor-authentication/multi-factor-authentication.dto.ts @@ -0,0 +1,17 @@ +import { IsOptional, IsPhoneNumber, IsString } from 'class-validator'; + +export class EnableTotpMfaDto { + @IsString() + @IsOptional() + token?: string; +} + +export class EnableSmsMfaDto { + @IsString() + @IsOptional() + token?: string; + + @IsPhoneNumber('ZZ') + @IsOptional() + phone?: string; +} diff --git a/src/modules/multi-factor-authentication/multi-factor-authentication.module.ts b/src/modules/multi-factor-authentication/multi-factor-authentication.module.ts new file mode 100644 index 000000000..a43befc52 --- /dev/null +++ b/src/modules/multi-factor-authentication/multi-factor-authentication.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { AuthModule } from '../auth/auth.module'; +import { EmailModule } from '../email/email.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { TwilioModule } from '../twilio/twilio.module'; +import { MultiFactorAuthenticationController } from './multi-factor-authentication.controller'; +import { MultiFactorAuthenticationService } from './multi-factor-authentication.service'; + +@Module({ + imports: [ + PrismaModule, + AuthModule, + TwilioModule, + EmailModule, + ConfigModule, + TokensModule, + ], + controllers: [MultiFactorAuthenticationController], + providers: [MultiFactorAuthenticationService], +}) +export class MultiFactorAuthenticationModule {} diff --git a/src/modules/multi-factor-authentication/multi-factor-authentication.service.ts b/src/modules/multi-factor-authentication/multi-factor-authentication.service.ts new file mode 100644 index 000000000..2a8ade233 --- /dev/null +++ b/src/modules/multi-factor-authentication/multi-factor-authentication.service.ts @@ -0,0 +1,135 @@ +import { + BadRequestException, + ConflictException, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { MfaMethod, users } from '@prisma/client'; +import { hash } from 'bcrypt'; +import { + MFA_ENABLED_CONFLICT, + MFA_NOT_ENABLED, + NO_EMAILS, + USER_NOT_FOUND, +} from 'src/errors/errors.constants'; +import { AuthService } from '../auth/auth.service'; +import { EmailService } from '../email/email.service'; +import { Expose } from '../prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; +import { TokensService } from '../tokens/tokens.service'; +import { TwilioService } from '../twilio/twilio.service'; + +@Injectable() +export class MultiFactorAuthenticationService { + constructor( + private prisma: PrismaService, + private auth: AuthService, + private configService: ConfigService, + private twilioService: TwilioService, + private emailService: EmailService, + private tokensService: TokensService, + ) {} + + async requestTotpMfa(userId: number): Promise { + const enabled = await this.prisma.users.findOne({ + where: { id: userId }, + select: { twoFactorMethod: true }, + }); + if (!enabled) throw new NotFoundException(USER_NOT_FOUND); + if (enabled.twoFactorMethod !== 'NONE') + throw new ConflictException(MFA_ENABLED_CONFLICT); + return this.auth.getTotpQrCode(userId); + } + + async requestSmsMfa(userId: number, phone: string): Promise { + const enabled = await this.prisma.users.findOne({ + where: { id: userId }, + select: { twoFactorMethod: true }, + }); + if (!enabled) throw new NotFoundException(USER_NOT_FOUND); + if (enabled.twoFactorMethod !== 'NONE') + throw new ConflictException(MFA_ENABLED_CONFLICT); + const secret = this.tokensService.generateUuid(); + await this.prisma.users.update({ + where: { id: userId }, + data: { twoFactorSecret: secret, twoFactorPhone: phone }, + }); + return this.twilioService.send({ + to: phone, + body: `${this.auth.getOneTimePassword(secret)} is your ${ + this.configService.get('sms.smsServiceName') ?? '' + } verification code.`, + }); + } + + async requestEmailMfa(userId: number): Promise { + const user = await this.prisma.users.findOne({ + where: { id: userId }, + select: { + twoFactorMethod: true, + prefersEmail: true, + name: true, + id: true, + }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + if (user.twoFactorMethod !== 'NONE') + throw new ConflictException(MFA_ENABLED_CONFLICT); + const secret = this.tokensService.generateUuid(); + await this.prisma.users.update({ + where: { id: userId }, + data: { twoFactorSecret: secret }, + }); + if (!user.prefersEmail) throw new BadRequestException(NO_EMAILS); + return this.emailService.send({ + to: `"${user.name}" <${user.prefersEmail.emailSafe}>`, + template: 'auth/enable-email-mfa', + data: { + name: user.name, + code: this.auth.getOneTimePassword(secret), + }, + }); + } + + async enableMfa( + method: MfaMethod, + userId: number, + token: string, + ): Promise { + await this.auth.enableMfaMethod(method, userId, token); + return this.regenerateBackupCodes(userId); + } + + async disableMfa(userId: number): Promise> { + const enabled = await this.prisma.users.findOne({ + where: { id: userId }, + select: { twoFactorMethod: true }, + }); + if (!enabled) throw new NotFoundException(USER_NOT_FOUND); + if (enabled.twoFactorMethod === 'NONE') + throw new BadRequestException(MFA_NOT_ENABLED); + const user = await this.prisma.users.update({ + where: { id: userId }, + data: { twoFactorMethod: 'NONE', twoFactorSecret: null }, + }); + return this.prisma.expose(user); + } + + async regenerateBackupCodes(id: number) { + await this.prisma.backupCodes.deleteMany({ where: { user: { id } } }); + const codes: string[] = []; + for await (const _ of [...Array(10)]) { + const unsafeCode = this.tokensService.generateUuid(); + codes.push(unsafeCode); + const code = await hash( + unsafeCode, + this.configService.get('security.saltRounds') ?? 10, + ); + await this.prisma.backupCodes.create({ + data: { user: { connect: { id } }, code }, + }); + } + return codes; + } +} diff --git a/src/modules/prisma/prisma.interface.ts b/src/modules/prisma/prisma.interface.ts new file mode 100644 index 000000000..309e2f4aa --- /dev/null +++ b/src/modules/prisma/prisma.interface.ts @@ -0,0 +1,7 @@ +export type Expose = Omit< + Omit< + Omit, 'twoFactorSecret'>, 'token'>, + 'emailSafe' + >, + 'subnet' +>; diff --git a/src/modules/prisma/prisma.module.ts b/src/modules/prisma/prisma.module.ts new file mode 100644 index 000000000..ec0ce3291 --- /dev/null +++ b/src/modules/prisma/prisma.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { PrismaService } from './prisma.service'; + +@Module({ + providers: [PrismaService], + exports: [PrismaService], +}) +export class PrismaModule {} diff --git a/src/modules/prisma/prisma.service.ts b/src/modules/prisma/prisma.service.ts new file mode 100644 index 000000000..cf322acf6 --- /dev/null +++ b/src/modules/prisma/prisma.service.ts @@ -0,0 +1,33 @@ +import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; +import { + approvedSubnets, + emails, + PrismaClient, + sessions, + users, +} from '@prisma/client'; +import { Expose } from './prisma.interface'; + +@Injectable() +export class PrismaService + extends PrismaClient + implements OnModuleInit, OnModuleDestroy { + async onModuleInit() { + await this.$connect(); + } + + async onModuleDestroy() { + await this.$disconnect(); + } + + /** Delete sensitive keys from an object */ + expose(item: T): Expose { + if (!item) return {} as T; + delete ((item as any) as Partial).password; + delete ((item as any) as Partial).twoFactorSecret; + delete ((item as any) as Partial).token; + delete ((item as any) as Partial).emailSafe; + delete ((item as any) as Partial).subnet; + return item; + } +} diff --git a/src/modules/pwned/pwned.module.ts b/src/modules/pwned/pwned.module.ts new file mode 100644 index 000000000..25aca6ff4 --- /dev/null +++ b/src/modules/pwned/pwned.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { PwnedService } from './pwned.service'; + +@Module({ + providers: [PwnedService], + exports: [PwnedService], +}) +export class PwnedModule {} diff --git a/src/modules/pwned/pwned.service.ts b/src/modules/pwned/pwned.service.ts new file mode 100644 index 000000000..e5871006e --- /dev/null +++ b/src/modules/pwned/pwned.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { pwnedPassword } from 'hibp'; + +@Injectable() +export class PwnedService { + async isPasswordSafe(password: string): Promise { + try { + const numberOfPwned = await this.unsafeCheckPwnedPassword(password); + return !numberOfPwned; + } catch (error) { + return true; + } + } + + private async unsafeCheckPwnedPassword(password: string): Promise { + return pwnedPassword(password); + } +} diff --git a/src/modules/sessions/sessions.controller.ts b/src/modules/sessions/sessions.controller.ts new file mode 100644 index 000000000..528d071b3 --- /dev/null +++ b/src/modules/sessions/sessions.controller.ts @@ -0,0 +1,58 @@ +import { + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Query, +} from '@nestjs/common'; +import { sessions } from '@prisma/client'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { SessionsService } from './sessions.service'; + +@Controller('users/:userId/sessions') +export class SessionController { + constructor(private sessionsService: SessionsService) {} + + @Get() + @Scopes('user-{userId}:read-session-*') + async getAll( + @Param('userId', ParseIntPipe) userId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.sessionsService.getSessions(userId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get(':id') + @Scopes('user-{userId}:read-session-{id}') + async get( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.sessionsService.getSession(userId, Number(id)); + } + + @Delete(':id') + @Scopes('user-{userId}:delete-session-{id}') + async remove( + @Param('userId', ParseIntPipe) userId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.sessionsService.deleteSession(userId, Number(id)); + } +} diff --git a/src/modules/sessions/sessions.module.ts b/src/modules/sessions/sessions.module.ts new file mode 100644 index 000000000..fab207f92 --- /dev/null +++ b/src/modules/sessions/sessions.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from '../prisma/prisma.module'; +import { SessionController } from './sessions.controller'; +import { SessionsService } from './sessions.service'; + +@Module({ + imports: [PrismaModule], + controllers: [SessionController], + providers: [SessionsService], +}) +export class SessionsModule {} diff --git a/src/modules/sessions/sessions.service.ts b/src/modules/sessions/sessions.service.ts new file mode 100644 index 000000000..079600f4d --- /dev/null +++ b/src/modules/sessions/sessions.service.ts @@ -0,0 +1,66 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { + sessions, + sessionsOrderByInput, + sessionsWhereInput, + sessionsWhereUniqueInput, +} from '@prisma/client'; +import { + SESSION_NOT_FOUND, + UNAUTHORIZED_RESOURCE, +} from 'src/errors/errors.constants'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class SessionsService { + constructor(private prisma: PrismaService) {} + async getSessions( + userId: number, + params: { + skip?: number; + take?: number; + cursor?: sessionsWhereUniqueInput; + where?: sessionsWhereInput; + orderBy?: sessionsOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const sessions = await this.prisma.sessions.findMany({ + skip, + take, + cursor, + where: { ...where, user: { id: userId } }, + orderBy, + }); + return sessions.map((user) => this.prisma.expose(user)); + } + + async getSession(userId: number, id: number): Promise> { + const session = await this.prisma.sessions.findOne({ + where: { id }, + }); + if (!session) throw new NotFoundException(SESSION_NOT_FOUND); + if (session.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + if (!session) throw new NotFoundException(SESSION_NOT_FOUND); + return this.prisma.expose(session); + } + + async deleteSession(userId: number, id: number): Promise> { + const testSession = await this.prisma.sessions.findOne({ + where: { id }, + }); + if (!testSession) throw new NotFoundException(SESSION_NOT_FOUND); + if (testSession.userId !== userId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const session = await this.prisma.sessions.delete({ + where: { id }, + }); + return this.prisma.expose(session); + } +} diff --git a/src/modules/stripe/stripe-billing.controller.ts b/src/modules/stripe/stripe-billing.controller.ts new file mode 100644 index 000000000..7299a04f5 --- /dev/null +++ b/src/modules/stripe/stripe-billing.controller.ts @@ -0,0 +1,72 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Put, +} from '@nestjs/common'; +import Stripe from 'stripe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { + CreateBillingDto, + ReplaceBillingDto, + UpdateBillingDto, +} from './stripe.dto'; +import { StripeService } from './stripe.service'; + +@Controller('groups/:groupId/billing') +export class StripeBillingController { + constructor(private stripeService: StripeService) {} + + @Post() + @AuditLog('create-billing') + @Scopes('group-{groupId}:write-billing') + async createBillingAccount( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: CreateBillingDto, + ): Promise { + return this.stripeService.createCustomer(groupId, data); + } + + @Get() + @Scopes('group-{groupId}:read-billing') + async getBillingAccount( + @Param('groupId', ParseIntPipe) groupId: number, + ): Promise { + return this.stripeService.getCustomer(groupId); + } + + @Patch() + @AuditLog('update-billing') + @Scopes('group-{groupId}:write-billing') + async updateBillingAccount( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: UpdateBillingDto, + ): Promise { + return this.stripeService.updateCustomer(groupId, data); + } + + @Put() + @AuditLog('update-billing') + @Scopes('group-{groupId}:write-billing') + async replaceBillingAccount( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: ReplaceBillingDto, + ): Promise { + return this.stripeService.updateCustomer(groupId, data); + } + + @Delete() + @AuditLog('delete-billing') + @Scopes('group-{groupId}:delete-billing') + async deleteBillingAccount( + @Param('groupId', ParseIntPipe) groupId: number, + ): Promise { + return this.stripeService.deleteCustomer(groupId); + } +} diff --git a/src/modules/stripe/stripe-invoices.controller.ts b/src/modules/stripe/stripe-invoices.controller.ts new file mode 100644 index 000000000..cd83fb277 --- /dev/null +++ b/src/modules/stripe/stripe-invoices.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, ParseIntPipe, Query } from '@nestjs/common'; +import Stripe from 'stripe'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { StripeService } from './stripe.service'; + +@Controller('groups/:groupId/invoices') +export class StripeBillingController { + constructor(private stripeService: StripeService) {} + + @Get() + @Scopes('group-{groupId}:read-invoice-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: { id: string }, + ): Promise { + return this.stripeService.getInvoices(groupId, { take, cursor }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-invoice-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id') id: string, + ): Promise { + return this.stripeService.getInvoice(groupId, id); + } +} diff --git a/src/modules/stripe/stripe-sources.controller.ts b/src/modules/stripe/stripe-sources.controller.ts new file mode 100644 index 000000000..c083b3373 --- /dev/null +++ b/src/modules/stripe/stripe-sources.controller.ts @@ -0,0 +1,58 @@ +import { + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from '@nestjs/common'; +import Stripe from 'stripe'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { StripeService } from './stripe.service'; + +@Controller('groups/:groupId/sources') +export class StripeBillingController { + constructor(private stripeService: StripeService) {} + + @Post() + @AuditLog('write-source') + @Scopes('group-{groupId}:write-source-*') + async create( + @Param('groupId', ParseIntPipe) groupId: number, + ): Promise { + return this.stripeService.createSession(groupId, 'setup'); + } + + @Get() + @Scopes('group-{groupId}:read-source-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: { id: string }, + ): Promise { + return this.stripeService.getSources(groupId, { take, cursor }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-source-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id') id: string, + ): Promise { + return this.stripeService.getSource(groupId, id); + } + + @Delete(':id') + @AuditLog('delete-source') + @Scopes('group-{groupId}:delete-source-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id') id: string, + ): Promise { + return this.stripeService.deleteSource(groupId, id); + } +} diff --git a/src/modules/stripe/stripe-subscription.controller.ts b/src/modules/stripe/stripe-subscription.controller.ts new file mode 100644 index 000000000..7b4af3dbe --- /dev/null +++ b/src/modules/stripe/stripe-subscription.controller.ts @@ -0,0 +1,68 @@ +import { + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from '@nestjs/common'; +import Stripe from 'stripe'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { StripeService } from './stripe.service'; + +@Controller('groups/:groupId/subscriptions') +export class StripeBillingController { + constructor(private stripeService: StripeService) {} + + @Post(':plan') + @AuditLog('create-subscription') + @Scopes('group-{groupId}:write-subscription-*') + async create( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('plan') plan: string, + ): Promise { + return this.stripeService.createSession(groupId, 'subscription', plan); + } + + @Get() + @Scopes('group-{groupId}:read-subscription-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: { id: string }, + ): Promise { + return this.stripeService.getSubscriptions(groupId, { take, cursor }); + } + + @Get(':id') + @Scopes('group-{groupId}:read-subscription-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id') id: string, + ): Promise { + return this.stripeService.getSubscription(groupId, id); + } + + @Delete(':id') + @AuditLog('delete-subscription') + @Scopes('group-{groupId}:delete-subscription-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id') id: string, + ): Promise { + return this.stripeService.cancelSubscription(groupId, id); + } + + @Get('plans') + @Scopes('group-{groupId}:write-subscription-*') + async getPlans( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('product') product?: string, + ): Promise { + return this.stripeService.plans(groupId, product); + } +} diff --git a/src/modules/stripe/stripe-webhook.controller.ts b/src/modules/stripe/stripe-webhook.controller.ts new file mode 100644 index 000000000..8891f09ea --- /dev/null +++ b/src/modules/stripe/stripe-webhook.controller.ts @@ -0,0 +1,17 @@ +import { Body, Controller, Headers, Post } from '@nestjs/common'; +import { Public } from '../auth/public.decorator'; +import { StripeService } from './stripe.service'; + +@Controller('webhooks/stripe') +@Public() +export class StripeWebhookController { + constructor(private stripeService: StripeService) {} + + @Post() + async handleWebhook( + @Headers('stripe-signature') signature: string, + @Body() raw: Buffer, + ): Promise<{ received: true }> { + return this.stripeService.handleWebhook(signature, raw); + } +} diff --git a/src/modules/stripe/stripe.dto.ts b/src/modules/stripe/stripe.dto.ts new file mode 100644 index 000000000..c875d5874 --- /dev/null +++ b/src/modules/stripe/stripe.dto.ts @@ -0,0 +1,104 @@ +import { + IsEmail, + IsNotEmpty, + IsObject, + IsOptional, + IsString, + Length, + ValidateNested, +} from 'class-validator'; + +class Address { + @IsString() + @IsNotEmpty() + line1!: string; + + @IsString() + @IsOptional() + city?: string; + + @IsString() + @IsOptional() + @Length(2) + country?: string; + + @IsString() + @IsOptional() + line2?: string; + + @IsString() + @IsOptional() + postal_code?: string; + + @IsString() + @IsOptional() + state?: string; +} + +export class CreateBillingDto { + @IsEmail() + @IsNotEmpty() + email!: string; + + @IsString() + @IsNotEmpty() + name!: string; + + @IsString() + @IsOptional() + phone?: string; + + @IsString() + @IsOptional() + promotion_code?: string; + + @IsObject() + @ValidateNested() + @IsOptional() + address?: Address; +} + +export class UpdateBillingDto { + @IsString() + @IsOptional() + default_source?: string; + + @IsEmail() + @IsOptional() + email?: string; + + @IsString() + @IsOptional() + name?: string; + + @IsString() + @IsOptional() + phone?: string; + + @IsString() + @IsOptional() + promotion_code?: string; + + @IsObject() + @ValidateNested() + @IsOptional() + address?: Address; +} + +export class ReplaceBillingDto { + @IsEmail() + @IsNotEmpty() + email!: string; + + @IsString() + @IsNotEmpty() + name!: string; + + @IsString() + @IsNotEmpty() + phone!: string; + + @IsObject() + @ValidateNested() + address!: Address; +} diff --git a/src/modules/stripe/stripe.module.ts b/src/modules/stripe/stripe.module.ts new file mode 100644 index 000000000..300e81896 --- /dev/null +++ b/src/modules/stripe/stripe.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from '../prisma/prisma.module'; +import { StripeBillingController } from './stripe-billing.controller'; +import { StripeService } from './stripe.service'; + +@Module({ + imports: [ConfigModule, PrismaModule], + providers: [StripeService], + exports: [StripeService], + controllers: [StripeBillingController], +}) +export class StripeModule {} diff --git a/src/modules/stripe/stripe.service.ts b/src/modules/stripe/stripe.service.ts new file mode 100644 index 000000000..d7e3b17e7 --- /dev/null +++ b/src/modules/stripe/stripe.service.ts @@ -0,0 +1,254 @@ +import { + BadRequestException, + ConflictException, + Injectable, + Logger, + NotFoundException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + BILLING_ACCOUNT_CREATED_CONFLICT, + BILLING_NOT_FOUND, + CUSTOMER_NOT_FOUND, + GROUP_NOT_FOUND, + INVOICE_NOT_FOUND, + SOURCE_NOT_FOUND, + SUBSCRIPTION_NOT_FOUND, +} from 'src/errors/errors.constants'; +import Stripe from 'stripe'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class StripeService { + stripe: Stripe; + logger = new Logger(StripeService.name); + + constructor( + private configService: ConfigService, + private prisma: PrismaService, + ) { + const stripeApiKey = this.configService.get( + 'payments.stripeApiKey', + ); + this.stripe = new Stripe(stripeApiKey, { + apiVersion: '2020-08-27', + }); + } + + async createCustomer(groupId: number, data: Stripe.CustomerCreateParams) { + const group = await this.prisma.groups.findOne({ + where: { id: groupId }, + select: { attributes: true }, + }); + if (!group) throw new NotFoundException(GROUP_NOT_FOUND); + const attributes = group.attributes as { stripeCustomerId?: string }; + if (attributes?.stripeCustomerId) + throw new ConflictException(BILLING_ACCOUNT_CREATED_CONFLICT); + const result = await this.stripe.customers.create(data); + await this.prisma.groups.update({ + where: { id: groupId }, + data: { attributes: { stripeCustomerId: result.id } }, + }); + return result as Stripe.Response; + } + + async getCustomer(groupId: number) { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.customers.retrieve(stripeId); + if (result.deleted) throw new NotFoundException(CUSTOMER_NOT_FOUND); + return result as Stripe.Response; + } + + async updateCustomer(groupId: number, data: Stripe.CustomerUpdateParams) { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.customers.update(stripeId, data); + return result as Stripe.Response; + } + + async deleteCustomer(groupId: number): Promise { + const stripeId = await this.stripeId(groupId); + const result = (await this.stripe.customers.del( + stripeId, + )) as Stripe.DeletedCustomer; + await this.prisma.groups.update({ + where: { id: groupId }, + data: { attributes: { stripeCustomerId: null } }, + }); + return result; + } + + async getInvoices( + groupId: number, + params: { + take?: number; + cursor?: { id: string }; + }, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.invoices.list({ + customer: stripeId, + limit: params.take, + starting_after: params.cursor?.id, + }); + return this.list(result); + } + + async getInvoice( + groupId: number, + invoiceId: string, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.invoices.retrieve(invoiceId); + if (result.customer !== stripeId) + throw new NotFoundException(INVOICE_NOT_FOUND); + return result; + } + + async getSubscriptions( + groupId: number, + params: { + take?: number; + cursor?: { id: string }; + }, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.subscriptions.list({ + customer: stripeId, + limit: params.take, + starting_after: params.cursor?.id, + }); + return this.list(result); + } + + async getSubscription( + groupId: number, + subscriptionId: string, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.subscriptions.retrieve(subscriptionId); + if (result.customer !== stripeId) + throw new NotFoundException(SUBSCRIPTION_NOT_FOUND); + return result; + } + + async getSources( + groupId: number, + params: { + take?: number; + cursor?: { id: string }; + }, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.customers.listSources(stripeId, { + limit: params.take, + starting_after: params.cursor?.id, + }); + return this.list(result); + } + + async getSource(groupId: number, sourceId: string): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.sources.retrieve(sourceId); + if (result.customer !== stripeId) + throw new NotFoundException(SOURCE_NOT_FOUND); + return result; + } + + async deleteSource(groupId: number, sourceId: string): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.sources.retrieve(sourceId); + if (result.customer !== stripeId) + throw new NotFoundException(SOURCE_NOT_FOUND); + await this.stripe.customers.deleteSource(stripeId, sourceId); + } + + async createSession( + groupId: number, + mode: Stripe.Checkout.SessionCreateParams.Mode, + price?: string, + ): Promise { + const stripeId = await this.stripeId(groupId); + const data: Stripe.Checkout.SessionCreateParams = { + customer: stripeId, + mode, + payment_method_types: this.configService.get< + Array + >('payments.paymentMethodTypes') ?? ['card'], + success_url: `${this.configService.get( + 'frontendUrl', + )}/groups/${groupId}/subscription`, + cancel_url: `${this.configService.get( + 'frontendUrl', + )}/groups/${groupId}/subscription`, + }; + if (mode === 'subscription') data.line_items = [{ quantity: 1, price }]; + const result = await this.stripe.checkout.sessions.create(data); + return result; + } + + async cancelSubscription( + groupId: number, + subscriptionId: string, + ): Promise { + const stripeId = await this.stripeId(groupId); + const result = await this.stripe.subscriptions.retrieve(subscriptionId); + if (result.customer !== stripeId) + throw new NotFoundException(SUBSCRIPTION_NOT_FOUND); + return this.stripe.subscriptions.update(subscriptionId, { + cancel_at_period_end: true, + }); + } + + async plans(groupId: number, product?: string): Promise { + const stripeId = await this.stripeId(groupId); + const plans = await this.stripe.plans.list({ product }); + return plans.data.filter((plan) => { + let show = true; + ['special', 'internal'].forEach((word) => { + if (plan.nickname.toLowerCase().includes(word)) show = false; + }); + const tokens = plan.nickname + .toLowerCase() + .replace(/[^a-zA-Z0-9]/g, ' ') + .replace(/\s\s+/g, ' ') + .split(' '); + [stripeId, groupId.toString()].forEach((word) => { + if (tokens.includes(word)) show = true; + }); + return show; + }); + } + + async handleWebhook( + signature: string, + payload: Buffer, + ): Promise<{ received: true }> { + const event = this.stripe.webhooks.constructEvent( + payload, + signature, + this.configService.get('payments.stripeEndpointSecret') ?? '', + ); + switch (event.type) { + default: + this.logger.warn(`Unhandled event type ${event.type}`); + } + return { received: true }; + } + + private list(result: Stripe.Response>) { + return result.data; + } + + /** Get the Stripe customer ID from a group or throw an error */ + private async stripeId(groupId: number): Promise { + const group = await this.prisma.groups.findOne({ + where: { id: groupId }, + select: { attributes: true }, + }); + if (!group) throw new NotFoundException(GROUP_NOT_FOUND); + const attributes = group.attributes as { stripeCustomerId?: string }; + if (!attributes?.stripeCustomerId) + throw new BadRequestException(BILLING_NOT_FOUND); + return attributes.stripeCustomerId; + } +} diff --git a/src/modules/tasks/tasks.module.ts b/src/modules/tasks/tasks.module.ts new file mode 100644 index 000000000..f7f732e31 --- /dev/null +++ b/src/modules/tasks/tasks.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from '../prisma/prisma.module'; +import { TasksService } from './tasks.service'; + +@Module({ + imports: [ConfigModule, PrismaModule], + providers: [TasksService], + exports: [TasksService], +}) +export class TasksModule {} diff --git a/src/modules/tasks/tasks.service.ts b/src/modules/tasks/tasks.service.ts new file mode 100644 index 000000000..0aaea04e2 --- /dev/null +++ b/src/modules/tasks/tasks.service.ts @@ -0,0 +1,27 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class TasksService { + constructor( + private prisma: PrismaService, + private configService: ConfigService, + ) {} + private readonly logger = new Logger(TasksService.name); + + @Cron(CronExpression.EVERY_DAY_AT_1PM) + async deleteOldSessions() { + const now = new Date(); + const unusedRefreshTokenExpiryDays = + this.configService.get('security.unusedRefreshTokenExpiryDays') ?? + 30; + now.setDate(now.getDate() - unusedRefreshTokenExpiryDays); + const deleted = await this.prisma.sessions.deleteMany({ + where: { updatedAt: { lte: now } }, + }); + if (deleted.count) + this.logger.debug(`Deleted ${deleted.count} expired sessions`); + } +} diff --git a/src/modules/tokens/tokens.constants.ts b/src/modules/tokens/tokens.constants.ts new file mode 100644 index 000000000..886a0b224 --- /dev/null +++ b/src/modules/tokens/tokens.constants.ts @@ -0,0 +1,7 @@ +export const MULTI_FACTOR_TOKEN = 'MULTI_FACTOR_TOKEN'; +export const PASSWORD_RESET_TOKEN = 'PASSWORD_RESET_TOKEN'; +export const EMAIL_VERIFY_TOKEN = 'EMAIL_VERIFY_TOKEN'; +export const APPROVE_SUBNET_TOKEN = 'APPROVE_SUBNET_TOKEN'; +export const EMAIL_MFA_TOKEN = 'EMAIL_MFA_TOKEN'; +export const LOGIN_ACCESS_TOKEN = 'LOGIN_ACCESS_TOKEN'; +export const MERGE_ACCOUNTS_TOKEN = 'MERGE_ACCOUNTS_TOKEN'; diff --git a/src/modules/tokens/tokens.module.ts b/src/modules/tokens/tokens.module.ts new file mode 100644 index 000000000..cf0e29f9d --- /dev/null +++ b/src/modules/tokens/tokens.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TokensService } from './tokens.service'; + +@Module({ + imports: [ConfigModule], + providers: [TokensService], + exports: [TokensService], +}) +export class TokensModule {} diff --git a/src/modules/tokens/tokens.service.ts b/src/modules/tokens/tokens.service.ts new file mode 100644 index 000000000..6a0842392 --- /dev/null +++ b/src/modules/tokens/tokens.service.ts @@ -0,0 +1,55 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + decode, + DecodeOptions, + sign, + SignOptions, + verify, + VerifyOptions, +} from 'jsonwebtoken'; +import { v4 } from 'uuid'; +import { INVALID_TOKEN } from '../../errors/errors.constants'; + +@Injectable() +export class TokensService { + constructor(private configService: ConfigService) {} + + signJwt( + subject: string, + payload: number | string | object | Buffer, + expiresIn?: string, + options?: SignOptions, + ) { + if (typeof payload === 'number') payload = payload.toString(); + return sign( + payload, + this.configService.get('security.jwtSecret') ?? '', + { + ...options, + subject, + expiresIn, + }, + ); + } + + verify(subject: string, token: string, options?: VerifyOptions) { + try { + return (verify( + token, + this.configService.get('security.jwtSecret') ?? '', + { ...options, subject }, + ) as any) as T; + } catch (error) { + throw new UnauthorizedException(INVALID_TOKEN); + } + } + + decode(token: string, options?: DecodeOptions) { + return decode(token, options) as T; + } + + generateUuid() { + return v4(); + } +} diff --git a/src/modules/twilio/twilio.module.ts b/src/modules/twilio/twilio.module.ts new file mode 100644 index 000000000..5adc195f6 --- /dev/null +++ b/src/modules/twilio/twilio.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TwilioService } from './twilio.service'; + +@Module({ + imports: [ConfigModule], + providers: [TwilioService], + exports: [TwilioService], +}) +export class TwilioModule {} diff --git a/src/modules/twilio/twilio.service.ts b/src/modules/twilio/twilio.service.ts new file mode 100644 index 000000000..d92b89c2f --- /dev/null +++ b/src/modules/twilio/twilio.service.ts @@ -0,0 +1,47 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import PQueue from 'p-queue'; +import pRetry from 'p-retry'; +import twilio from 'twilio'; +import { MessageListInstanceCreateOptions } from 'twilio/lib/rest/api/v2010/account/message'; +import TwilioClient from 'twilio/lib/rest/Twilio'; + +@Injectable() +export class TwilioService { + twilio: TwilioClient; + logger = new Logger(TwilioService.name); + private queue = new PQueue({ concurrency: 1 }); + + constructor(private configService: ConfigService) { + const twilioAccountSid = this.configService.get( + 'sms.twilioAccountSid', + ); + const twilioAuthToken = this.configService.get( + 'sms.twilioAuthToken', + ); + if (!twilioAccountSid || !twilioAuthToken) + this.logger.warn('Twilio account SID/auth token not found'); + this.twilio = twilio(twilioAccountSid ?? '', twilioAuthToken ?? ''); + } + + send(options: MessageListInstanceCreateOptions) { + this.queue + .add(() => + pRetry(() => this.sendSms(options), { + retries: 3, + onFailedAttempt: (error) => { + this.logger.error( + `SMS to ${options.to} failed, retrying (${error.retriesLeft} attempts left)`, + error.name, + ); + }, + }), + ) + .then(() => {}) + .catch(() => {}); + } + + private async sendSms(options: MessageListInstanceCreateOptions) { + return this.twilio.messages.create(options); + } +} diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts new file mode 100644 index 000000000..ef06f8b83 --- /dev/null +++ b/src/modules/users/users.controller.ts @@ -0,0 +1,84 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Query, +} from '@nestjs/common'; +import { users } from '@prisma/client'; +import { RateLimit } from 'nestjs-rate-limiter'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { Scopes } from '../auth/scope.decorator'; +import { UpdateUserDto } from './users.dto'; +import { UsersService } from './users.service'; + +@Controller('users') +export class UserController { + constructor(private usersService: UsersService) {} + + @Get() + @Scopes('user-*:read-info') + async getAll( + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.usersService.getUsers({ skip, take, orderBy, cursor, where }); + } + + @Get(':id') + @Scopes('user-{id}:read-info') + async get(@Param('id', ParseIntPipe) id: number): Promise> { + return this.usersService.getUser(Number(id)); + } + + @Patch(':id') + @Scopes('user-{id}:write-info') + async update( + @Param('id', ParseIntPipe) id: number, + @Body() data: UpdateUserDto, + ): Promise> { + return this.usersService.updateUser(Number(id), data); + } + + @Delete(':id') + @Scopes('user-{id}:delete') + async remove(@Param('id', ParseIntPipe) id: number): Promise> { + return this.usersService.deleteUser(Number(id)); + } + + @Post(':id/merge-request') + @Scopes('user-{id}:merge') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to merge again', + }) + async mergeRequest( + @Param('id', ParseIntPipe) id: number, + @Body('email') email: string, + ): Promise { + return this.usersService.requestMerge(Number(id), email); + } + + @Post('merge') + @Scopes('user-{id}:merge') + @RateLimit({ + points: 10, + duration: 60, + errorMessage: 'Wait for 60 seconds before trying to merge again', + }) + async merge(@Body('token') token: string): Promise { + return this.usersService.mergeUsers(token); + } +} diff --git a/src/modules/users/users.dto.ts b/src/modules/users/users.dto.ts new file mode 100644 index 000000000..d9bbcd37b --- /dev/null +++ b/src/modules/users/users.dto.ts @@ -0,0 +1,80 @@ +import { MfaMethod } from '@prisma/client'; +import { + IsBoolean, + IsEnum, + IsIn, + IsLocale, + IsObject, + IsOptional, + IsString, + IsUrl, + Length, + MinLength, +} from 'class-validator'; + +export class UpdateUserDto { + @IsBoolean() + @IsOptional() + checkLocationOnLogin?: boolean; + + @IsString() + @Length(2, 2) + @IsOptional() + countryCode?: string; + + @IsString() + @IsIn(['MALE', 'FEMALE', 'NONBINARY', 'UNKNOWN']) + @IsOptional() + gender?: 'MALE' | 'FEMALE' | 'NONBINARY' | 'UNKNOWN'; + + @IsString() + @MinLength(3) + @IsOptional() + name?: string; + + @IsIn(['ACCOUNT', 'UPDATES', 'PROMOTIONS']) + @IsOptional() + notificationEmails?: 'ACCOUNT' | 'UPDATES' | 'PROMOTIONS'; + + @IsString() + @IsOptional() + newPassword?: string; + + @IsString() + @IsOptional() + currentPassword?: string; + + @IsBoolean() + @IsOptional() + ignorePwnedPassword?: boolean; + + @IsLocale() + @IsOptional() + prefersLanguage?: string; + + @IsString() + @IsIn(['NO_PREFERENCE', 'LIGHT', 'DARK']) + @IsOptional() + prefersColorScheme?: 'NO_PREFERENCE' | 'LIGHT' | 'DARK'; + + @IsString() + @IsIn(['NO_PREFERENCE', 'REDUCE']) + @IsOptional() + prefersReducedMotion?: 'NO_PREFERENCE' | 'REDUCE'; + + @IsUrl() + @IsOptional() + profilePictureUrl?: string; + + @IsString() + @IsOptional() + timezone?: string; + + @IsEnum(['NONE', 'TOTP', 'EMAIL']) + @IsOptional() + twoFactorMethod?: MfaMethod; + + @IsObject() + @IsOptional() + attributes?: Record; +} diff --git a/src/modules/users/users.interface.ts b/src/modules/users/users.interface.ts new file mode 100644 index 000000000..58d45af48 --- /dev/null +++ b/src/modules/users/users.interface.ts @@ -0,0 +1,5 @@ +export interface PasswordUpdateInput { + currentPassword?: string; + newPassword?: string; + ignorePwnedPassword?: boolean; +} diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts new file mode 100644 index 000000000..8c396cedc --- /dev/null +++ b/src/modules/users/users.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { AuthModule } from '../auth/auth.module'; +import { EmailModule } from '../email/email.module'; +import { PrismaModule } from '../prisma/prisma.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { UserController } from './users.controller'; +import { UsersService } from './users.service'; + +@Module({ + imports: [PrismaModule, AuthModule, EmailModule, ConfigModule, TokensModule], + controllers: [UserController], + providers: [UsersService], + exports: [UsersService], +}) +export class UsersModule {} diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts new file mode 100644 index 000000000..ee997eb4b --- /dev/null +++ b/src/modules/users/users.service.ts @@ -0,0 +1,193 @@ +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { + emailsDelegate, + users, + usersCreateInput, + usersOrderByInput, + usersUpdateInput, + usersWhereInput, + usersWhereUniqueInput, +} from '@prisma/client'; +import { compare } from 'bcrypt'; +import { + CURRENT_PASSWORD_REQUIRED, + INVALID_CREDENTIALS, + USER_NOT_FOUND, +} from '../../errors/errors.constants'; +import { safeEmail } from '../../helpers/safe-email'; +import { Expose } from '../../modules/prisma/prisma.interface'; +import { AuthService } from '../auth/auth.service'; +import { EmailService } from '../email/email.service'; +import { PrismaService } from '../prisma/prisma.service'; +import { MERGE_ACCOUNTS_TOKEN } from '../tokens/tokens.constants'; +import { TokensService } from '../tokens/tokens.service'; +import { PasswordUpdateInput } from './users.interface'; + +@Injectable() +export class UsersService { + constructor( + private prisma: PrismaService, + private auth: AuthService, + private email: EmailService, + private configService: ConfigService, + private tokensService: TokensService, + ) {} + + async getUser(id: number): Promise> { + const user = await this.prisma.users.findOne({ + where: { id }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + return this.prisma.expose(user); + } + + async getUsers(params: { + skip?: number; + take?: number; + cursor?: usersWhereUniqueInput; + where?: usersWhereInput; + orderBy?: usersOrderByInput; + }): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const users = await this.prisma.users.findMany({ + skip, + take, + cursor, + where, + orderBy, + }); + return users.map((user) => this.prisma.expose(user)); + } + + async createUser(data: usersCreateInput): Promise { + return this.prisma.users.create({ + data, + }); + } + + async updateUser( + id: number, + data: Omit & PasswordUpdateInput, + ): Promise> { + const transformed: usersUpdateInput & PasswordUpdateInput = data; + if (data.newPassword) { + if (!data.currentPassword) + throw new BadRequestException(CURRENT_PASSWORD_REQUIRED); + const previousPassword = ( + await this.prisma.users.findOne({ + where: { id }, + select: { password: true }, + }) + )?.password; + if (previousPassword) + if (!(await compare(data.currentPassword, previousPassword))) + throw new BadRequestException(INVALID_CREDENTIALS); + transformed.password = await this.auth.hashAndValidatePassword( + data.newPassword, + !!data.ignorePwnedPassword, + ); + } + delete transformed.currentPassword; + delete transformed.newPassword; + delete transformed.ignorePwnedPassword; + const updateData: usersUpdateInput = transformed; + const user = await this.prisma.users.update({ + data: updateData, + where: { id }, + }); + return this.prisma.expose(user); + } + + async deleteUser(id: number): Promise> { + const user = await this.prisma.users.delete({ + where: { id }, + }); + return this.prisma.expose(user); + } + + async requestMerge(userId: number, email: string): Promise { + const emailSafe = safeEmail(email); + const user = await this.prisma.users.findFirst({ + where: { emails: { some: { emailSafe } } }, + include: { prefersEmail: true }, + }); + if (!user) throw new NotFoundException(USER_NOT_FOUND); + const minutes = parseInt( + this.configService.get('security.mergeUsersTokenExpiry') ?? '', + ); + return this.email.send({ + to: `"${user.name}" <${user.prefersEmail.email}>`, + template: 'auth/mfa-code', + data: { + name: user.name, + minutes, + link: `${this.configService.get( + 'frontendUrl', + )}/auth/merge-accounts?token=${this.tokensService.signJwt( + MERGE_ACCOUNTS_TOKEN, + { baseUserId: userId, mergeUserId: user.id }, + `${minutes}m`, + )}`, + }, + }); + } + + async mergeUsers(token: string): Promise { + let baseUserId: number | undefined = undefined; + let mergeUserId: number | undefined = undefined; + try { + const result = this.tokensService.verify<{ + baseUserId: number; + mergeUserId: number; + }>(MERGE_ACCOUNTS_TOKEN, token); + baseUserId = result.baseUserId; + mergeUserId = result.mergeUserId; + } catch (error) {} + if (!baseUserId || !mergeUserId) + throw new BadRequestException(USER_NOT_FOUND); + return this.merge(baseUserId, mergeUserId); + } + + private async merge(baseUserId: number, mergeUserId: number): Promise { + const baseUser = await this.prisma.users.findOne({ + where: { id: baseUserId }, + }); + const mergeUser = await this.prisma.users.findOne({ + where: { id: mergeUserId }, + }); + if (!baseUser || !mergeUser) throw new NotFoundException(USER_NOT_FOUND); + + const combinedUser = { ...baseUser }; + Object.keys(mergeUser).forEach((key) => { + if (mergeUser[key]) combinedUser[key] = mergeUser[key]; + }); + await this.prisma.users.update({ + where: { id: baseUserId }, + data: combinedUser, + }); + + for await (const dataType of [ + this.prisma.memberships, + this.prisma.emails, + this.prisma.sessions, + this.prisma.approvedSubnets, + this.prisma.backupCodes, + this.prisma.identities, + this.prisma.auditLogs, + ]) { + for await (const item of await (dataType as emailsDelegate).findMany({ + where: { user: { id: mergeUserId } }, + select: { id: true }, + })) + await (dataType as emailsDelegate).update({ + where: { id: item.id }, + data: { user: { connect: { id: baseUserId } } }, + }); + } + } +} diff --git a/src/modules/webhooks/webhooks.controller.ts b/src/modules/webhooks/webhooks.controller.ts new file mode 100644 index 000000000..ac82be87c --- /dev/null +++ b/src/modules/webhooks/webhooks.controller.ts @@ -0,0 +1,107 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Put, + Query, +} from '@nestjs/common'; +import { webhooks } from '@prisma/client'; +import { CursorPipe } from '../../pipes/cursor.pipe'; +import { OptionalIntPipe } from '../../pipes/optional-int.pipe'; +import { OrderByPipe } from '../../pipes/order-by.pipe'; +import { WherePipe } from '../../pipes/where.pipe'; +import { AuditLog } from '../audit-logs/audit-log.decorator'; +import { Scopes } from '../auth/scope.decorator'; +import { Expose } from '../prisma/prisma.interface'; +import { + CreateWebhookDto, + ReplaceWebhookDto, + UpdateWebhookDto, +} from './webhooks.dto'; +import { WebhooksService } from './webhooks.service'; + +@Controller('groups/:groupId/webhooks') +export class WebhookController { + constructor(private webhooksService: WebhooksService) {} + + @Post() + @AuditLog('create-webhook') + @Scopes('group-{groupId}:write-webhook-*') + async create( + @Param('groupId', ParseIntPipe) groupId: number, + @Body() data: CreateWebhookDto, + ): Promise> { + return this.webhooksService.createWebhook(groupId, data); + } + + @Get() + @Scopes('group-{groupId}:read-webhook-*') + async getAll( + @Param('groupId', ParseIntPipe) groupId: number, + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('cursor', CursorPipe) cursor?: Record, + @Query('where', WherePipe) where?: Record, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.webhooksService.getWebhooks(groupId, { + skip, + take, + orderBy, + cursor, + where, + }); + } + + @Get('scopes') + @Scopes('group-{groupId}:write-webhook-*') + async scopes(): Promise> { + return this.webhooksService.getWebhookScopes(); + } + + @Get(':id') + @Scopes('group-{groupId}:read-webhook-{id}') + async get( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.webhooksService.getWebhook(groupId, Number(id)); + } + + @Patch(':id') + @AuditLog('update-webhook') + @Scopes('group-{groupId}:write-webhook-{id}') + async update( + @Body() data: UpdateWebhookDto, + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.webhooksService.updateWebhook(groupId, Number(id), data); + } + + @Put(':id') + @AuditLog('update-webhook') + @Scopes('group-{groupId}:write-webhook-{id}') + async replace( + @Body() data: ReplaceWebhookDto, + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.webhooksService.updateWebhook(groupId, Number(id), data); + } + + @Delete(':id') + @AuditLog('delete-webhook') + @Scopes('group-{groupId}:delete-webhook-{id}') + async remove( + @Param('groupId', ParseIntPipe) groupId: number, + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.webhooksService.deleteWebhook(groupId, Number(id)); + } +} diff --git a/src/modules/webhooks/webhooks.dto.ts b/src/modules/webhooks/webhooks.dto.ts new file mode 100644 index 000000000..65cb75614 --- /dev/null +++ b/src/modules/webhooks/webhooks.dto.ts @@ -0,0 +1,67 @@ +import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator'; + +export class CreateWebhookDto { + @IsString() + @IsNotEmpty() + url: string; + + @IsString() + @IsNotEmpty() + event: string; + + @IsString() + @IsOptional() + contentType?: string; + + @IsBoolean() + @IsOptional() + isActive?: boolean; + + @IsString() + @IsOptional() + secret?: string; +} + +export class UpdateWebhookDto { + @IsString() + @IsOptional() + url?: string; + + @IsString() + @IsOptional() + event?: string; + + @IsString() + @IsOptional() + contentType?: string; + + @IsBoolean() + @IsOptional() + isActive?: boolean; + + @IsString() + @IsOptional() + secret?: string; +} + +export class ReplaceWebhookDto { + @IsString() + @IsNotEmpty() + url!: string; + + @IsString() + @IsNotEmpty() + event!: string; + + @IsString() + @IsOptional() + contentType!: string; + + @IsBoolean() + @IsOptional() + isActive!: boolean; + + @IsString() + @IsOptional() + secret!: string; +} diff --git a/src/modules/webhooks/webhooks.module.ts b/src/modules/webhooks/webhooks.module.ts new file mode 100644 index 000000000..aeac570ee --- /dev/null +++ b/src/modules/webhooks/webhooks.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from '../prisma/prisma.module'; +import { StripeModule } from '../stripe/stripe.module'; +import { TokensModule } from '../tokens/tokens.module'; +import { WebhookController } from './webhooks.controller'; +import { WebhooksService } from './webhooks.service'; + +@Module({ + imports: [PrismaModule, TokensModule, StripeModule], + controllers: [WebhookController], + providers: [WebhooksService], + exports: [WebhooksService], +}) +export class WebhooksModule {} diff --git a/src/modules/webhooks/webhooks.service.ts b/src/modules/webhooks/webhooks.service.ts new file mode 100644 index 000000000..f753c99be --- /dev/null +++ b/src/modules/webhooks/webhooks.service.ts @@ -0,0 +1,192 @@ +import { + Injectable, + Logger, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { + webhooks, + webhooksCreateInput, + webhooksOrderByInput, + webhooksUpdateInput, + webhooksWhereInput, + webhooksWhereUniqueInput, +} from '@prisma/client'; +import got from 'got'; +import PQueue from 'p-queue'; +import pRetry from 'p-retry'; +import { + UNAUTHORIZED_RESOURCE, + WEBHOOK_NOT_FOUND, +} from 'src/errors/errors.constants'; +import { Expose } from '../prisma/prisma.interface'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class WebhooksService { + private readonly logger = new Logger(WebhooksService.name); + private queue = new PQueue({ concurrency: 1 }); + + constructor(private prisma: PrismaService) {} + + async createWebhook( + groupId: number, + data: Omit, 'group'>, + ): Promise { + return this.prisma.webhooks.create({ + data: { ...data, group: { connect: { id: groupId } } }, + }); + } + + async getWebhooks( + groupId: number, + params: { + skip?: number; + take?: number; + cursor?: webhooksWhereUniqueInput; + where?: webhooksWhereInput; + orderBy?: webhooksOrderByInput; + }, + ): Promise[]> { + const { skip, take, cursor, where, orderBy } = params; + const webhooks = await this.prisma.webhooks.findMany({ + skip, + take, + cursor, + where: { ...where, group: { id: groupId } }, + orderBy, + }); + return webhooks.map((group) => this.prisma.expose(group)); + } + + async getWebhook(groupId: number, id: number): Promise> { + const webhook = await this.prisma.webhooks.findOne({ + where: { id }, + }); + if (!webhook) throw new NotFoundException(WEBHOOK_NOT_FOUND); + if (webhook.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + return this.prisma.expose(webhook); + } + + async updateWebhook( + groupId: number, + id: number, + data: webhooksUpdateInput, + ): Promise> { + const testWebhook = await this.prisma.webhooks.findOne({ + where: { id }, + }); + if (!testWebhook) throw new NotFoundException(WEBHOOK_NOT_FOUND); + if (testWebhook.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const webhook = await this.prisma.webhooks.update({ + where: { id }, + data, + }); + return this.prisma.expose(webhook); + } + + async replaceWebhook( + groupId: number, + id: number, + data: webhooksCreateInput, + ): Promise> { + const testWebhook = await this.prisma.webhooks.findOne({ + where: { id }, + }); + if (!testWebhook) throw new NotFoundException(WEBHOOK_NOT_FOUND); + if (testWebhook.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const webhook = await this.prisma.webhooks.update({ + where: { id }, + data, + }); + return this.prisma.expose(webhook); + } + + async deleteWebhook(groupId: number, id: number): Promise> { + const testWebhook = await this.prisma.webhooks.findOne({ + where: { id }, + }); + if (!testWebhook) throw new NotFoundException(WEBHOOK_NOT_FOUND); + if (testWebhook.groupId !== groupId) + throw new UnauthorizedException(UNAUTHORIZED_RESOURCE); + const webhook = await this.prisma.webhooks.delete({ + where: { id }, + }); + return this.prisma.expose(webhook); + } + + async getWebhookScopes(): Promise> { + const scopes: Record = { + 'create-api-key': 'Create API key', + 'update-api-key': 'Update API key', + 'delete-api-key': 'Delete API key', + 'create-domain': 'Create domain', + 'delete-domain': 'Delete domain', + 'verify-domain-txt': 'Verify domain (TXT)', + 'verify-domain-html': 'Verify domain (HTML)', + 'update-info': 'Update info', + delete: 'Delete group', + 'add-membership': 'Add membership', + 'update-membership': 'Update membership', + 'delete-membership': 'Delete membership', + 'create-billing': 'Create billing', + 'update-billing': 'Update billing', + 'delete-billing': 'Delete billing', + 'write-source': 'Write source', + 'delete-source': 'Delete source', + 'create-subscription': 'Create subscription', + 'delete-subscription': 'Delete subscription', + 'create-webhook': 'Create webhook', + 'update-webhook': 'Update webhook', + 'delete-webhook': 'Delete webhook', + }; + return scopes; + } + + triggerWebhook(groupId: number, event: string) { + this.prisma.webhooks + .findMany({ + where: { group: { id: groupId }, isActive: true, event }, + }) + .then((webhooks) => { + webhooks.forEach((webhook) => + this.queue + .add(() => + pRetry(() => this.callWebhook(webhook, event), { + retries: 3, + onFailedAttempt: (error) => { + this.logger.error( + `Triggering webhoook failed, retrying (${error.retriesLeft} attempts left)`, + error.name, + ); + if (error.retriesLeft === 0) + this.prisma.webhooks + .update({ + where: { id: webhook.id }, + data: { isActive: false }, + }) + .then(() => {}) + .catch(() => {}); + }, + }), + ) + .then(() => {}) + .catch(() => {}), + ); + }) + .catch((error) => this.logger.error('Unable to get webhooks', error)); + } + + private async callWebhook(webhook: webhooks, event: string) { + if (webhook.contentType === 'application/json') + await got(webhook.url, { method: 'POST', json: { event } }); + else await got(webhook.url, { method: 'POST', body: event }); + await this.prisma.webhooks.update({ + where: { id: webhook.id }, + data: { lastFiredAt: new Date() }, + }); + } +} diff --git a/src/pipes/cursor.pipe.ts b/src/pipes/cursor.pipe.ts new file mode 100644 index 000000000..76e517339 --- /dev/null +++ b/src/pipes/cursor.pipe.ts @@ -0,0 +1,23 @@ +import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; +import { CURSOR_PIPE_FORMAT } from 'src/errors/errors.constants'; +import { parseObjectLiteral } from '../helpers/parse-object-literal'; + +/** Convert a string like "id: 12, b: 'Anand'" to { id: 12, name: "Anand" } */ +@Injectable() +export class CursorPipe implements PipeTransform { + transform(value: string): Record | undefined { + if (value == null) return undefined; + try { + const rules = parseObjectLiteral(value); + const items: Record = {}; + rules.forEach((rule) => { + const num = Number(rule[1]); + if (!isNaN(num)) items[rule[0]] = num; + else if (rule[1]) items[rule[0]] = rule[1]; + }); + return items; + } catch (_) { + throw new BadRequestException(CURSOR_PIPE_FORMAT); + } + } +} diff --git a/src/pipes/optional-int.pipe.ts b/src/pipes/optional-int.pipe.ts new file mode 100644 index 000000000..ef80411d6 --- /dev/null +++ b/src/pipes/optional-int.pipe.ts @@ -0,0 +1,21 @@ +import { + ArgumentMetadata, + BadRequestException, + Injectable, + PipeTransform, +} from '@nestjs/common'; +import { OPTIONAL_INT_PIPE_NUMBER } from 'src/errors/errors.constants'; + +/** Convert a string like "1" to a number, but without NaN */ +@Injectable() +export class OptionalIntPipe implements PipeTransform { + transform(value: string, metadata: ArgumentMetadata): number | undefined { + if (value == null) return undefined; + const num = Number(value); + if (isNaN(num)) + throw new BadRequestException( + OPTIONAL_INT_PIPE_NUMBER.replace('$key', metadata.data), + ); + return num; + } +} diff --git a/src/pipes/order-by.pipe.ts b/src/pipes/order-by.pipe.ts new file mode 100644 index 000000000..aadfa8585 --- /dev/null +++ b/src/pipes/order-by.pipe.ts @@ -0,0 +1,35 @@ +import { + ArgumentMetadata, + BadGatewayException, + BadRequestException, + Injectable, + PipeTransform, +} from '@nestjs/common'; +import { + ORDER_BY_ASC_DESC, + ORDER_BY_FORMAT, +} from 'src/errors/errors.constants'; + +/** Convert a string like "name asc, address desc" to { name: "asc", address: "desc" } */ +@Injectable() +export class OrderByPipe implements PipeTransform { + transform( + value: string, + metadata: ArgumentMetadata, + ): Record | undefined { + if (value == null) return undefined; + try { + const rules = value.split(',').map((val) => val.trim()); + const orderBy: Record = {}; + rules.forEach((rule) => { + const [key, order] = rule.split(' ') as [string, 'asc' | 'desc']; + if (!['asc', 'desc'].includes(order.toLocaleLowerCase())) + throw new BadGatewayException(ORDER_BY_ASC_DESC); + orderBy[key] = order.toLocaleLowerCase() as 'asc' | 'desc'; + }); + return orderBy; + } catch (_) { + throw new BadRequestException(ORDER_BY_FORMAT); + } + } +} diff --git a/src/pipes/where.pipe.ts b/src/pipes/where.pipe.ts new file mode 100644 index 000000000..b7656fad0 --- /dev/null +++ b/src/pipes/where.pipe.ts @@ -0,0 +1,31 @@ +import { + ArgumentMetadata, + BadRequestException, + Injectable, + PipeTransform, +} from '@nestjs/common'; +import { WHERE_PIPE_FORMAT } from '../errors/errors.constants'; +import { parseObjectLiteral } from '../helpers/parse-object-literal'; + +/** Convert a string like "id: 12, b: 'Anand'" to { id: 12, name: "Anand" } */ +@Injectable() +export class WherePipe implements PipeTransform { + transform( + value: string, + metadata: ArgumentMetadata, + ): Record | undefined { + if (value == null) return undefined; + try { + const rules = parseObjectLiteral(value); + const items: Record = {}; + rules.forEach((rule) => { + const num = Number(rule[1]); + if (!isNaN(num)) items[rule[0]] = num; + else if (rule[1]) items[rule[0]] = rule[1]; + }); + return items; + } catch (_) { + throw new BadRequestException(WHERE_PIPE_FORMAT); + } + } +} diff --git a/src/rest/index.ts b/src/rest/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index cd04251bc..000000000 --- a/src/server.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { cosmicSync, config } from "@anandchowdhary/cosmic"; -cosmicSync("staart"); - -import { success } from "@staart/errors"; -import { Controller, Get, Server } from "@staart/server"; -import { setupMiddleware } from "@staart/server"; - -import { - errorHandler, - rateLimitHandler, - speedLimitHandler, - trackingHandler, -} from "./_staart/helpers/middleware"; - -@Controller(config("controllerPrefix")) -class RootController { - @Get() - async info() { - return { - repository: "https://github.com/staart/api", - docs: "https://staart.js.org", - madeBy: ["https://anandchowdhary.com"], - }; - } -} - -export class Staart extends Server { - constructor() { - super(); - this.setupHandlers(); - this.addControllers([new RootController()]); - this.app.use(errorHandler); - } - - public start(port: number): void { - this.app.listen(port, () => success(`Listening on ${port}`)); - } - - private setupHandlers() { - setupMiddleware(this.app); - this.app.use(trackingHandler); - this.app.use(rateLimitHandler); - this.app.use(speedLimitHandler); - } -} diff --git a/src/services/index.ts b/src/services/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/templates/auth/approve-subnet.md b/src/templates/auth/approve-subnet.md new file mode 100644 index 000000000..90626aa84 --- /dev/null +++ b/src/templates/auth/approve-subnet.md @@ -0,0 +1,9 @@ +# Approve your login + +Hi {{name}}, + +Someone (hopefully you) logged in to your account from a new location ({{ locationName }}), so you'll have to approve it. + +Approve this login + +Note that this link is valid for {{ minutes }} minutes only. If you didn't request this email, you can just ignore it; we won't give anyone else access to your account. diff --git a/src/templates/auth/email-verification.md b/src/templates/auth/email-verification.md new file mode 100644 index 000000000..991e7eb3a --- /dev/null +++ b/src/templates/auth/email-verification.md @@ -0,0 +1,9 @@ +# Verify your email + +Hi {{name}}, + +Someone (hopefully you) requested a link to confirm your email, so here you go. + +Verify my email + +Note that this link is valid for {{ days }} days only. If you didn't request this email, you can just ignore it. diff --git a/src/templates/auth/enable-email-mfa.md b/src/templates/auth/enable-email-mfa.md new file mode 100644 index 000000000..8ab4c9472 --- /dev/null +++ b/src/templates/auth/enable-email-mfa.md @@ -0,0 +1,7 @@ +# Enable multi-factor authentication with {{ code }} + +Hi {{name}}, + +Enter the following code to enable email-based multi-factor authentication: **{{ code }}**. + +If you didn't request this email, you can just ignore it; we won't give anyone else access to your account. diff --git a/src/templates/auth/mfa-code.md b/src/templates/auth/mfa-code.md new file mode 100644 index 000000000..7f5a52b29 --- /dev/null +++ b/src/templates/auth/mfa-code.md @@ -0,0 +1,9 @@ +# Approve your login + +Hi {{name}}, + +Someone (hopefully you) logged in to your account, but you'll have to approve it. + +Approve this login + +Note that this link is valid for {{ minutes }} minutes only. If you didn't request this email, you can just ignore it; we won't give anyone else access to your account. diff --git a/src/templates/auth/password-reset.md b/src/templates/auth/password-reset.md new file mode 100644 index 000000000..2698ac60f --- /dev/null +++ b/src/templates/auth/password-reset.md @@ -0,0 +1,9 @@ +# Reset your password + +Hi {{name}}, + +Someone (hopefully you) requested a link to reset your password, so here you go. + +Reset my password + +Note that this link is valid for {{ minutes }} minutes only. If you didn't request this email, you can just ignore it; we won't give anyone else access to your account. diff --git a/src/templates/auth/resend-email-verification.md b/src/templates/auth/resend-email-verification.md new file mode 100644 index 000000000..ccad33c8b --- /dev/null +++ b/src/templates/auth/resend-email-verification.md @@ -0,0 +1,9 @@ +# Verify your email + +Hi {{name}}, + +Someone (hopefully you) requested to another link to confirm your email, so here you go. + +Verify my email + +Note that this link is valid for {{ days }} days only. If you didn't request this email, you can just ignore it. diff --git a/src/templates/auth/used-backup-code.md b/src/templates/auth/used-backup-code.md new file mode 100644 index 000000000..7f55b4e26 --- /dev/null +++ b/src/templates/auth/used-backup-code.md @@ -0,0 +1,9 @@ +# Login with a backup code + +Hi {{name}}, + +Someone (hopefully you) logged in to your account from **{{ locationName }}**, and they used a backup code when asked for a two-factor authentication code. + +Check recent activity + +If you didn't login to your account, you should immediately change your password and regenerate your backup codes. You can do that by logging in to your account. diff --git a/src/templates/credits-invited-by.md b/src/templates/credits-invited-by.md deleted file mode 100644 index cd7733c9d..000000000 --- a/src/templates/credits-invited-by.md +++ /dev/null @@ -1,9 +0,0 @@ -# Your \$5 invite credits from {{newUserName}} - -Dear {{invitedByName}}, - -You invited {{newUserName}} to join Staart, and they just did! - -Here's your special code for \$5: **{{invitedByCode}}** - -Log in to your account diff --git a/src/templates/credits-new-user.md b/src/templates/credits-new-user.md deleted file mode 100644 index f3e7dc418..000000000 --- a/src/templates/credits-new-user.md +++ /dev/null @@ -1,9 +0,0 @@ -# Your \$5 invite credits from {{invitedByName}} - -Dear {{newUserName}}, - -{{invitedByName}} invited you to join Staart, and you just did! - -Here's your special code for \$5: **{{newUserCode}}** - -Log in to your account diff --git a/src/templates/email-verify.md b/src/templates/email-verify.md deleted file mode 100644 index e78b0e4b6..000000000 --- a/src/templates/email-verify.md +++ /dev/null @@ -1,9 +0,0 @@ -# Verify your email - -Dear {{name}}, - -Click on the following button to verify this email for your account. - -Verify your email - -If you didn't request this email, you can safely ignore it, we won't let anyone in. diff --git a/src/templates/groups/invitation.md b/src/templates/groups/invitation.md new file mode 100644 index 000000000..cff5c06bf --- /dev/null +++ b/src/templates/groups/invitation.md @@ -0,0 +1,9 @@ +# Welcome to {{ group }} + +Hi {{name}}, + +You've joined the group **{{ group }}**. You can manage your membership by logging to your account. + +Visit this group + +If you didn't want to be added to {{ group }}, you can log in to your account and leave the group. diff --git a/src/templates/invited.md b/src/templates/invited.md deleted file mode 100644 index 1b7760361..000000000 --- a/src/templates/invited.md +++ /dev/null @@ -1,11 +0,0 @@ -# Welcome to {{team}} - -Dear {{name}}, - -{{inviter}} invited you to the team **{{team}}**. - -When you log in to your Staart account, you can switch to this new team. - -Log in to your account - -If you didn't want to be added to this team, you can easily leave it after logging in. diff --git a/src/templates/layout.html b/src/templates/layout.html new file mode 100644 index 000000000..3eb2f0025 --- /dev/null +++ b/src/templates/layout.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + +
  +
+ + + + +
+ + + + +
{{{ content }}}
+
+
+
 
+ + diff --git a/src/templates/login-link.md b/src/templates/login-link.md deleted file mode 100644 index 11c9613d7..000000000 --- a/src/templates/login-link.md +++ /dev/null @@ -1,7 +0,0 @@ -# Your login link - -Dear {{name}}, - -To log in to your account, click on the following link: - -Login to your account diff --git a/src/templates/new-password.md b/src/templates/new-password.md deleted file mode 100644 index 6a4b78ccc..000000000 --- a/src/templates/new-password.md +++ /dev/null @@ -1,11 +0,0 @@ -# Set a password - -Dear {{name}}, - -Welcome to Staart! We're excited to have to. - -You can click on the following button to set up a password for your new account and log in: - -Set a password - -PS: You're getting this email because either you created a new Staart account, or someone invited you to their team. diff --git a/src/templates/password-reset.md b/src/templates/password-reset.md deleted file mode 100644 index ca475544a..000000000 --- a/src/templates/password-reset.md +++ /dev/null @@ -1,9 +0,0 @@ -# Reset your password - -Dear {{name}}, - -Click on the following button to reset your password: - -Reset your password - -If you didn't request this email, you can safely ignore it. diff --git a/src/templates/template.html b/src/templates/template.html deleted file mode 100644 index 1395e3909..000000000 --- a/src/templates/template.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - - - - - - - - - - -
  -
- {{ introLine }} - - - - -
- - - - -
-

Text

- - - - - - -
- - - - - - -
- {{ ctaText }} -
-
-

More text

-
-
- -
-
 
- - diff --git a/src/templates/unapproved-location.md b/src/templates/unapproved-location.md deleted file mode 100644 index a5e403274..000000000 --- a/src/templates/unapproved-location.md +++ /dev/null @@ -1,9 +0,0 @@ -# Approve this login in {{location}} - -Dear {{name}}, - -Someone tried to log in to your account from {{location}}. If this was you, you can approve this login and we'll remember this location. - -Approve this login - -If this wasn't you, maybe someone else is trying to log in to your account. You should definitely change your password if that's the case. diff --git a/src/templates/users/merge-request.md b/src/templates/users/merge-request.md new file mode 100644 index 000000000..26e05eca1 --- /dev/null +++ b/src/templates/users/merge-request.md @@ -0,0 +1,9 @@ +# Account merge request + +Hi {{name}}, + +We received a request to merge your account with another account. + +Merge this account + +Note that this link is valid for {{ minutes }} minutes only. If you didn't request this email, you can just ignore it; we won't give anyone else access to your account. diff --git a/static/favicon.ico b/static/favicon.ico deleted file mode 100644 index b10ad3017..000000000 Binary files a/static/favicon.ico and /dev/null differ diff --git a/static/robots.txt b/static/robots.txt index e223f0983..1f53798bb 100644 --- a/static/robots.txt +++ b/static/robots.txt @@ -1,3 +1,2 @@ User-agent: * -Allow: /$ Disallow: / diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts new file mode 100644 index 000000000..50cda6233 --- /dev/null +++ b/test/app.e2e-spec.ts @@ -0,0 +1,24 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from './../src/app.module'; + +describe('AppController (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + it('/ (GET)', () => { + return request(app.getHttpServer()) + .get('/') + .expect(200) + .expect('Hello World!'); + }); +}); diff --git a/test/jest-e2e.json b/test/jest-e2e.json new file mode 100644 index 000000000..e9d912f3e --- /dev/null +++ b/test/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 000000000..64f86c6bd --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index 9d89b6d63..3a4985d5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,16 @@ { "compilerOptions": { - "moduleResolution": "node", - "target": "es6", "module": "commonjs", - "lib": ["esnext", "dom"], - "strict": true, - "sourceMap": true, "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "experimentalDecorators": true, - "resolveJsonModule": true, - "emitDecoratorMetadata": true, - "declarationDir": "./dist", - "outDir": "./dist" - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules"] + "allowSyntheticDefaultImports": true, + "target": "es2017", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true + } }