diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..23a0816 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +# don't ever lint node_modules +node_modules +# don't lint build output (make sure it's set to your correct build folder name) +dist +# don't lint nyc coverage output +coverage + +test/ diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..2a8ad73 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + root: true, + env: { + node: true, + mocha: true + }, + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json' + }, + plugins: [ + '@typescript-eslint' + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'standard-with-typescript' + ], + rules: { + semi: ['warn', 'always'], + '@typescript-eslint/semi': ['warn', 'always'], + '@typescript-eslint/strict-boolean-expressions': ['off'], + 'spaced-comment': ['off'] + }, + overrides: [ + { + files: ['test/**/*.ts'], + rules: { + '@typescript-eslint/ban-ts-comment': ['off'] + } + } + ] +}; diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..441a09f --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,29 @@ +# This workflow will do a clean install of node dependencies, run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x, 15.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm test diff --git a/.gitignore b/.gitignore index 5457862..8050818 100755 --- a/.gitignore +++ b/.gitignore @@ -33,9 +33,10 @@ node_modules # The compiled/babelified modules lib/ +dist/ ## editor .idea/ -.vscode/ -.prettierrc \ No newline at end of file +#.vscode/ +.prettierrc diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 0000000..30deb04 --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,12 @@ +'use strict'; +const path = require("path"); + +module.exports = { + extension: ["ts", "js"], + package: path.join(__dirname, "./package.json"), + ui: "bdd", + spec: [ + "./test/**/*.test.*", + ], + exit: true +}; diff --git a/.nycrc b/.nycrc index b2d4769..0651971 100644 --- a/.nycrc +++ b/.nycrc @@ -1,5 +1,15 @@ { "all": true, - "include": ["src/**/*.js"], + "include": [ + "src/**/*.js", + "src/**/*.ts" + ], + "exclude": [ + "coverage/**", + "node_modules/**", + "**/*.d.ts", + "**/*.test.ts" + ], + "sourceMap": true, "reporter": ["text", "html", "lcov"] -} \ No newline at end of file +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..da964b5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-node", + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!**/node_modules/**" + ], + "request": "launch", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/mocha", + "args": [ + "--require", + "ts-node/register", + "--timeout", + "999999", + "--colors", + "--recursive" + ], + "internalConsoleOptions": "openOnSessionStart", + "env": { + "NODE_ENV": "test", + "TS_NODE_PROJECT": "tsconfig.test.json" + }, + "outputCapture": "std", + "skipFiles": [ + "/**" + ] + }, + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9665201 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "search.exclude": { + "**/node_modules": true, + "**/public": true, + "**/package-lock.json": true, + "**/yarn.lock": true + }, + "workbench.colorCustomizations": { + "activityBar.background": "#520064", + "titleBar.activeBackground": "#520064", + "titleBar.activeForeground": "#FAFBF4" + } +} diff --git a/LICENSE b/LICENSE index 1eaf9ea..3f395cc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Feathers +Copyright (c) 2021 Feathers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs.md b/docs.md index 8d96d3c..6a730a6 100755 --- a/docs.md +++ b/docs.md @@ -82,23 +82,31 @@ Leaving it a pure API server, lets it be used with both native and browser clien ## Contents -- [The Service](#service) -- [Client](#client) - - [Using Feathers' method calls](#using-feathers-method-calls) - - [Provided service wrappers](#provided-service-wrappers) - - [HTTP fetch](#http-fetch) - - [React's redux](#react-redux) - - [Dispatching services](#dispatching-services) - - [Dispatching authentication](#dispatching-authentication) - - [Vue 2.0 (docs to do)](#vue) -- [Hooks](#hooks) -- [Multiple services](#multiple-services) -- [Database](#database) -- [Routing](#routing) -- [Security](#security) -- [Docs](#docs) -- [Configurable](#configurable) -- [Tests](#tests) +- [feathers-authentication-management](#feathers-authentication-management) + - [Multiple communication channels:](#multiple-communication-channels) + - [Capabilities:](#capabilities) + - [User notifications may be sent for:](#user-notifications-may-be-sent-for) + - [May be used with](#may-be-used-with) + - [Contents](#contents) + - [Service](#service) + - [Client](#client) + - [Using Feathers method calls](#using-feathers-method-calls) + - [Provided service wrappers](#provided-service-wrappers) + - [HTTP fetch](#http-fetch) + - [React Redux](#react-redux) + - [Dispatching services](#dispatching-services) + - [Dispatching authentication](#dispatching-authentication) + - [Vue](#vue) + - [Hooks](#hooks) + - [`verifyHooks.addVerification( path = 'authManagement' )`](#verifyhooksaddverification-path--authmanagement-) + - [`verifyHooks.isVerified()`](#verifyhooksisverified) + - [Multiple services](#multiple-services) + - [Database](#database) + - [Routing](#routing) + - [Security](#security) + - [Docs](#docs) + - [Configurable](#configurable) + - [Tests](#tests) ## Service @@ -497,7 +505,7 @@ You should add them to your user model if your database uses models. resetToken: { type: String }, resetShortToken: { type: String }, resetExpires: { type: Date }, // or a long integer - resetAttempts: { type: Number }, + resetAttempts: { type: Number } } ``` diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js new file mode 100644 index 0000000..098ede6 --- /dev/null +++ b/docs/.vitepress/config.js @@ -0,0 +1,23 @@ +module.exports = { + title: 'feathers-authentication-management', + description: 'Sign up verification, forgotten password reset, and other capabilities for local authentication', + themeConfig: { + repo: 'feathersjs-ecosystem/feathers-authentication-management', + editLinks: true, + editLinkText: 'Edit this page on GitHub', + lastUpdated: 'Last Updated', + sidebarDepth: 1, + displayAllHeaders: true, + sidebar: { + '/': [ + { text: 'Overview', link: '/overview' }, + { text: 'Getting Started', link: '/getting-started' }, + { text: 'Basic Usage', link: '/basic' }, + { text: 'Services', link: '/services' }, + { text: 'Hooks', link: "/hooks" }, + { text: "Client", link: "/client" }, + { text: "Advanced Usage", link: "/advanced" } + ] + }, + } +} diff --git a/docs/.vitepress/style.styl b/docs/.vitepress/style.styl new file mode 100644 index 0000000..5f2c5db --- /dev/null +++ b/docs/.vitepress/style.styl @@ -0,0 +1,20 @@ +// colors +$accentColor = #520064 +$textColor = #2c3e50 +$borderColor = #eaecef +$codeBgColor = #282c34 +$arrowBgColor = #ccc +$badgeTipColor = #520064 +$badgeWarningColor = darken(#ffe564, 35%) +$badgeErrorColor = #DA5961 + +// layout +$navbarHeight = 3.6rem +$sidebarWidth = 20rem +$contentWidth = 960px +$homePageWidth = 960px + +// responsive breakpoints +$MQNarrow = 959px +$MQMobile = 719px +$MQMobileNarrow = 419px diff --git a/docs/advanced.md b/docs/advanced.md new file mode 100644 index 0000000..1e631ab --- /dev/null +++ b/docs/advanced.md @@ -0,0 +1,135 @@ +--- +title: Advanced Usage +--- + +# {{ $frontmatter.title }} + +[[toc]] + +## Multiple services + +We have considered until now situations where authentication was based on a user item. +`feathers-authorization` however allows users to sign in with group and organization +credentials as well as user ones. + +You can easily configure `feathers-authentication-management` to handle such situations. +Please refer to `test/multiInstances.test.js`. + +## Database + +The service adds the following optional properties to the user item. +You should add them to your user model if your database uses models. + +```javascript +{ + isVerified: { type: Boolean }, + verifyToken: { type: String }, + verifyShortToken: { type: String }, + verifyExpires: { type: Date }, // or a long integer + verifyChanges: // an object (key-value map), e.g. { field: "value" } + resetToken: { type: String }, + resetShortToken: { type: String }, + resetExpires: { type: Date }, // or a long integer + resetAttempts: { type: Number } +} +``` + +## Routing + +The client handles all interactions with the user. +Therefore the server must serve the client app when, for example, a URL link is followed +for email addr verification. +The client must do some routing based on the path in the link. + +Assume you have sent the email link: +`http://localhost:3030/socket/verify/12b827994bb59cacce47978567989e` + +The server serves the client app on `/socket`: + +```javascript +// Express-like middleware provided by Feathersjs. +app.use("/", serveStatic(app.get("public"))).use("/socket", (req, res) => { + res.sendFile(path.resolve(__dirname, "..", "public", "socket.html")); // serve the client +}); +``` + +The client then routes itself based on the URL. +You will likely use you favorite client-side router, +but a primitive routing would be: + +```javascript +const [leader, provider, action, slug] = window.location.pathname.split("/"); + +switch (action) { + case "verify": + verifySignUp(slug); + break; + case "reset": + resetPassword(slug); + break; + default: + // normal app startup +} +``` + +## Security + +- The user must be identified when the short token is used, making the short token less appealing + as an attack vector. +- The long and short tokens are erased on successful verification and password reset attempts. + New tokens must be acquired for another attempt. +- API params are verified to be strings. If the param is an object, the values of its props are + verified to be strings. +- options.identifyUserProps restricts the prop names allowed in param objects. +- In order to protect sensitive data, you should set a hook that prevent `PATCH` or `PUT` calls on + authentication-management related properties: + +```javascript +// in user service hook +before: { + update: [ + iff(isProvider('external'), preventChanges( + 'isVerified', + 'verifyToken', + 'verifyShortToken', + 'verifyExpires', + 'verifyChanges', + 'resetToken', + 'resetShortToken', + 'resetExpires' + )), + ], + patch: [ + iff(isProvider('external'), preventChanges( + 'isVerified', + 'verifyToken', + 'verifyShortToken', + 'verifyExpires', + 'verifyChanges', + 'resetToken', + 'resetShortToken', + 'resetExpires' + )), + ], +}, +``` + +## Docs + +_optional params_ + +Because this service doesn't use `app.use()` but `app.configure()`, you can't add documentation like it's recommended by [@feathers-swagger](feathers-swagger). Instead, you've just have to pass your docs through the second params. + +```js +// authManagement.service.js +const docs = { + description: "A service to manage authentication", +}; + +app.configure(authManagement(notifier(app), docs)); +``` + +## Configurable + +The length of the "30-char" token is configurable. +The length of the "6-digit" token is configurable. It may also be configured as alphanumeric. diff --git a/docs/basic.md b/docs/basic.md new file mode 100644 index 0000000..0e53f52 --- /dev/null +++ b/docs/basic.md @@ -0,0 +1,5 @@ +--- +title: Basic Usage +--- + +# {{ $frontmatter.title }} diff --git a/docs/client.md b/docs/client.md new file mode 100644 index 0000000..d505807 --- /dev/null +++ b/docs/client.md @@ -0,0 +1,281 @@ +--- +title: Client +--- + +# {{ $frontmatter.title }} + +The service may be called on the client using + +[[toc]] + +### + +```html + + +

+ Sending token +

+ + + +``` + +### Using Feathers method calls + +Method calls return a Promise. + +```js +const authManagementService = require("feathers-authentication-management"); +app.configure(authManagementService(options)); +const authManagement = app.service("authManagement"); + +// check props are unique in the users items +authManagement.create({ + action: "checkUnique", + value: identifyUser, // e.g. {email, username}. Props with null or undefined are ignored. + ownId, // excludes your current user from the search + meta: { noErrMsg }, // if return an error.message if not unique +}); +// ownId allows the "current" item to be ignored when checking if a field value is unique amoung users. +// noErrMsg determines if the returned error.message contains text. This may simplify your client side validation. + +// resend sign up verification notification +authManagement.create({ + action: "resendVerifySignup", + value: identifyUser, // {email}, {token: verifyToken} + notifierOptions: {}, // options passed to options.notifier, e.g. {preferredComm: 'cellphone'} +}); + +// sign up or identityChange verification with long token +authManagement.create({ + action: "verifySignupLong", + value: verifyToken, // compares to .verifyToken +}); + +// sign up or identityChange verification with short token +authManagement.create({ + action: "verifySignupShort", + value: { + user, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps. + token, // compares to .verifyShortToken + }, +}); + +// sign up verification and set password with long token +authManagement.create({ + action: "verifySignupSetPasswordLong", + value: { + token, // compares to .verifyToken + password, // new password + }, +}); + +// sign up verification and set password with short token +authManagement.create({ + action: "verifySignupSetPasswordShort", + value: { + user, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps. + token, // compares to .verifyShortToken + password, // new password + }, +}); + +// send forgotten password notification +authManagement.create({ + action: "sendResetPwd", + value: identifyUser, // {email}, {token: verifyToken} + notifierOptions, // options passed to options.notifier, e.g. {preferredComm: 'email'} +}); + +// forgotten password verification with long token +authManagement.create({ + action: "resetPwdLong", + value: { + token, // compares to .resetToken + password, // new password + }, +}); + +// forgotten password verification with short token +authManagement.create({ + action: "resetPwdShort", + value: { + user: identifyUser, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps. + token, // compares to .resetShortToken + password, // new password + }, +}); + +// change password +authManagement.create({ + action: "passwordChange", + value: { + user: identifyUser, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps. + oldPassword, // old password for verification + password, // new password + }, +}); + +// change communications +authManagement.create({ + action: "identityChange", + value: { + user: identifyUser, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps. + password, // current password for verification + changes, // {email: 'a@a.com'} or {email: 'a@a.com', cellphone: '+1-800-555-1212'} + }, +}); + +// Authenticate user and log on if user is verified. +let cbCalled = false; +app + .authenticate({ type: "local", email, password }) + .then((result) => { + const user = result.data; + if (!user || !user.isVerified) { + app.logout(); + cb( + new Error(user ? "User's email is not verified." : "No user returned.") + ); + return; + } + cbCalled = true; + cb(null, user); + }) + .catch((err) => { + if (!cbCalled) { + cb(err); + } // ignore throws from .then( cb(null, user) ) + }); +``` + +### Provided service wrappers + +The wrappers return a Promise. + +```javascript + + // or +const AuthManagement = require('feathers-authentication-management/lib/client'); +const app = feathers() ... +const authManagement = new AuthManagement(app); + +// check props are unique in the users items +authManagement.checkUnique(identifyUser, ownId, ifErrMsg) + +// resend sign up verification notification +authManagement.resendVerifySignup(identifyUser, notifierOptions) + +// sign up or identityChange verification with long token +authManagement.verifySignupLong(verifyToken) + +// sign up or identityChange verification with short token +authManagement.verifySignupShort(verifyShortToken, identifyUser) + +// sign up or identityChange verification with long token +authManagement.verifySignupSetPasswordLong(verifyToken, password) + +// sign up or identityChange verification with short token +authManagement.verifySignupSetPasswordShort(verifyShortToken, identifyUser, password) + +// send forgotten password notification +authManagement.sendResetPwd(identifyUser, notifierOptions) + +// forgotten password verification with long token +authManagement.resetPwdLong(resetToken, password) + +// forgotten password verification with short token +authManagement.resetPwdShort(resetShortToken, identifyUser, password) + +// change password +authManagement.passwordChange(oldPassword, password, identifyUser) + +// change identity +authManagement.identityChange(password, changesIdentifyUser, identifyUser) + +// Authenticate user and log on if user is verified. v0.x only. +authManagement.authenticate(email, password) +``` + +### HTTP fetch + +```javascript +// check props are unique in the users items +// Set params just like [Feathers method calls.](#methods) +fetch('/authManagement', { + method: 'POST', headers: { Accept: 'application/json' }, + body: JSON.stringify({ action: 'checkUnique', value: identifyUser, ownId, meta: { noErrMsg } }) +}) + .then(data => { ... }).catch(err => { ... }); +``` + +### React Redux + +See `feathers-reduxify-services` for information about state, etc. +See `feathers-starter-react-redux-login-roles` for a working example. + +#### Dispatching services + +```javascript +import feathers from 'feathers-client'; +import reduxifyServices from 'feathers-reduxify-services'; +const app = feathers().configure(feathers.socketio(socket)).configure(feathers.hooks()); +const services = reduxifyServices(app, ['users', 'authManagement', ...]); +... +// hook up Redux reducers +export default combineReducers({ + users: services.users.reducer, + authManagement: services.authManagement.reducer, +}); +... + +// email addr verification with long token +// Feathers is now 100% compatible with Redux. Use just like [Feathers method calls.](#methods) +store.dispatch(services.authManagement.create({ action: 'verifySignupLong', + value: verifyToken, + }, {}) +); +``` + +#### Dispatching authentication + +User must be verified to sign in. v0.x only. + +```javascript +const reduxifyAuthentication = require('feathers-reduxify-authentication'); +const signin = reduxifyAuthentication(app, { isUserAuthorized: (user) => user.isVerified }); + +// Sign in with the JWT currently in localStorage +if (localStorage['feathers-jwt']) { + store.dispatch(signin.authenticate()).catch(err => { ... }); +} + +// Sign in with credentials +store.dispatch(signin.authenticate({ type: 'local', email, password })) + .then(() => { ... ) + .catch(err => { ... }); +``` + +### Vue diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..674d1c6 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,230 @@ +--- +title: Getting Started +--- + +# {{ $frontmatter.title }} + +## Installation + +```bash +npm i feathers-authentication-management feathers-mailer +# or +yarn add feathers-authentication-management feathers-mailer +``` + +## Setup feathers-mailer + +See [feathers-mailer](https://github.com/feathersjs-ecosystem/feathers-mailer) + +## Setup application + +```js +// src/app.js +const authManagement = require('feathers-authentication-management'); +app + .configure(authentication) + .configure(authManagement({ options }, { docs })) +``` + +### Options + +- `service: string = '/users'`: The path of the service for user items, e.g. `/users` (default) or `/organization`. +- `path: string = 'authManagement'`: The path to associate with this service`. + See [Multiple services](#multiple-services) for more information. +- `skipIsVerifiedCheck: boolean = false`: if `false` (default) it is impossible to reset password if email is not verified. +- `sanitizeUserForClient: (user: User) => Partial`: ([default](https://github.com/feathers-plus/feathers-authentication-management/blob/master/src/helpers/sanitize-user-for-client.js)) sanitize the user in the response, if not overwritten **THE USER OBJECT IS IN THE RESPONSE** eg. on a password reset request, to reply with empty object use `sanitizeUserForClient: () => ({})` +- `notifier: (type: string, user: User, notifierOptions) => Promise` returns a Promise. + - type: type of notification + - `'resendVerifySignup'` From resendVerifySignup API call + - `'verifySignup'` From verifySignupLong and verifySignupShort API calls + - `'verifySignupSetPassword'` From verifySignupSetPasswordLong and verifySignupSetPasswordShort API calls + - `'sendResetPwd'` From sendResetPwd API call + - `'resetPwd'` From resetPwdLong and resetPwdShort API calls + - `'passwordChange'` From passwordChange API call + - `'identityChange'` From identityChange API call + - `user`: user's item, minus password. + - `notifierOptions`: notifierOptions option from resendVerifySignup and sendResetPwd API calls +- `longTokenLen: number = 15`: Half the length of the long token. Default is 15, giving 30-char tokens. +- `shortTokenLen: number = 6`: Length of short token. +- `shortTokenDigits: boolean = true`: Short token is digits if true, else alphanumeric. +- `delay: number = 1000 * 60 * 60 * 24 * 5`: Duration for sign up email verification token in ms. Default is 5 days. +- `resetDelay: number = 1000 * 60 * 60 * 2`: Duration for password reset token in ms. Default is 2 hours. +- `resetAttempts: number = 0`: Amount of times a user can submit an invalid token before the current token gets removed from the database. Default is 0. +- `reuseResetToken: boolean = false`: Use the same reset token if the user resets password twice in a short period. In this case token is not hashed in the database. Default is false. +- `identifyUserProps: string[] = ['email']`: Prop names in `user` item which uniquely identify the user, + e.g. `['username', 'email', 'cellphone']`. + The default is `['email']`. + The prop values must be strings. + Only these props may be changed with verification by the service. + At least one of these props must be provided whenever a short token is used, + as the short token alone is too susceptible to brute force attack. +- `passwordField: string = 'password'`: Prop name of the password field. +- `useSeparateServices: boolean | Record = false`: Registers the following services which are also accessible on the client: + - `checkUnique`: `${path}/check-unique'` + - `identityChange`: `${path}/identity-change`, + - `passwordChange`: `${path}/password-change`, + - `resendVerifySignup`: `${path}/resend-verify-signup`, + - `resetPwdLong`: `${path}/reset-password-long`, + - `resetPwdShort`: `${path}/reset-password-short`, + - `sendResetPwd`: `${path}/send-reset-pwd`, + - `verifySignupLong`: `${path}/verify-signup-long`, + - `verifySignupSetPasswordLong`: `${path}/verify-signup-set-password-long`, + - `verifySignupSetPasswordShort`: `${path}/verify-signup-set-password-short`, + - `verifySignupShort`: `${path}/verify-signup-short` + +`docs` (optional) are: + +- representation of the service swagger documentation. Default `{}` + +### Create notifier function + +```js +// src/services/auth-management/notifier.js + +module.exports = function(app) { + function getLink(type, hash) { + const url = 'http://localhost:3030/' + type + '?token=' + hash; // your domain url + return url; + } + + function sendEmail(email) { + return app.service('mailer').create(email).then(function (result) { + console.log('Sent email', result) + }).catch(err => { + console.log('Error sending email', err) + }) + } + + return { + // see options.notifier + notifier: function(type, user, notifierOptions) { + let tokenLink + let email + switch (type) { + case 'resendVerifySignup': //sending the user the verification email + tokenLink = getLink('verify', user.verifyToken) + email = { + from: process.env.FROM_EMAIL, + to: user.email, + subject: 'Verify Signup', + html: tokenLink + } + return sendEmail(email) + break + + case 'verifySignup': // confirming verification + tokenLink = getLink('verify', user.verifyToken) + email = { + from: process.env.FROM_EMAIL, + to: user.email, + subject: 'Confirm Signup', + html: 'Thanks for verifying your email' + } + return sendEmail(email) + break + + case 'sendResetPwd': + tokenLink = getLink('reset', user.resetToken) + email = {} + return sendEmail(email) + break + + case 'resetPwd': + tokenLink = getLink('reset', user.resetToken) + email = {} + return sendEmail(email) + break + + case 'passwordChange': + email = {} + return sendEmail(email) + break + + case 'identityChange': + tokenLink = getLink('verifyChanges', user.verifyToken) + email = {} + return sendEmail(email) + break + + default: + break + } + } + } +} +``` + +- The `getLink` function generates our token url. This can either have a verify token or a reset token included. For now, we are only using the verify token. +- The `sendEmail` function calls our `/mailer` service internally to send the email. +- The notifier function, based on the action type, decides what email to send where. We are now only using the verification part but this can also be used to code the other actions. Also, we will only be sending the plain link to the email. If you want to use html templates or some preprocessor to generate nicer looking emails, you need to make sure they are inserted as a value in the html key in the email object. + +### Add properties to your `/users` service + +The service creates and maintains the following properties in the `user` item: + +- `isVerified: boolean`: If the user's email addr has been verified +- `verifyToken: string`: The 30-char token generated for email addr verification +- `verifyShortToken: string`: The 6-digit token generated for cellphone addr verification +- `verifyExpires: Date|number`: When the email addr token expire +- `verifyChanges: string[]`: New values to apply on verification to some identifyUserProps +- `resetToken: string`: The 30-char token generated for forgotten password reset +- `resetShortToken: string`: The 6-digit token generated for forgotten password reset +- `resetExpires: Date|number`: When the forgotten password token expire +- `resetAttempts: number`: Amount of incorrect reset submissions left before token invalidation + +The following user item might also contain the following props: + +- `preferredComm`: The preferred way to notify the user. One of `options.identifyUserProps`. + +The `/users` service is expected to be already configured. +Its `patch` method is used to update the password when needed, +and this module hashes the password before it is passed to `patch`, +therefore `patch` may _not_ have a `auth.hashPassword()` hook. In cases where you only need hashPassword for externally submitted patch calls, you may use `iff(isProvider('external'), hashPassword())` on the patch hook. + +The user must be signed in before being allowed to change their password or communication values. +The service, for feathers-authenticate v1.x, requires hooks similar to: + +```javascript +// src/services/auth-management/auth-management.hooks.js +const { authenticate } = require("@feathersjs/authentication").hooks; +const { iff } = require('feathers-hooks-common'); + +const isAction = (...args) => (hook) => args.includes(hook.data.action); +app.service("authManagement").before({ + create: [ + iff( + isAction("passwordChange", "identityChange"), + authenticate("jwt") + ), + ], +}); +``` + +### Setting up authentication management hooks + +Now we are ready to set up some hooks to actually get our service to work. For this we need to adapt the `users.hooks.js` file. We need to do a couple of things here. + +- Import the verification hooks from feathers authentication management by adding this line to the top: `const { addVerification, removeVerification } = require(‘feathers-authentication-management’).hooks;` + +- Import our `notifier` by adding this line: `const accountService = require(‘../authmanagement/notifier’);` +- Then add `addVerification()` to the before create hook to add verification to our user object. This needs to be after the `hashPassword()` hook. What this code does is that it adds some extra fields to our user objects and generates a token. +- Finally, we need to add two after create hooks to our `/users` service. One to call our notifier function and one to remove the verification again. That looks like this: + +For a full example, see [Hooks](/hooks.html) + +### Verifying the email link + +For simplicity we will create a basic html page with a `XMLHttpRequest()` script to handle the verification. Obviously there are better ways to handle this with feathers-client and your favorite frontend library. However, that is out of scope of this article. Following the structure of our verification link we will create a new folder in the `/public` folder of our app called “verify”. Here we will put a new `index.html` file. All this needs to do is to send a POST request to our `/authmanagement` service with the following JSON object. + +```json +{ + "action": "verifySignupLong", + "value": YOUR_TOKEN +} +``` + +So in the end all we need to do is create a script that takes the `token` parameter from the URL and posts this to our endpoint. You can create a sample page which looks like this. + +### Securing the application + +Now that the app works there is only one step to complete and that is adding some security to the users service. Since we have a nice authentication flow running we don’t want any users to meddle with the user service directly anymore. For this we create two before hooks. One on the update method and one on the patch method. With the one on the update method we are going to disallow this method in its entirety. After all, we wouldn’t want someone to be able to replace our carefully verified user by a new one. The one on the patch method we want to restrict the user from touching any of the authentication field methods directly. For a full example of the `services/users/users.hooks.js` file see: [Hooks](/hooks.md) diff --git a/docs/hooks.md b/docs/hooks.md new file mode 100644 index 0000000..529eff1 --- /dev/null +++ b/docs/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +--- + +# {{ $frontmatter.title }} + +The service does not itself handle creation of a new user account nor the sending of the initial sign up verification request. Instead hooks are provided for you to use with the `users` service `create` method. If you set a service path other than the default of `'authManagement'`, the custom path name must be passed into the hook. + +## addVerification + +This hook is made exclusively for the `/users` service. Creates tokens and sets default `authManagement` data for users. + +|before|after|methods|multi|details| +|---|---|---|---|---| +|yes|no|create, patch, update|no|[source]()| + +- **Arguments:** + - `path?: string` + +| Argument | Type | Default | Description | +| -------- | :-----------: | ------- | ----------- | +| `path` | `string` | `authManagement` | The service path for the `authManagement` service. | + +- **Example:** + +```javascript +// src/services/users/users.hooks.js +const { + hashPassword, + protect +} = require('@feathersjs/authentication-local').hooks; + +const { + addVerification, + removeVerification +} = require('feathers-authentication-management').hooks; + +const { + disallow, + iff, + isProvider, + preventChanges +} = require('feathers-hooks-common'); + +module.exports = { + before: { + all: [], + find: [ authenticate('jwt') ], + get: [ authenticate('jwt') ], + create: [ + hashPassword('password'), + addVerification(), // adds .isVerified, .verifyExpires, .verifyToken, .verifyChanges + ], + update: [ + disallow('external'), + authenticate('jwt'), + hashPassword('password') + ], + patch: [ + authenticate('jwt'), + iff( + isProvider('external'), + preventChanges( + 'email', + 'isVerified', + 'verifyToken', + 'verifyShortToken', + 'verifyExpires', + 'verifyChanges', + 'resetToken', + 'resetShortToken', + 'resetExpires' + ), + hashPassword('password'), + ) + ], + remove: [ + authenticate('jwt'), + hashPassword('password') + ] + }, + after: { + all: [], + find: [ protect('password') ], + get: [ protect('password') ], + create: [ + protect('password'), + aHookToEmailYourVerification(), + removeVerification(), // removes verification/reset fields other than .isVerified from the response + ], + update: [ protect('password') ], + patch: [ protect('password') ], + remove: [ protect('password') ] + }, + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +}; +``` + +## isVerified + +Throws, if requesting user is not verified (`params.user.isVerified`) and passes otherwise. + +|before|after|methods|multi|details| +|---|---|---|---|---| +|yes|no|all|yes|[source]()| + +- **Arguments:** + - *none* + +- **Example:** + +```js +const { authenticate } = require('feathers-authentication').hooks; +const { isVerified } = require('feathers-authentication-management').hooks; + +module.exports = { + before: { + all: [ + authenticate('jwt'), + isVerified() + ], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + after: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +} +``` + +## removeVerification + +This hook is made exclusively for the `/users` service. It deletes data on user items for external requests that was added for `feathers-authentication-management` to work. It's similar to the `protect('password')` hook from `@feathersjs/authentication-local`. +It deletes `verifyExpires`, `resetExpires` and `verifyChanges` and if `ifReturnToken: true` it also deletes `verifyToken`, `verifyShortToken`, `resetToken` and `resetShortToken`. + +|before|after|methods|multi|details| +|---|---|---|---|---| +|no|yes|all|yes|[source]()| + +- **Arguments:** + - `ifReturnToken?: boolean` + +| Argument | Type | Default | Description | +| -------- | :-----------: | ------- | ----------- | +| `ifReturnToken` | `boolean` | `false` | removes | + +- **Example:** +See the example under [addVerification](hooks.html#addverification) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..3df240e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,10 @@ +--- +home: true +heroImage: /img/logo.svg +heroText: feathers-authentication-management +tagLine: Sign up verification, forgotten password reset, and other capabilities for local authentication. +actionText: Get Started +actionLink: ./getting-started +features: +footer: MIT Licensed | Copyright © 2021 +--- diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..c35742c --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,100 @@ +--- +title: Overview +--- + +# {{ $frontmatter.title }} + +![npm](https://img.shields.io/npm/v/feathers-authentication-management) + +![npm](https://img.shields.io/npm/dm/feathers-authentication-management) +[![GitHub license](https://img.shields.io/github/license/feathersjs-ecosystem/feathers-authentication-management)](https://github.com/feathersjs-ecosystem/feathers-authentication-management/blob/master/LICENSE) + +Sign up verification, forgotten password reset, and other capabilities for local authentication. + +This project is built for [FeathersJS](http://feathersjs.com). An open source web framework for building modern real-time applications. + +### Multiple communication channels: + +Traditionally users have been authenticated using their `username` or `email`. +However that landscape is changing. + +Teens are more involved with cellphone SMS, whatsapp, facebook, QQ and wechat than they are with email. +Seniors may not know how to create an email account or check email, but they have smart phones +and perhaps whatsapp or wechat accounts. + +A more flexible design would maintain multiple communication channels for a user +-- username, email address, phone number, handles for whatsapp, facebook, QQ, wechat -- +which each uniquely identify the user. +The user could then sign in using any of their unique identifiers. +The user could also indicate how they prefer to be contacted. +Some may prefer to get password resets via long tokens sent by email; +others may prefer short numeric tokens sent by SMS or wechat. + +`feathers-authentication` and `feathers-authentication-management` +provide much of the infrastructure necessary to implement such a scenario. + +### Features + +- Checking that values for fields like username, email, cellphone are unique within `users` items. +- Hooks for adding a new user. +- Send another sign up verification notification, routing through user's selected transport. +- Process a sign up or identity change verification from a URL response. +- Process a sign up or identity change verification using a short token. +- Send a forgotten password reset notification, routing through user's preferred communication transport. +- Process a forgotten password reset from a URL response. +- Process a forgotten password reset using a short token. +- Process password change. +- Process an identity change such as a new email addr, or cellphone. + +### User notifications may be sent for: + +- Sign up verification when a new user is created. +- Sign up verification and initial password set when a new user is created. +- Resending a signup verification, e.g. previous verification was lost or is expired. +- Successful user verification. +- Resetting the password when the password is forgotten. +- Successful password reset for a forgotten password. +- Manual change of a password. +- Change of identity. Notify both the current and new e.g. old email addr may be notified when the email addr changes. + +### May be used with + +- `feathers-client` service calls over websockets or HTTP. +- Client side wrappers for `feathers-client` service calls. +- HTTP POST calls. +- React's Redux. +- Vue (docs to do) + +Various-sized tokens can be used during the verify/reset processes: + +A 30-char token is generated suitable for URL responses. +(Configurable length.) +This may be embedded in URL links sent by email, SMS or social media +so that clicking the link starts the sign up verification or the password reset. + +A 6-digit token is also generated suitable for notification by SMS or social media. +(Configurable length, may be alpha-numeric instead.) +This may be manually entered in a UI to start the sign up verification or the password reset. + +The email verification token has a 5-day expiry (configurable), +while the password reset has a 2 hour expiry (configurable). + +Typically your notifier routine refers to a property like `user.preferredComm: 'email'` +to determine which transport to use for user notification. +However the API allows the UI to be set up to ask the user which transport they prefer for that time. + +The server does not handle any interactions with the user. +Leaving it a pure API server, lets it be used with both native and browser clients. + +### Testing + +`npm test` +This repo is pre-configured to work with the Visual Studio Code debugger. After running `npm install`, use the "Mocha Tests" debug script for a smooth debugging experience. + +### Help + +Open an issue or come talk on the FeathersJS Slack. + +### License + +Licensed under the [MIT license](LICENSE). diff --git a/docs/services.md b/docs/services.md new file mode 100644 index 0000000..4e01842 --- /dev/null +++ b/docs/services.md @@ -0,0 +1,213 @@ +--- +title: Services +--- + +# {{ $frontmatter.title }} + +## AuthenticationManagementService + +### create + +`app.service('authManagement').create(data)` + +#### data properties: + +| data action | other data properties | result | +| ------ | ---------- | ------ | +| `'checkUnique'` | - `value: IdentifyUser`
- `ownId?: Id`
- `meta?: { noErrMsg?: boolean }`| `throws BadRequest` or returns `null`| +| `'identityChange'` | - `value: { changes: Record, password: string, user: IdentifyUser }`
- `notifierOptions?: Record` | | +| `'passwordChange'` | - `value: { oldPassword: string, password: string, user: IdentifyUser }`
- `notifierOptions?: Record` | | +| `'resendVerifySignup'` | - `value: IdentifyUser`
- `notifierOptions?: Record` | | +| `'resetPwdLong'` | - `value: { password: string, token: string }`
- `notifierOptions?: Record` | | +| `'resetPwdShort'` | - `value: { password: string, token: string, user: IdentifyUser }`
- `notifierOptions?: Record`| | +| `'sendResetPwd'` | - `value: IdentifyUser`
- `notifierOptions?: Record` | | +| `'verifySignupLong'` | - `value: string`
- `notifierOptions?: Record` | | +| `'verifySignupSetPasswordLong'` | - `value: { password: string, token: string }`
- `notifierOptions?: Record` | | +| `'verifySignupSetPasswordShort'` | - `value: { password: string, token: string, user: IdentifyUser }`
- `notifierOptions?: Record` | | +| `'verifySignupShort'` | - `value: { token: string, user: IdentifyUser }`
- `notifierOptions?: Record`| | +| `'options'` | - | | + +## CheckUniqueService + +check props are unique in the users items + +### create + +`app.service('authManagement/check-unique').create(data)` + +#### data properties: +- `value: IdentifyUser` - the users properties for checking uniqueness +- `ownId?: Id` - the id of the requesting user +- `meta?: object` + - `noErrMsg?: boolean` + +#### result: +if is unique: `Promise` otherwise rejects with `BadRequest` + +## IdentityChangeService + +change identity + +### create + +`app.service('authManagement/identity-change').create(data)` + +#### data properties: +- `value: object` + - `changes: Record` - `user.verifyChanges` gets updated by this + - `password: string` - the password of the user + - `user: IdentifyUser` - the users properties to search for +- `notifierOptions?: Record` + +#### result: +`Promise` + +## PasswordChangeService + +change password + +### create + +`app.service('authManagement/password-change').create(data)` + +#### data properties: +- `value: object` + - `oldPassword: string` - the currently valid password + - `password: string` - the new password to set + - `user: IdentifyUser` - the users properties to search for +- `notifierOptions?: Record` + +#### result: +`Promise` + +## ResendVerifySignupService + +resend sign up verification notification + +### create + +`app.service('authManagement/resend-verify-signup').create(data)` + +#### data properties: +- `value: IdentifyUser` - the users properties to search for +- `notifierOptions?: Record` + +#### result: +`Promise` + +## ResetPwdLongService + +forgotten password verification with long token + +### create + +`app.service('authManagement/reset-password-long').create(data)` + +#### data properties: +- `value: object` + - `password: string` + - `token: string` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## ResetPwdShortService + +forgotten password verification with short token + +### create + +`app.service('authManagement/reset-password-short').create(data)` + +#### data properties: +- `value: object` + - `password: string` + - `token: string` + - `user: IdentifyUser` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## SendResetPwdService + +send forgotten password notification + +### create + +`app.service('authManagement/send-reset-password').create(data)` + +#### data properties: +- `value: IdentifyUser` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## VerifySignupLongService + +sign up or identityChange verification with long token + +### create + +`app.service('authManagement/verify-signup-long').create(data)` + +#### data properties: +- `value: string` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## VerifySignupSetPasswordLongService + +sign up or identityChange verification with long token + +### create + +`app.service('authManagement/verify-signup-set-password-long').create(data)` + +#### data properties: +- `value: object` + - `password: string` + - `token: string` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## VerifySignupSetPasswordShortService + +sign up or identityChange verification with short token + +### create + +`app.service('authManagement/verify-signup-set-password-short').create(data)` + +#### data properties: +- `value: object` + - `password: string` + - `token: string` + - `user: IdentifyUser` +- `notifierOptions?: Record` + +#### result: +`Promise` + +## VerifySignupShort + +sign up or identityChange verification with short token + +### create + +`app.service('authManagement/verify-signup-short').create(data)` + +#### data properties: +- `value: object` + - `token: string` + - `user: IdentifyUser` +- `notifierOptions?: Record` + +#### result: +`Promise` diff --git a/examples/js/.editorconfig b/examples/js/.editorconfig new file mode 100644 index 0000000..e717f5e --- /dev/null +++ b/examples/js/.editorconfig @@ -0,0 +1,13 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/examples/js/.eslintrc.json b/examples/js/.eslintrc.json new file mode 100644 index 0000000..cbdf798 --- /dev/null +++ b/examples/js/.eslintrc.json @@ -0,0 +1,32 @@ +{ + "root": true, + "env": { + "es6": true, + "node": true, + "mocha": true + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "extends": [ + "eslint:recommended" + ], + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +} diff --git a/examples/js/.gitignore b/examples/js/.gitignore new file mode 100644 index 0000000..3da46cd --- /dev/null +++ b/examples/js/.gitignore @@ -0,0 +1,111 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Users Environment Variables +.lock-wscript + +# IDEs and editors (shamelessly copied from @angular/cli's .gitignore) +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.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 + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Others +lib/ +data/ diff --git a/examples/js/config/default.json b/examples/js/config/default.json new file mode 100644 index 0000000..da97348 --- /dev/null +++ b/examples/js/config/default.json @@ -0,0 +1,32 @@ +{ + "host": "localhost", + "port": 3030, + "public": "../public/", + "paginate": { + "default": 10, + "max": 50 + }, + "authentication": { + "entity": "user", + "service": "users", + "secret": "v66dnIEkEpMTRXgn5N4t/uN/VvI=", + "authStrategies": [ + "jwt", + "local" + ], + "jwtOptions": { + "header": { + "typ": "access" + }, + "audience": "https://yourdomain.com", + "issuer": "feathers", + "algorithm": "HS256", + "expiresIn": "1d" + }, + "local": { + "usernameField": "email", + "passwordField": "password" + } + }, + "postgres": "postgres://postgres:1@localhost:5432/js" +} diff --git a/examples/js/config/production.json b/examples/js/config/production.json new file mode 100644 index 0000000..da0fd2c --- /dev/null +++ b/examples/js/config/production.json @@ -0,0 +1,4 @@ +{ + "host": "js-app.feathersjs.com", + "port": "PORT" +} diff --git a/examples/js/config/test.json b/examples/js/config/test.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/examples/js/config/test.json @@ -0,0 +1 @@ +{} diff --git a/examples/js/package-lock.json b/examples/js/package-lock.json new file mode 100644 index 0000000..e36817f --- /dev/null +++ b/examples/js/package-lock.json @@ -0,0 +1,4024 @@ +{ + "name": "js", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", + "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "dev": true, + "requires": { + "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.20", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@feathers-plus/batch-loader": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.6.tgz", + "integrity": "sha512-r+n31iZ/B5Rl1mLkC9/S20UI445MdkZvE3VBmjupep2t8OuyTYHPkFEgR25HY6khH+RothK1VL3B5eumk9N2QQ==" + }, + "@feathersjs/adapter-commons": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-4.5.11.tgz", + "integrity": "sha512-qJ+P/6GLR3KfXhzgRkvl3p66YmaTxLO1js1Jzs+d5QnnUYx+jWSV7tzYVZoVjQSlF8ht/zh9N5qfh0RV9w1E+w==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11" + } + }, + "@feathersjs/authentication": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-4.5.11.tgz", + "integrity": "sha512-zLPbz+NIV6wYLstjZtLfozO7koJyzJTj+GyZYDsIK3N4GDhQc1mqWskuwWQtgeYZVpDdEsxPEohJ/7f576pFQQ==", + "requires": { + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "@feathersjs/transport-commons": "^4.5.11", + "@types/jsonwebtoken": "^8.5.0", + "debug": "^4.3.1", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.20", + "long-timeout": "^0.1.1", + "uuid": "^8.3.1" + } + }, + "@feathersjs/authentication-local": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-4.5.11.tgz", + "integrity": "sha512-oz8WRzk1gugO8qA1JIoVPIkPJklEq1h5DnU8dsYWMoImsgqfAsSaV4+RulIxNwCDIb6V0Xs5waTu+b53f2rGnA==", + "requires": { + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "bcryptjs": "^2.4.3", + "debug": "^4.3.1", + "lodash": "^4.17.20" + } + }, + "@feathersjs/authentication-oauth": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-oauth/-/authentication-oauth-4.5.11.tgz", + "integrity": "sha512-Ok2OHu1IRGcTBGpPZJAldy5E9nHA5GCtMyojasowcrrrglxUbK7TLijz16IAuLZRLYdaZgivn3WyoLijCjOKhQ==", + "requires": { + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/express": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "debug": "^4.3.1", + "express-session": "^1.17.1", + "grant": "^4.7.0", + "grant-profile": "^0.0.11", + "lodash": "^4.17.20" + } + }, + "@feathersjs/commons": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-4.5.11.tgz", + "integrity": "sha512-it/9lc0OER36+2zidopWo6Z4xRqNImQ+qegyQdHEuIDpEsYLXAv6MVHuDccaW2x2UmW5pce75UB7DhQ8yh8J/Q==" + }, + "@feathersjs/configuration": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/configuration/-/configuration-4.5.11.tgz", + "integrity": "sha512-D9RKWIPmOzCOG6WqEbAEqCTEA2h71s6hxHEhxcJRobmEAqsEEkXAq275lcUNdzdp+XTdns3qZOC0Q9OrJ0r+gw==", + "requires": { + "@feathersjs/feathers": "^4.5.11", + "config": "^3.3.3", + "debug": "^4.3.1" + } + }, + "@feathersjs/errors": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-4.5.11.tgz", + "integrity": "sha512-KzkUqmaV7/SGK6SM/ILXjMI/EHOGKQE4GgDHCsB4+mcIwb8IZboeHL6IkYjh6MvwjKNDyS728McZvcflDGn/fA==", + "requires": { + "debug": "^4.3.1" + } + }, + "@feathersjs/express": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-4.5.11.tgz", + "integrity": "sha512-Z7Lq0QDfDgsBGRyWNaraYEZ/xu4F6Ccv1zusKtqZYK48YOXAvXVse04xWgDVD/MC0j3d6NDe2RklFeGvWtaBng==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@types/express": "^4.17.9", + "debug": "^4.3.1", + "express": "^4.17.1", + "lodash": "^4.17.20", + "uberproto": "^2.0.6" + } + }, + "@feathersjs/feathers": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-4.5.11.tgz", + "integrity": "sha512-13zorhzi9eOwAW+l3oT4K8+CGCljpd9yPkx1XOZZyG5J1RSENWpPhgJ5Oe+qWw6Iqk768UBYp3+W1hLCQa6t2g==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "debug": "^4.3.1", + "events": "^3.2.0", + "uberproto": "^2.0.6" + } + }, + "@feathersjs/socketio": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/socketio/-/socketio-4.5.11.tgz", + "integrity": "sha512-Qwcg9LU76CwS0r3Qqrs0JqlIy54aqJBLwxj9N+Pv6HsLxhc8C4KkyitKv2yYORi2Fz+QzXoVNzC9W4EuAbiynA==", + "requires": { + "@feathersjs/transport-commons": "^4.5.11", + "@types/socket.io": "^2.1.11", + "debug": "^4.3.1", + "socket.io": "^2.3.0", + "uberproto": "^2.0.6" + } + }, + "@feathersjs/transport-commons": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-4.5.11.tgz", + "integrity": "sha512-YuQZnHQWOnhDLggwcMHdWGfIwZ5xabZCQ9/g18Nx770SWYwYPSLyvvbwsxs52LVvHyXW7j1VojcNixdUrOnFHQ==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "debug": "^4.3.1", + "lodash": "^4.17.20", + "radix-router": "^3.0.1" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@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==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@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": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-DLVpLEGTEZGBXOYoYoagHSxXkDHONc0fZouF2ayw7Q18aRu1Afwci+1CFKvPpouCUOVWP+dmCaAWpQjswe7kpg==", + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", + "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz", + "integrity": "sha512-m4JTwx5RUBNZvky/JJ8swEJPKFd8si08pPF2PfizYjGZOKr/svUWPcoUmLow6MmPzhasphB7gSTINY67xn3JNA==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@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": { + "@types/node": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==" + }, + "@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/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/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/socket.io": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.13.tgz", + "integrity": "sha512-JRgH3nCgsWel4OPANkhH8TelpXvacAJ9VeryjuqCDiaVDMpLysd6sbt0dr6Z15pqH3p2YpOT3T1C5vQ+O/7uyg==", + "requires": { + "@types/engine.io": "*", + "@types/node": "*", + "@types/socket.io-parser": "*" + } + }, + "@types/socket.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/socket.io-parser/-/socket.io-parser-2.2.1.tgz", + "integrity": "sha512-+JNb+7N7tSINyXPxAJb62+NcpC1x/fPn7z818W4xeNCdPTp6VsO/X8fCsg6+ug4a56m1v9sEiTIIUKVupcHOFQ==", + "requires": { + "@types/node": "*" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "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 + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "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==", + "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" + } + } + } + }, + "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-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": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "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" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dev": true, + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "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=" + } + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "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" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.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" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "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" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "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" + }, + "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" + } + }, + "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" + } + } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "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" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz", + "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "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==" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "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=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "config": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.3.tgz", + "integrity": "sha512-T3RmZQEAji5KYqUQpziWtyGJFli6Khz7h0rpxDwYNjSkr5ynyTWwO7WpfjHzTXclNCDfSWQRcwMb+NwxJesCKw==", + "requires": { + "json5": "^2.1.1" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "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" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "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=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "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==", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "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" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", + "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "~7.4.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "engine.io-client": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz", + "integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==", + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "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" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "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==", + "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=", + "dev": true + }, + "eslint": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", + "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.3.0", + "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.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "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.20", + "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": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "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": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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": { + "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 + } + } + }, + "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 + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.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 + } + } + }, + "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 + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "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", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "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=" + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "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=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "express-session": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", + "integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "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" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "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==" + }, + "feathers-authentication-management": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/feathers-authentication-management/-/feathers-authentication-management-3.1.0.tgz", + "integrity": "sha512-XCzdzhOGeX8t6Vjpw/foVtMD9ha5chcXSA5c8UJbeAofPYIJtLa92RbcBo3KnnOZJVhO6FFxYo7HBNjOlhcWVA==", + "requires": { + "@feathersjs/authentication": "^4.3.0", + "@feathersjs/authentication-local": "^4.3.0", + "@feathersjs/errors": "^4.3.0", + "bcryptjs": "^2.3.0", + "debug": "^4.1.0", + "feathers-hooks-common": "^5.0.3" + } + }, + "feathers-hooks-common": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/feathers-hooks-common/-/feathers-hooks-common-5.0.5.tgz", + "integrity": "sha512-GOHZ6W/ioEK5uCs4bCh21P/oLObVqIkbQ6WTKZMscJlykDptH3KOIMiUpFscO6uLQcKKZHY7a1PabLNFP2J7tA==", + "requires": { + "@feathers-plus/batch-loader": "^0.3.6", + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "ajv": "^6.12.6", + "debug": "^4.3.1", + "graphql": "^15.5.0", + "lodash": "^4.17.20", + "process": "0.11.10", + "traverse": "^0.6.6" + } + }, + "feathers-mailer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/feathers-mailer/-/feathers-mailer-3.0.1.tgz", + "integrity": "sha512-IC78GDfW4df4fi6VYIzOIBkJgzm1CyDdJW8BN9tnPUjuygPkp17AS/w5ASY4WvgOczRJZKZgD0nZEa2V5JlL7A==", + "requires": { + "debug": "^3.1.0", + "nodemailer": "^4.4.2", + "uberproto": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "nodemailer": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", + "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" + } + } + }, + "feathers-sequelize": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/feathers-sequelize/-/feathers-sequelize-6.2.0.tgz", + "integrity": "sha512-TInQA/wXTReZFkf1WKKnkVhOE8FRFx3w/Hb0YrADijmu5tMwngaAHP/AP38TCTVgVn2VICVWKNb97TVnC5Dt0Q==", + "requires": { + "@feathersjs/adapter-commons": "^4.4.3", + "@feathersjs/commons": "^4.4.3", + "@feathersjs/errors": "^4.4.3" + } + }, + "fecha": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", + "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "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" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "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": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "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 + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "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==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + } + }, + "globals": { + "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" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "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" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "grant": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/grant/-/grant-4.7.0.tgz", + "integrity": "sha512-QGPjCYDrBnb/OIiTRxbK3TnNOE6Ycgfc/GcgPzI4vyNIr+b7yisEexYp7VM74zj6bxr+mDTzfGONRLzzsVPJIA==", + "requires": { + "qs": "^6.9.1", + "request-compose": "^1.2.1", + "request-oauth": "0.0.3" + }, + "dependencies": { + "qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + } + } + }, + "grant-profile": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/grant-profile/-/grant-profile-0.0.11.tgz", + "integrity": "sha512-gfSFCZC2zmwkWYQ3rb2J6JbINbgExQgkjssOMJrKg1nq9izjP0Yzj5F0HzQuRUMi84onAo7dQJN4ZDVYXzavhw==", + "requires": { + "qs": "^6.9.1", + "request-compose": "^1.2.1", + "request-oauth": "0.0.3" + }, + "dependencies": { + "qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + } + } + }, + "graphql": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.0.tgz", + "integrity": "sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "helmet": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.4.1.tgz", + "integrity": "sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw==" + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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 + }, + "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=", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, + "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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "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==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "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 + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "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==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "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==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "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==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "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 + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "levn": { + "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.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "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": { + "chalk": "^4.0.0" + } + }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, + "long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "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" + } + }, + "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" + }, + "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 + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.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==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mocha": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", + "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "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==", + "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 + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "moment": { + "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.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nodemailer": { + "version": "6.4.18", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.18.tgz", + "integrity": "sha512-ht9cXxQ+lTC+t00vkSIpKHIyM4aXIsQ1tcbQCn5IOnxYHi81W2XOaU66EQBFFpbtzLEBTC94gmkbD4mGZQzVpA==" + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "dev": true, + "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.3", + "update-notifier": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "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" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "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==", + "dev": true + } + } + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "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 + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "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=" + }, + "pg": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.2.tgz", + "integrity": "sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "0.1.3", + "pg-packet-stream": "^1.1.0", + "pg-pool": "^2.0.10", + "pg-types": "^2.1.0", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" + } + } + }, + "pg-connection-string": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", + "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-packet-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz", + "integrity": "sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg==" + }, + "pg-pool": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.10.tgz", + "integrity": "sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "prelude-ls": { + "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=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "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==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "radix-router": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/radix-router/-/radix-router-3.0.1.tgz", + "integrity": "sha512-jpHXHgP+ZmVzEfmZ7WVRSvc/EqMoAqYuMtBsHd9s47Hs9Iy8FDJhkweMrDH0wmdxanLzVIWhq0UpomLXNpW8tg==" + }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, + "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" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "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=", + "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==", + "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" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "readdirp": { + "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": { + "picomatch": "^2.2.1" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "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==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "request-compose": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/request-compose/-/request-compose-1.2.3.tgz", + "integrity": "sha512-i2m8y3kEveoaAVTsTqig2LmWI10bUdakqzIVHkTEAK8kcsr4a/+iL93tsujsLaMiCZmnB1Osdk3WEMsB//H66A==" + }, + "request-oauth": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/request-oauth/-/request-oauth-0.0.3.tgz", + "integrity": "sha512-q7WdJlpIcPaIDac0FZSy/yH37FO3UkUuPDIsiLALiLjuC6vzvuKIU14YIC3Lm0wtQRXS9GqvSo/fCYj8n75xSw==", + "requires": { + "oauth-sign": "^0.8.2", + "qs": "^6.5.1", + "uuid": "^3.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "requires": { + "any-promise": "^1.3.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.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 + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "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", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "sequelize": { + "version": "5.22.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.22.3.tgz", + "integrity": "sha512-+nxf4TzdrB+PRmoWhR05TP9ukLAurK7qtKcIFv5Vhxm5Z9v+d2PcTT6Ea3YAoIQVkZ47QlT9XWAIUevMT/3l8Q==", + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.24.0", + "moment-timezone": "^0.5.21", + "retry-as-promised": "^3.2.0", + "semver": "^6.3.0", + "sequelize-pool": "^2.3.0", + "toposort-class": "^1.0.1", + "uuid": "^3.3.3", + "validator": "^10.11.0", + "wkx": "^0.4.8" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "sequelize-pool": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", + "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==" + }, + "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": { + "randombytes": "^2.1.0" + } + }, + "serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", + "requires": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.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" + } + }, + "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 + } + } + }, + "socket.io": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", + "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", + "requires": { + "debug": "~4.1.0", + "engine.io": "~3.5.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.4.0", + "socket.io-parser": "~3.4.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" + }, + "socket.io-client": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "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" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "socket.io-parser": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", + "requires": { + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + } + } + }, + "socket.io-parser": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", + "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + }, + "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" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.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" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "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 + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "dev": true, + "requires": { + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ajv": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "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 + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "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==", + "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" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "type-check": { + "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.2.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==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "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" + } + }, + "uberproto": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.6.tgz", + "integrity": "sha512-68H97HffZoFaa3HFtpstahWorN9dSp5uTU6jo3GjIQ6JkJBR3hC2Nx/e/HFOoYHdUyT/Z1MRWfxN1EiQJZUyCQ==" + }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "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==", + "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" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "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=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "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 + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "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=", + "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": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "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" + } + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + } + }, + "wkx": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", + "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", + "requires": { + "@types/node": "*" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.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" + } + }, + "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 + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "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", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", + "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==" + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/examples/js/package.json b/examples/js/package.json new file mode 100644 index 0000000..450bf11 --- /dev/null +++ b/examples/js/package.json @@ -0,0 +1,69 @@ +{ + "name": "js", + "description": "", + "version": "0.0.0", + "homepage": "", + "private": true, + "main": "src", + "keywords": [ + "feathers" + ], + "author": { + "name": "Fratzinger", + "email": "22286818+fratzinger@users.noreply.github.com" + }, + "contributors": [], + "bugs": {}, + "directories": { + "lib": "src", + "test": "test/", + "config": "config/" + }, + "engines": { + "node": "^12.0.0", + "npm": ">= 3.0.0" + }, + "scripts": { + "test": "npm run lint && npm run mocha", + "lint": "eslint src/. test/. --config .eslintrc.json --fix", + "dev": "nodemon src/", + "start": "node src/", + "mocha": "mocha test/ --recursive --exit" + }, + "standard": { + "env": [ + "mocha" + ], + "ignore": [] + }, + "dependencies": { + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/authentication-local": "^4.5.11", + "@feathersjs/authentication-oauth": "^4.5.11", + "@feathersjs/configuration": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/express": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "@feathersjs/socketio": "^4.5.11", + "@feathersjs/transport-commons": "^4.5.11", + "compression": "^1.7.4", + "cors": "^2.8.5", + "feathers-authentication-management": "^3.1.0", + "feathers-hooks-common": "^5.0.5", + "feathers-mailer": "^3.0.1", + "feathers-sequelize": "^6.2.0", + "helmet": "^4.4.1", + "lodash": "^4.17.21", + "nodemailer": "^6.4.18", + "pg": "^7.18.2", + "sequelize": "^5.22.3", + "serve-favicon": "^2.5.0", + "winston": "^3.3.3" + }, + "devDependencies": { + "axios": "^0.21.1", + "eslint": "^7.20.0", + "mocha": "^8.3.0", + "nodemon": "^2.0.7" + } +} diff --git a/examples/js/public/authmgmt.html b/examples/js/public/authmgmt.html new file mode 100644 index 0000000..14159e5 --- /dev/null +++ b/examples/js/public/authmgmt.html @@ -0,0 +1,30 @@ + + +

+ Sending token +

+ + + diff --git a/examples/js/public/favicon.ico b/examples/js/public/favicon.ico new file mode 100644 index 0000000..7ed25a6 Binary files /dev/null and b/examples/js/public/favicon.ico differ diff --git a/examples/js/public/index.html b/examples/js/public/index.html new file mode 100644 index 0000000..73128e5 --- /dev/null +++ b/examples/js/public/index.html @@ -0,0 +1,75 @@ + + + + A FeathersJS application + + + + + +
+ + + +
+ + diff --git a/examples/js/src/app.hooks.js b/examples/js/src/app.hooks.js new file mode 100644 index 0000000..8392578 --- /dev/null +++ b/examples/js/src/app.hooks.js @@ -0,0 +1,33 @@ +// Application hooks that run for every service + +module.exports = { + before: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + + after: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +}; diff --git a/examples/js/src/app.js b/examples/js/src/app.js new file mode 100644 index 0000000..105b316 --- /dev/null +++ b/examples/js/src/app.js @@ -0,0 +1,59 @@ +const path = require('path'); +const favicon = require('serve-favicon'); +const compress = require('compression'); +const helmet = require('helmet'); +const cors = require('cors'); +const logger = require('./logger'); + +const feathers = require('@feathersjs/feathers'); +const configuration = require('@feathersjs/configuration'); +const express = require('@feathersjs/express'); +const socketio = require('@feathersjs/socketio'); + + +const middleware = require('./middleware'); +const services = require('./services'); +const appHooks = require('./app.hooks'); +const channels = require('./channels'); + +const authentication = require('./authentication'); + +const sequelize = require('./sequelize'); + +const app = express(feathers()); + +// Load app configuration +app.configure(configuration()); +// Enable security, CORS, compression, favicon and body parsing +app.use(helmet({ + contentSecurityPolicy: false +})); +app.use(cors()); +app.use(compress()); +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); +app.use(favicon(path.join(app.get('public'), 'favicon.ico'))); +// Host the public folder +app.use('/', express.static(app.get('public'))); + +// Set up Plugins and providers +app.configure(express.rest()); +app.configure(socketio()); + +app.configure(sequelize); + +// Configure other middleware (see `middleware/index.js`) +app.configure(middleware); +app.configure(authentication); +// Set up our services (see `services/index.js`) +app.configure(services); +// Set up event channels (see channels.js) +app.configure(channels); + +// Configure a middleware for 404s and the error handler +app.use(express.notFound()); +app.use(express.errorHandler({ logger })); + +app.hooks(appHooks); + +module.exports = app; diff --git a/examples/js/src/authentication.js b/examples/js/src/authentication.js new file mode 100644 index 0000000..3936187 --- /dev/null +++ b/examples/js/src/authentication.js @@ -0,0 +1,13 @@ +const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication'); +const { LocalStrategy } = require('@feathersjs/authentication-local'); +const { expressOauth } = require('@feathersjs/authentication-oauth'); + +module.exports = app => { + const authentication = new AuthenticationService(app); + + authentication.register('jwt', new JWTStrategy()); + authentication.register('local', new LocalStrategy()); + + app.use('/authentication', authentication); + app.configure(expressOauth()); +}; diff --git a/examples/js/src/channels.js b/examples/js/src/channels.js new file mode 100644 index 0000000..f8eec54 --- /dev/null +++ b/examples/js/src/channels.js @@ -0,0 +1,61 @@ +module.exports = function(app) { + if(typeof app.channel !== 'function') { + // If no real-time functionality has been configured just return + return; + } + + app.on('connection', connection => { + // On a new real-time connection, add it to the anonymous channel + app.channel('anonymous').join(connection); + }); + + app.on('login', (authResult, { connection }) => { + // connection can be undefined if there is no + // real-time connection, e.g. when logging in via REST + if(connection) { + // Obtain the logged in user from the connection + // const user = connection.user; + + // The connection is no longer anonymous, remove it + app.channel('anonymous').leave(connection); + + // Add it to the authenticated user channel + app.channel('authenticated').join(connection); + + // Channels can be named anything and joined on any condition + + // E.g. to send real-time events only to admins use + // if(user.isAdmin) { app.channel('admins').join(connection); } + + // If the user has joined e.g. chat rooms + // if(Array.isArray(user.rooms)) user.rooms.forEach(room => app.channel(`rooms/${room.id}`).join(connection)); + + // Easily organize users by email and userid for things like messaging + // app.channel(`emails/${user.email}`).join(connection); + // app.channel(`userIds/${user.id}`).join(connection); + } + }); + + // eslint-disable-next-line no-unused-vars + app.publish((data, hook) => { + // Here you can add event publishers to channels set up in `channels.js` + // To publish only for a specific event use `app.publish(eventname, () => {})` + + console.log('Publishing all events to all authenticated users. See `channels.js` and https://docs.feathersjs.com/api/channels.html for more information.'); // eslint-disable-line + + // e.g. to publish all service events to all authenticated users use + return app.channel('authenticated'); + }); + + // Here you can also add service specific event publishers + // e.g. the publish the `users` service `created` event to the `admins` channel + // app.service('users').publish('created', () => app.channel('admins')); + + // With the userid and email organization from above you can easily select involved users + // app.service('messages').publish(() => { + // return [ + // app.channel(`userIds/${data.createdBy}`), + // app.channel(`emails/${data.recipientEmail}`) + // ]; + // }); +}; diff --git a/examples/js/src/index.js b/examples/js/src/index.js new file mode 100644 index 0000000..d68605b --- /dev/null +++ b/examples/js/src/index.js @@ -0,0 +1,13 @@ +/* eslint-disable no-console */ +const logger = require('./logger'); +const app = require('./app'); +const port = app.get('port'); +const server = app.listen(port); + +process.on('unhandledRejection', (reason, p) => + logger.error('Unhandled Rejection at: Promise ', p, reason) +); + +server.on('listening', () => + logger.info('Feathers application started on http://%s:%d', app.get('host'), port) +); diff --git a/examples/js/src/logger.js b/examples/js/src/logger.js new file mode 100644 index 0000000..b9aba0d --- /dev/null +++ b/examples/js/src/logger.js @@ -0,0 +1,16 @@ +const { createLogger, format, transports } = require('winston'); + +// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston +const logger = createLogger({ + // To see more detailed errors, change this to 'debug' + level: 'info', + format: format.combine( + format.splat(), + format.simple() + ), + transports: [ + new transports.Console() + ], +}); + +module.exports = logger; diff --git a/examples/js/src/middleware/index.js b/examples/js/src/middleware/index.js new file mode 100644 index 0000000..49ad533 --- /dev/null +++ b/examples/js/src/middleware/index.js @@ -0,0 +1,5 @@ +// eslint-disable-next-line no-unused-vars +module.exports = function (app) { + // Add your custom middleware here. Remember that + // in Express, the order matters. +}; diff --git a/examples/js/src/sequelize.js b/examples/js/src/sequelize.js new file mode 100644 index 0000000..a827f88 --- /dev/null +++ b/examples/js/src/sequelize.js @@ -0,0 +1,32 @@ +const Sequelize = require('sequelize'); + +module.exports = function (app) { + const connectionString = app.get('postgres'); + const sequelize = new Sequelize(connectionString, { + dialect: 'postgres', + logging: false, + define: { + freezeTableName: true + } + }); + const oldSetup = app.setup; + + app.set('sequelizeClient', sequelize); + + app.setup = function (...args) { + const result = oldSetup.apply(this, args); + + // Set up data relationships + const models = sequelize.models; + Object.keys(models).forEach(name => { + if ('associate' in models[name]) { + models[name].associate(models); + } + }); + + // Sync to the database + app.set('sequelizeSync', sequelize.sync()); + + return result; + }; +}; diff --git a/examples/js/src/services/auth-management/auth-management.class.js b/examples/js/src/services/auth-management/auth-management.class.js new file mode 100644 index 0000000..21e95fc --- /dev/null +++ b/examples/js/src/services/auth-management/auth-management.class.js @@ -0,0 +1,6 @@ +const { AuthenticationManagementService } = require('../../../../../dist').services; +// const { AuthenticationManagementService } = require('feathers-authentication-management').services; + +exports.AuthManagement = class AuthManagement extends AuthenticationManagementService { + +}; diff --git a/examples/js/src/services/auth-management/auth-management.hooks.js b/examples/js/src/services/auth-management/auth-management.hooks.js new file mode 100644 index 0000000..5b8e069 --- /dev/null +++ b/examples/js/src/services/auth-management/auth-management.hooks.js @@ -0,0 +1,41 @@ +const { authenticate } = require('@feathersjs/authentication').hooks; +const { iff } = require('feathers-hooks-common'); + +const isAction = (...args) => (hook) => args.includes(hook.data.action); + +module.exports = { + before: { + all: [], + find: [], + get: [], + create: [ + // The user must be signed in before being allowed to change their password or communication values. + iff(isAction('passwordChange', 'identityChange'), + authenticate('jwt') + ) + ], + update: [], + patch: [], + remove: [] + }, + + after: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +}; diff --git a/examples/js/src/services/auth-management/auth-management.service.js b/examples/js/src/services/auth-management/auth-management.service.js new file mode 100644 index 0000000..1bd661a --- /dev/null +++ b/examples/js/src/services/auth-management/auth-management.service.js @@ -0,0 +1,38 @@ +// Initializes the `auth-management` service on path `/auth-management` +const { AuthManagement } = require('./auth-management.class'); +const hooks = require('./auth-management.hooks'); + +const { + makeNotifier, + sanitizeUserForClient +} = require('./auth-management.utils'); + +module.exports = function (app) { + const notifier = makeNotifier(app); + + // these are the available options for feathers-authentication-management + const options = { + app, // <- this one is required. The following are optional + service: '/users', + notifier, + longTokenLen: 15, // token's length will be twice this + shortTokenLen: 6, + shortTokenDigits: true, + resetDelay: 1000 * 60 * 60 * 2, // 2 hours + delay: 1000 * 60 * 60 * 24 * 5, // 5 days + resetAttempts: 0, + reuseResetToken: false, + identifyUserProps: ['email'], + sanitizeUserForClient, + skipIsVerifiedCheck: false, + passwordField: 'password' + }; + + // Initialize our service with any options it requires + app.use('/auth-management', new AuthManagement(options, app)); + + // Get our initialized service so that we can register hooks + const service = app.service('auth-management'); + + service.hooks(hooks); +}; diff --git a/examples/js/src/services/auth-management/auth-management.utils.js b/examples/js/src/services/auth-management/auth-management.utils.js new file mode 100644 index 0000000..18eef26 --- /dev/null +++ b/examples/js/src/services/auth-management/auth-management.utils.js @@ -0,0 +1,80 @@ +const _cloneDeep = require('lodash/cloneDeep'); + +function sanitizeUserForClient (user) { + user = _cloneDeep(user); + + delete user.password; + delete user.verifyExpires; + delete user.verifyToken; + delete user.verifyShortToken; + delete user.verifyChanges; + delete user.resetExpires; + delete user.resetToken; + delete user.resetShortToken; + + return user; +} + +exports.sanitizeUserForClient = sanitizeUserForClient; + +function makeNotifier(app) { + function getLink(action, hash) { + const url = new URL('http://localhost:3030/'); + url.pathname = '/authmgmt.html'; + url.searchParams.append('action', action); + url.searchParams.append('token', hash); + return url.toString(); + } + + async function sendEmail(email) { + return await app.service('mailer').create(email).then(function (result) { + console.log('Sent email', result); + }).catch(err => { + console.log('Error sending email', err); + }); + } + + // eslint-disable-next-line no-unused-vars + return async function(type, user, notifierOptions) { + if (type === 'resendVerifySignup') { + const tokenLink = getLink('verify', user.verifyToken); + return await sendEmail({ + to: user.email, + subject: 'Verify Signup', + html: tokenLink + }); + } else if (type === 'verifySignup') { + const tokenLink = getLink('verify', user.verifyToken); + return await sendEmail({ + to: user.email, + subject: 'Confirm Signup', + html: tokenLink + }); + } else if (type === 'sendResetPwd') { + const tokenLink = getLink('reset', user.resetToken); + return await sendEmail({ + to: user.email, + subject: 'Send Reset Password', + html: tokenLink + }); + } else if (type === 'resetPwd') { + const tokenLink = getLink('reset', user.resetToken); + return await sendEmail({ + to: user.email, + subject: 'Reset Password', + html: tokenLink + }); + } else if (type === 'passwordChange') { + return await sendEmail({}); + } else if (type === 'identityChange') { + const tokenLink = getLink('verifyChanges', user.verifyToken); + return await sendEmail({ + to: user.email, + subject: 'Change your identity', + html: tokenLink + }); + } + }; +} + +exports.makeNotifier = makeNotifier; diff --git a/examples/js/src/services/index.js b/examples/js/src/services/index.js new file mode 100644 index 0000000..101cfd6 --- /dev/null +++ b/examples/js/src/services/index.js @@ -0,0 +1,10 @@ +const users = require('./users/users.service.js'); +const mailer = require('./mailer/mailer.service.js'); +const authManagement = require('./auth-management/auth-management.service.js'); + +// eslint-disable-next-line no-unused-vars +module.exports = function (app) { + app.configure(users); + app.configure(mailer); + app.configure(authManagement); +}; diff --git a/examples/js/src/services/mailer/mailer.class.js b/examples/js/src/services/mailer/mailer.class.js new file mode 100644 index 0000000..1bfa97d --- /dev/null +++ b/examples/js/src/services/mailer/mailer.class.js @@ -0,0 +1,9 @@ +const { Service } = require('feathers-mailer'); + +class Mailer extends Service { + constructor(transport, defaults) { + super(transport, defaults); + } +} + +exports.Mailer = Mailer; diff --git a/examples/js/src/services/mailer/mailer.hooks.js b/examples/js/src/services/mailer/mailer.hooks.js new file mode 100644 index 0000000..5179199 --- /dev/null +++ b/examples/js/src/services/mailer/mailer.hooks.js @@ -0,0 +1,35 @@ +const { disallow } = require('feathers-hooks-common'); + +module.exports = { + before: { + all: [ + disallow('external') + ], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + + after: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +}; diff --git a/examples/js/src/services/mailer/mailer.service.js b/examples/js/src/services/mailer/mailer.service.js new file mode 100644 index 0000000..3571106 --- /dev/null +++ b/examples/js/src/services/mailer/mailer.service.js @@ -0,0 +1,33 @@ +// Initializes the `mailer` service on path `/mailer` +const { Mailer } = require('./mailer.class'); +const hooks = require('./mailer.hooks'); +const nodemailer = require('nodemailer'); +// see https://github.com/feathersjs-ecosystem/feathers-mailer + +module.exports = async function (app) { + const account = await nodemailer.createTestAccount(); // internet required + + const transporter = { + host: account.smtp.host, + port: account.smtp.port, + secure: account.smtp.secure, // 487 only + requireTLS: true, + auth: { + user: account.user, // generated ethereal user + pass: account.pass // generated ethereal password + } + }; + + + // Initialize our service with any options it requires + app.use('/mailer', new Mailer(transporter, { from: account.user })); + + // Get our initialized service so that we can register hooks + const service = app.service('mailer'); + + service.hooks(hooks); + + service.hooks({ after: { create: (context) => { + console.log(nodemailer.getTestMessageUrl(context.result)); + }}}); +}; diff --git a/examples/js/src/services/users/users.class.js b/examples/js/src/services/users/users.class.js new file mode 100644 index 0000000..2cd34ea --- /dev/null +++ b/examples/js/src/services/users/users.class.js @@ -0,0 +1,6 @@ +const { Service } = require('feathers-sequelize'); +//const { Service } = require('feathers-mongoose'); + +exports.Users = class Users extends Service { + +}; diff --git a/examples/js/src/services/users/users.hooks.js b/examples/js/src/services/users/users.hooks.js new file mode 100644 index 0000000..d06e596 --- /dev/null +++ b/examples/js/src/services/users/users.hooks.js @@ -0,0 +1,91 @@ +const { authenticate } = require('@feathersjs/authentication').hooks; +const { hashPassword, protect } = require('@feathersjs/authentication-local').hooks; +const { addVerification, removeVerification } = require('feathers-authentication-management').hooks; + +const { + checkContext, + disallow, + iff, + isProvider, + preventChanges, + getItems +} = require('feathers-hooks-common'); + +const { makeNotifier } = require('../auth-management/auth-management.utils'); + +const sendVerifySignup = () => { + return async context => { + checkContext(context, 'after', 'create'); + let users = getItems(context); + users = (Array.isArray(users)) ? users : [users]; + const notify = makeNotifier(context.app); + const promises = users.map(user => notify( + 'resendVerifySignup', + user + )); + await Promise.all(promises); + }; +}; + +module.exports = { + before: { + all: [], + find: [ authenticate('jwt') ], + get: [ authenticate('jwt') ], + create: [ + hashPassword('password'), + addVerification(), // adds .isVerified, .verifyExpires, .verifyToken, .verifyChanges + ], + update: [ + disallow('external'), + authenticate('jwt'), + hashPassword('password') + ], + patch: [ + authenticate('jwt'), + iff( + isProvider('external'), + preventChanges( + false, + 'email', + 'isVerified', + 'verifyToken', + 'verifyShortToken', + 'verifyExpires', + 'verifyChanges', + 'resetToken', + 'resetShortToken', + 'resetExpires' + ), + hashPassword('password'), + ) + ], + remove: [ + authenticate('jwt'), + hashPassword('password') + ] + }, + after: { + all: [ + protect('password'), + removeVerification() // removes verification/reset fields other than .isVerified from the response + ], + find: [], + get: [], + create: [ + sendVerifySignup() + ], + update: [], + patch: [], + remove: [] + }, + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +}; diff --git a/examples/js/src/services/users/users.model.js b/examples/js/src/services/users/users.model.js new file mode 100644 index 0000000..52b2997 --- /dev/null +++ b/examples/js/src/services/users/users.model.js @@ -0,0 +1,63 @@ +// See http://docs.sequelizejs.com/en/latest/docs/models-definition/ +// for more of what you can do here. +const Sequelize = require('sequelize'); +const DataTypes = Sequelize.DataTypes; + +module.exports = function (app) { + const sequelizeClient = app.get('sequelizeClient'); + const users = sequelizeClient.define('users', { + email: { + type: DataTypes.STRING, + allowNull: false, + unique: true + }, + password: { + type: DataTypes.STRING, + allowNull: false + }, + isVerified: { + type: DataTypes.BOOLEAN + }, + verifyToken: { + type: DataTypes.STRING + }, + verifyShortToken: { + type: DataTypes.STRING + }, + verifyExpires: { + type: DataTypes.DATE + }, + verifyChanges: { + type: DataTypes.ARRAY(DataTypes.STRING) + }, + resetToken: { + type: DataTypes.STRING + }, + resetShortToken: { + type: DataTypes.STRING + }, + resetExpires: { + type: DataTypes.DATE + }, + resetAttempts: { + type: DataTypes.NUMBER + }, + preferredComm: { + type: DataTypes.STRING + } + }, { + hooks: { + beforeCount(options) { + options.raw = true; + } + } + }); + + // eslint-disable-next-line no-unused-vars + users.associate = function (models) { + // Define associations here + // See http://docs.sequelizejs.com/en/latest/docs/associations/ + }; + + return users; +}; diff --git a/examples/js/src/services/users/users.service.js b/examples/js/src/services/users/users.service.js new file mode 100644 index 0000000..aa66c33 --- /dev/null +++ b/examples/js/src/services/users/users.service.js @@ -0,0 +1,19 @@ +// Initializes the `users` service on path `/users` +const { Users } = require('./users.class'); +const createModel = require('./users.model'); +const hooks = require('./users.hooks'); + +module.exports = function (app) { + const options = { + Model: createModel(app), + paginate: app.get('paginate') + }; + + // Initialize our service with any options it requires + app.use('/users', new Users(options, app)); + + // Get our initialized service so that we can register hooks + const service = app.service('users'); + + service.hooks(hooks); +}; diff --git a/examples/js/test/app.test.js b/examples/js/test/app.test.js new file mode 100644 index 0000000..03ed0f9 --- /dev/null +++ b/examples/js/test/app.test.js @@ -0,0 +1,65 @@ +const assert = require('assert').strict; +const axios = require('axios'); +const url = require('url'); +const app = require('../src/app'); + +const port = app.get('port') || 8998; +const getUrl = pathname => url.format({ + hostname: app.get('host') || 'localhost', + protocol: 'http', + port, + pathname +}); + +describe('Feathers application tests', () => { + let server; + + before(function(done) { + server = app.listen(port); + server.once('listening', () => done()); + }); + + after(function(done) { + server.close(done); + }); + + it('starts and shows the index page', async () => { + const { data } = await axios.get(getUrl()); + + assert.ok(data.indexOf('') !== -1); + }); + + describe('404', function() { + it('shows a 404 HTML page', async () => { + try { + await axios.get(getUrl('path/to/nowhere'), { + headers: { + 'Accept': 'text/html' + } + }); + assert.fail('should never get here'); + } catch (error) { + const { response } = error; + + assert.equal(response.status, 404); + assert.ok(response.data.indexOf('') !== -1); + } + }); + + it('shows a 404 JSON error without stack trace', async () => { + try { + await axios.get(getUrl('path/to/nowhere'), { + json: true + }); + assert.fail('should never get here'); + } catch (error) { + const { response } = error; + + assert.equal(response.status, 404); + assert.equal(response.data.code, 404); + assert.equal(response.data.message, 'Page not found'); + assert.equal(response.data.name, 'NotFound'); + } + }); + }); +}); diff --git a/examples/js/test/authentication.test.js b/examples/js/test/authentication.test.js new file mode 100644 index 0000000..c42b3cc --- /dev/null +++ b/examples/js/test/authentication.test.js @@ -0,0 +1,33 @@ +const assert = require('assert'); +const app = require('../src/app'); + +describe('authentication', () => { + it('registered the authentication service', () => { + assert.ok(app.service('authentication')); + }); + + describe('local strategy', () => { + const userInfo = { + email: 'someone@example.com', + password: 'supersecret' + }; + + before(async () => { + try { + await app.service('users').create(userInfo); + } catch (error) { + // Do nothing, it just means the user already exists and can be tested + } + }); + + it('authenticates user and creates accessToken', async () => { + const { user, accessToken } = await app.service('authentication').create({ + strategy: 'local', + ...userInfo + }); + + assert.ok(accessToken, 'Created access token for user'); + assert.ok(user, 'Includes user in authentication data'); + }); + }); +}); diff --git a/examples/js/test/services/auth-management.test.js b/examples/js/test/services/auth-management.test.js new file mode 100644 index 0000000..cb43e33 --- /dev/null +++ b/examples/js/test/services/auth-management.test.js @@ -0,0 +1,10 @@ +const assert = require('assert'); +const app = require('../../src/app'); + +describe('\'auth-management\' service', () => { + it('registered the service', () => { + const service = app.service('auth-management'); + + assert.ok(service, 'Registered the service'); + }); +}); diff --git a/examples/js/test/services/mailer.test.js b/examples/js/test/services/mailer.test.js new file mode 100644 index 0000000..0db6c9c --- /dev/null +++ b/examples/js/test/services/mailer.test.js @@ -0,0 +1,10 @@ +const assert = require('assert'); +const app = require('../../src/app'); + +describe('\'mailer\' service', () => { + it('registered the service', () => { + const service = app.service('mailer'); + + assert.ok(service, 'Registered the service'); + }); +}); diff --git a/examples/js/test/services/users.test.js b/examples/js/test/services/users.test.js new file mode 100644 index 0000000..cc555e5 --- /dev/null +++ b/examples/js/test/services/users.test.js @@ -0,0 +1,10 @@ +const assert = require('assert'); +const app = require('../../src/app'); + +describe('\'users\' service', () => { + it('registered the service', () => { + const service = app.service('users'); + + assert.ok(service, 'Registered the service'); + }); +}); diff --git a/index.js b/index.js new file mode 100644 index 0000000..e69de29 diff --git a/mocha.opts b/mocha.opts deleted file mode 100755 index b8e24b1..0000000 --- a/mocha.opts +++ /dev/null @@ -1,3 +0,0 @@ ---timeout 40000 ---recursive test/ ---exit \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5b84932..3f5eaf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,212 +4,365 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@algolia/cache-browser-local-storage": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.9.0.tgz", + "integrity": "sha512-H659baxPygLp1ed5Y+kko9nLhhTRtZ6v2k2cs2/WTErAd6XU+OrvTvsEedUprDYUve/t9NLg95Ka9TK8QEQk1w==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.9.0" + } + }, + "@algolia/cache-common": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.9.0.tgz", + "integrity": "sha512-hBqkLEw1Y7oxEJEVmcdm/s/+KKlvCmSenlX5rrQts5qCNdhdS1QkCvHx8vgFF9J6uliP2TPs+umrrXc+aKsLPw==", + "dev": true + }, + "@algolia/cache-in-memory": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.9.0.tgz", + "integrity": "sha512-8q9z8tkIrgPenZl+aTc6MOQleLnanVy+Nsz7Uzga5r9Kb7xpqYKNI9rSJYyBzl7KRxock5v6AOUiFgi45eDnDg==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.9.0" + } + }, + "@algolia/client-account": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.9.0.tgz", + "integrity": "sha512-u9cljyqUnlgHIKazeOA2R820pDZFReRVm3AObiGrxhdKVQ44ZOgAlN+NIqA+c19iFdpulzpkPKxU+Uavcky7JQ==", + "dev": true, + "requires": { + "@algolia/client-common": "4.9.0", + "@algolia/client-search": "4.9.0", + "@algolia/transporter": "4.9.0" + } + }, + "@algolia/client-analytics": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.9.0.tgz", + "integrity": "sha512-5TafTR/uP9X4EpDOvBK1w4cgc3JpKeokPJqD37q46AH1IGI8UO5Gy1H5LxcGmPTIMdMnuSfiYgRJsyoEO1Co0A==", + "dev": true, + "requires": { + "@algolia/client-common": "4.9.0", + "@algolia/client-search": "4.9.0", + "@algolia/requester-common": "4.9.0", + "@algolia/transporter": "4.9.0" + } + }, + "@algolia/client-common": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.9.0.tgz", + "integrity": "sha512-Rjk4XMXi6B63jdKQwnGbKwIubB5QIgok+k67QwrgadbqVphHueJ3af3D6i3sRcKBBTmdprFAXn0zX/zaxYBhAQ==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.9.0", + "@algolia/transporter": "4.9.0" + } + }, + "@algolia/client-recommendation": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/client-recommendation/-/client-recommendation-4.9.0.tgz", + "integrity": "sha512-6y6uyQmmowuBqMkk4iLeBOkd1qtBpfGJ5/di0S041eHQlD0v9WxyhbZyOopn0XxopSLbQaO22u0rjEcla7KYlA==", + "dev": true, + "requires": { + "@algolia/client-common": "4.9.0", + "@algolia/requester-common": "4.9.0", + "@algolia/transporter": "4.9.0" + } + }, + "@algolia/client-search": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.9.0.tgz", + "integrity": "sha512-HFfeUJN6GPHsjfcchmksoqlBLF5gT+jRHmSait4fWtde85eGFyJVL7ubUZD9KjlEjzebmUPPIZ1ixcupaTUBnw==", + "dev": true, + "requires": { + "@algolia/client-common": "4.9.0", + "@algolia/requester-common": "4.9.0", + "@algolia/transporter": "4.9.0" + } + }, + "@algolia/logger-common": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.9.0.tgz", + "integrity": "sha512-OU8lzR1I8R0Qsgk+u4GOSFpEEKZkzPYZP1OXsw92gejW08k5N6kVLzfvVvgNA1KAeZPFXADdH26VBQ/2M9wF3g==", + "dev": true + }, + "@algolia/logger-console": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.9.0.tgz", + "integrity": "sha512-CrBU+E2iA4xXnb1rwX3G1ox9O+N+OjxnWccL75sWr1nQ/kh08TPpV7TYAvQEOFEDj8vV1kPeYEMENulbjmVZSA==", + "dev": true, + "requires": { + "@algolia/logger-common": "4.9.0" + } + }, + "@algolia/requester-browser-xhr": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.9.0.tgz", + "integrity": "sha512-KJESXTv4z+mDCn1C9b/azUqPTgIFVL/Y4+Eopz6YBg9Lj0C6KQrsW68w0uLJcGSw9o/qBoKcpUo4QNm4/CwrdQ==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.9.0" + } + }, + "@algolia/requester-common": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.9.0.tgz", + "integrity": "sha512-8/ljy4/pnB8d4/yTaJQa2t3oKdbsVq9nDXkwhCACVum8tGYSSGpCtpBGln6M4g+QdfBSQxYILTB1wwHLFUstmg==", + "dev": true + }, + "@algolia/requester-node-http": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.9.0.tgz", + "integrity": "sha512-JpkjPXDCgT+Z8G8d/6hxId7+560HeCHoiDcEFr9eWR/kClAOgVwgVH1I64pmH8ucsjL7kdWbkxez7zBzPiV+Tg==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.9.0" + } + }, + "@algolia/transporter": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.9.0.tgz", + "integrity": "sha512-GySLvXwg0DQ2LM0/W+hr9y1Co3QY1iNnhWA82gFhBrz7RWGzw47qEsh//9u/wnjl6S1WOjH+eKm5PaQATG1BXg==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.9.0", + "@algolia/logger-common": "4.9.0", + "@algolia/requester-common": "4.9.0" + } + }, + "@arr/every": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", + "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", + "dev": true + }, "@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", - "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@babel/highlight": "^7.10.1" + "@babel/highlight": "^7.10.4" } }, + "@babel/compat-data": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", + "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", + "dev": true + }, "@babel/core": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", - "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.2", - "@babel/helper-module-transforms": "^7.10.1", - "@babel/helpers": "^7.10.1", - "@babel/parser": "^7.10.2", - "@babel/template": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.2", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", + "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helpers": "^7.13.0", + "@babel/parser": "^7.13.4", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", + "lodash": "^4.17.19", + "semver": "^6.3.0", "source-map": "^0.5.0" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "dev": true, "requires": { - "ms": "^2.1.1" + "@babel/highlight": "^7.12.13" } }, - "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 + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/generator": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", - "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.0.tgz", + "integrity": "sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw==", "dev": true, "requires": { - "@babel/types": "^7.10.2", + "@babel/types": "^7.13.0", "jsesc": "^2.5.1", - "lodash": "^4.17.13", "source-map": "^0.5.0" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", + "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" }, "dependencies": { - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/helper-function-name": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", - "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/helper-get-function-arity": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", - "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", "dev": true, "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", - "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", + "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", "dev": true, "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.13.0" } }, "@babel/helper-module-imports": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", - "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", + "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", "dev": true, "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-module-transforms": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", - "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", + "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.10.1", - "@babel/helper-replace-supers": "^7.10.1", - "@babel/helper-simple-access": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1", - "lodash": "^4.17.13" + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", + "lodash": "^4.17.19" } }, "@babel/helper-optimise-call-expression": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", - "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", "dev": true, "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-replace-supers": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", - "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", + "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.1", - "@babel/helper-optimise-call-expression": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/helper-member-expression-to-functions": "^7.13.0", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/helper-simple-access": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", - "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", + "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", "dev": true, "requires": { - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-split-export-declaration": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", - "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", "dev": true, "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-validator-identifier": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", "dev": true }, "@babel/helpers": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", - "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", + "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", "dev": true, "requires": { - "@babel/template": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/highlight": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", - "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", + "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.1", + "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -220,71 +373,61 @@ "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, "@babel/parser": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", - "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "version": "7.13.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.4.tgz", + "integrity": "sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==", "dev": true }, "@babel/template": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", - "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + } } }, "@babel/traverse": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", - "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", + "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.1", - "@babel/helper-function-name": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1", + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.13.0", + "@babel/types": "^7.13.0", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.13" + "lodash": "^4.17.19" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "dev": true, "requires": { - "ms": "^2.1.1" + "@babel/highlight": "^7.12.13" } }, "globals": { @@ -292,30 +435,93 @@ "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/types": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", - "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", + "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "lodash": "^4.17.13", + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" + } + }, + "@docsearch/css": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-1.0.0-alpha.28.tgz", + "integrity": "sha512-1AhRzVdAkrWwhaxTX6/R7SnFHz8yLz1W8I/AldlTrfbNvZs9INk1FZiEFTJdgHaP68nhgQNWSGlQiDiI3y2RYg==", + "dev": true + }, + "@docsearch/js": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-1.0.0-alpha.28.tgz", + "integrity": "sha512-2g7aPhBy7FoEyeZW2G3LYHWVa8CFvqyozEz8PXt3hyywdFcmEIqmoCRwn8kboVftrOKCjtPcuLCewsaBoB3uiw==", + "dev": true, + "requires": { + "@docsearch/react": "^1.0.0-alpha.28", + "preact": "^10.0.0" + } + }, + "@docsearch/react": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-1.0.0-alpha.28.tgz", + "integrity": "sha512-XjJOnCBXn+UZmtuDmgzlVIHnnvh6yHVwG4aFq8AXN6xJEIX3f180FvGaowFWAxgdtHplJxFGux0Xx4piHqBzIw==", + "dev": true, + "requires": { + "@docsearch/css": "^1.0.0-alpha.28", + "@francoischalifour/autocomplete-core": "^1.0.0-alpha.28", + "@francoischalifour/autocomplete-preset-algolia": "^1.0.0-alpha.28", + "algoliasearch": "^4.0.0" }, "dependencies": { - "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=", + "algoliasearch": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.9.0.tgz", + "integrity": "sha512-hhlza8j/uCWGe2kSz89HlcexiLxO1wzOKLNPWivNtZeZO5J85agbcMsrKV5+xLFI4LbulP/b/4/IvswxzPrGIw==", + "dev": true, + "requires": { + "@algolia/cache-browser-local-storage": "4.9.0", + "@algolia/cache-common": "4.9.0", + "@algolia/cache-in-memory": "4.9.0", + "@algolia/client-account": "4.9.0", + "@algolia/client-analytics": "4.9.0", + "@algolia/client-common": "4.9.0", + "@algolia/client-recommendation": "4.9.0", + "@algolia/client-search": "4.9.0", + "@algolia/logger-common": "4.9.0", + "@algolia/logger-console": "4.9.0", + "@algolia/requester-browser-xhr": "4.9.0", + "@algolia/requester-common": "4.9.0", + "@algolia/requester-node-http": "4.9.0", + "@algolia/transporter": "4.9.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "dev": true, + "requires": { + "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", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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 } } @@ -326,159 +532,118 @@ "integrity": "sha512-r+n31iZ/B5Rl1mLkC9/S20UI445MdkZvE3VBmjupep2t8OuyTYHPkFEgR25HY6khH+RothK1VL3B5eumk9N2QQ==" }, "@feathersjs/adapter-commons": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-4.3.0.tgz", - "integrity": "sha512-eQ7N55cHZh0p0D4WI0qbulUi+nkRc3qshGAxqRU2oG+fPzuKXaeW2CANzuaJfU1rkJEn7gWruFCxh7mCz+QBVQ==", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-4.5.11.tgz", + "integrity": "sha512-qJ+P/6GLR3KfXhzgRkvl3p66YmaTxLO1js1Jzs+d5QnnUYx+jWSV7tzYVZoVjQSlF8ht/zh9N5qfh0RV9w1E+w==", "dev": true, "requires": { - "@feathersjs/commons": "^4.3.0", - "@feathersjs/errors": "^4.3.0", - "@feathersjs/feathers": "^4.3.0" + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11" } }, "@feathersjs/authentication": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-4.3.0.tgz", - "integrity": "sha512-/VMw04isM7XprZekRuxcFjQrubh43RNzMU8A4+3N19KisHCFd+WuGRBODxXHLkeLAnOldw3CtAY1xCvvFCHtaw==", - "requires": { - "@feathersjs/errors": "^4.3.0", - "@feathersjs/transport-commons": "^4.3.0", - "debug": "^4.1.1", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-4.5.11.tgz", + "integrity": "sha512-zLPbz+NIV6wYLstjZtLfozO7koJyzJTj+GyZYDsIK3N4GDhQc1mqWskuwWQtgeYZVpDdEsxPEohJ/7f576pFQQ==", + "requires": { + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "@feathersjs/transport-commons": "^4.5.11", + "@types/jsonwebtoken": "^8.5.0", + "debug": "^4.3.1", "jsonwebtoken": "^8.5.1", - "lodash": "^4.17.15", - "uuid": "^3.3.2" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "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==" - } + "lodash": "^4.17.20", + "long-timeout": "^0.1.1", + "uuid": "^8.3.1" + } + }, + "@feathersjs/authentication-client": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-client/-/authentication-client-4.5.11.tgz", + "integrity": "sha512-yONvXZb09eg4bBOPi6jDJZw/ANA7fsQwOlcf4M0feqFjsulFpsRlmEv77fzakMZtY7Nq6Ax5i2iqZP+zZr5hgA==", + "requires": { + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "debug": "^4.3.1" } }, "@feathersjs/authentication-local": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-4.3.0.tgz", - "integrity": "sha512-zmI21nohmQdsJi87nPec0wD/2U6Hxo4bpasVjbT1PMrXd1z95N8w/eL5kesfXxBMArFeZ1PBYA+AMgf0evSbHw==", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-4.5.11.tgz", + "integrity": "sha512-oz8WRzk1gugO8qA1JIoVPIkPJklEq1h5DnU8dsYWMoImsgqfAsSaV4+RulIxNwCDIb6V0Xs5waTu+b53f2rGnA==", "requires": { - "@feathersjs/errors": "^4.3.0", + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", "bcryptjs": "^2.4.3", - "debug": "^4.1.1", - "lodash": "^4.17.15" - }, - "dependencies": { - "bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "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==" - } + "debug": "^4.3.1", + "lodash": "^4.17.20" } }, "@feathersjs/commons": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-4.3.0.tgz", - "integrity": "sha512-N3CDavCNRp+usgyfDSFXCwETnp4nIEevl5v1nqULGhPYco0SjF15zu4hYyd3GCn0aAwzaIehYyaMcdee9Eo1KQ==" + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-4.5.11.tgz", + "integrity": "sha512-it/9lc0OER36+2zidopWo6Z4xRqNImQ+qegyQdHEuIDpEsYLXAv6MVHuDccaW2x2UmW5pce75UB7DhQ8yh8J/Q==" }, "@feathersjs/errors": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-4.3.0.tgz", - "integrity": "sha512-tOwBpJmLYy0Fq/Dp8Y3dO2/B6ojfqSrTFXixTYH2qBR3aFS/U0VzhoyEa1O+/FcJRDqgW54HNCyy520zqYB/pw==", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-4.5.11.tgz", + "integrity": "sha512-KzkUqmaV7/SGK6SM/ILXjMI/EHOGKQE4GgDHCsB4+mcIwb8IZboeHL6IkYjh6MvwjKNDyS728McZvcflDGn/fA==", "requires": { - "debug": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "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==" - } + "debug": "^4.3.1" } }, "@feathersjs/feathers": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-4.3.0.tgz", - "integrity": "sha512-iH/T8UGvv5gbDqHnU2Rlf5NZxqBmFvrl9BdNPNl2EYPGBvkfi/Dxp3+xJLyw8MZFbtgG+4fxP1KyFG1uGivGrA==", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-4.5.11.tgz", + "integrity": "sha512-13zorhzi9eOwAW+l3oT4K8+CGCljpd9yPkx1XOZZyG5J1RSENWpPhgJ5Oe+qWw6Iqk768UBYp3+W1hLCQa6t2g==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "debug": "^4.3.1", + "events": "^3.2.0", + "uberproto": "^2.0.6" + } + }, + "@feathersjs/socketio": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/socketio/-/socketio-4.5.11.tgz", + "integrity": "sha512-Qwcg9LU76CwS0r3Qqrs0JqlIy54aqJBLwxj9N+Pv6HsLxhc8C4KkyitKv2yYORi2Fz+QzXoVNzC9W4EuAbiynA==", "dev": true, "requires": { - "@feathersjs/commons": "^4.3.0", - "debug": "^4.1.1", - "events": "^3.0.0", - "uberproto": "^2.0.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "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==", - "dev": true - } + "@feathersjs/transport-commons": "^4.5.11", + "@types/socket.io": "^2.1.11", + "debug": "^4.3.1", + "socket.io": "^2.3.0", + "uberproto": "^2.0.6" } }, "@feathersjs/transport-commons": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-4.3.0.tgz", - "integrity": "sha512-dKz6aCkxolwmTQfsMR7geNFr19bGRiMNDB/Ij5KQcstRhBnOY4a5KAULObYccWzzWdnajRQ+OANY9o3AvKNP6w==", - "requires": { - "@feathersjs/commons": "^4.3.0", - "@feathersjs/errors": "^4.3.0", - "debug": "^4.1.1", - "lodash": "^4.17.15", + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-4.5.11.tgz", + "integrity": "sha512-YuQZnHQWOnhDLggwcMHdWGfIwZ5xabZCQ9/g18Nx770SWYwYPSLyvvbwsxs52LVvHyXW7j1VojcNixdUrOnFHQ==", + "requires": { + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "debug": "^4.3.1", + "lodash": "^4.17.20", "radix-router": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "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==" - } } }, + "@francoischalifour/autocomplete-core": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@francoischalifour/autocomplete-core/-/autocomplete-core-1.0.0-alpha.28.tgz", + "integrity": "sha512-rL9x+72btViw+9icfBKUJjZj87FgjFrD2esuTUqtj4RAX3s4AuVZiN8XEsfjQBSc6qJk31cxlvqZHC/BIyYXgg==", + "dev": true + }, + "@francoischalifour/autocomplete-preset-algolia": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@francoischalifour/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.28.tgz", + "integrity": "sha512-bprfNmYt1opFUFEtD2XfY/kEsm13bzHQgU80uMjhuK0DJ914IjolT1GytpkdM6tJ4MBvyiJPP+bTtWO+BZ7c7w==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -492,6 +657,12 @@ "resolve-from": "^5.0.0" }, "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -550,467 +721,903 @@ } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, + "@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", "dev": true }, - "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", "dev": true }, - "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "@types/chai": { + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.15.tgz", + "integrity": "sha512-rYff6FI+ZTKAPkJUoyz7Udq3GaoDZnxYDEvdEdFZASiA7PoErltHezDishqQiSDWrGxvxmplH304jyzQmjp0AQ==", "dev": true }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "@types/engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-DLVpLEGTEZGBXOYoYoagHSxXkDHONc0fZouF2ayw7Q18aRu1Afwci+1CFKvPpouCUOVWP+dmCaAWpQjswe7kpg==", "dev": true, "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } + "@types/node": "*" } }, - "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, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true }, - "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "@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": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@types/node": "*" } }, - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "@types/lodash": { + "version": "4.14.168", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", + "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", "dev": true }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "@types/mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-NysN+bNqj6E0Hv4CTGWSlPzMW6vTKjDpOteycDkV4IWBsO+PU48JonrPzV9ODjiI2XrjmA05KInLgF5ivZ/YGQ==", "dev": true }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==" }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "@types/socket.io": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.13.tgz", + "integrity": "sha512-JRgH3nCgsWel4OPANkhH8TelpXvacAJ9VeryjuqCDiaVDMpLysd6sbt0dr6Z15pqH3p2YpOT3T1C5vQ+O/7uyg==", + "dev": true, + "requires": { + "@types/engine.io": "*", + "@types/node": "*", + "@types/socket.io-parser": "*" + } }, - "ansi-styles": { + "@types/socket.io-parser": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "resolved": "https://registry.npmjs.org/@types/socket.io-parser/-/socket.io-parser-2.2.1.tgz", + "integrity": "sha512-+JNb+7N7tSINyXPxAJb62+NcpC1x/fPn7z818W4xeNCdPTp6VsO/X8fCsg6+ug4a56m1v9sEiTIIUKVupcHOFQ==", "dev": true, "requires": { - "default-require-extensions": "^1.0.0" + "@types/node": "*" } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "@typescript-eslint/eslint-plugin": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz", + "integrity": "sha512-uiQQeu9tWl3f1+oK0yoAv9lt/KXO24iafxgQTkIYO/kitruILGx3uH+QtIAHqxFV+yIsdnJH+alel9KuE3J15Q==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "@typescript-eslint/experimental-utils": "4.15.2", + "@typescript-eslint/scope-manager": "4.15.2", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "@typescript-eslint/experimental-utils": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.2.tgz", + "integrity": "sha512-Fxoshw8+R5X3/Vmqwsjc8nRO/7iTysRtDqx6rlfLZ7HbT8TZhPeQqbPjTyk2RheH3L8afumecTQnUc9EeXxohQ==", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.15.2", + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/typescript-estree": "4.15.2", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array.prototype.find": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", - "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "@typescript-eslint/parser": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.2.tgz", + "integrity": "sha512-SHeF8xbsC6z2FKXsaTb1tBCf0QZsjJ94H6Bo51Y1aVEZ4XAefaw5ZAilMoDPlGghe+qtq7XdTiDlGfVTOmvA+Q==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "@typescript-eslint/scope-manager": "4.15.2", + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/typescript-estree": "4.15.2", + "debug": "^4.1.1" } }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "babel-code-frame": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", - "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "@typescript-eslint/scope-manager": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.2.tgz", + "integrity": "sha512-Zm0tf/MSKuX6aeJmuXexgdVyxT9/oJJhaCkijv0DvJVT3ui4zY6XYd6iwIo/8GEZGy43cd7w1rFMiCLHbRzAPQ==", "dev": true, "requires": { - "chalk": "^1.1.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/visitor-keys": "4.15.2" } }, - "babel-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz", - "integrity": "sha1-5xX0hsWN7SVknYiJRNUqoHxdlJc=", + "@typescript-eslint/types": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.2.tgz", + "integrity": "sha512-r7lW7HFkAarfUylJ2tKndyO9njwSyoy6cpfDKWPX6/ctZA+QyaYscAHXVAfJqtnY6aaTwDYrOhp+ginlbc7HfQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.2.tgz", + "integrity": "sha512-cGR8C2g5SPtHTQvAymEODeqx90pJHadWsgTtx6GbnTWKqsg7yp6Eaya9nFzUd4KrKhxdYTTFBiYeTPQaz/l8bw==", "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.2.0", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/visitor-keys": "4.15.2", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "@typescript-eslint/visitor-keys": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.2.tgz", + "integrity": "sha512-TME1VgSb7wTwgENN5KVj4Nqg25hP8DisXxNBojM4Nn31rYaNDIocNm5cmjOFfh42n7NVERxWrDFoETO/76ePyg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "@typescript-eslint/types": "4.15.2", + "eslint-visitor-keys": "^2.0.0" } }, - "babel-runtime": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", - "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "@vitejs/plugin-vue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.1.tgz", + "integrity": "sha512-TG+LbEUNwfFrx1VyN+iq+PsiGd9MT16hUdJY+BnMXj3MrLAF8m3VYUspTDM3aXoh48YDmAkMjG4gWFRg3lbG5A==", + "dev": true + }, + "@vue/compiler-core": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.11.tgz", + "integrity": "sha512-6sFj6TBac1y2cWCvYCA8YzHJEbsVkX7zdRs/3yK/n1ilvRqcn983XvpBbnN3v4mZ1UiQycTvOiajJmOgN9EVgw==", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/shared": "3.0.11", + "estree-walker": "^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 + } } }, - "babel-template": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz", - "integrity": "sha1-BK5RTx+Ts6JTfyoPYKWkX7gwgzM=", + "@vue/compiler-dom": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.11.tgz", + "integrity": "sha512-+3xB50uGeY5Fv9eMKVJs2WSRULfgwaTJsy23OIltKgMrynnIj8hTYY2UL97HCoz78aDw1VDXdrBQ4qepWjnQcw==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1", - "babylon": "^6.11.0", - "lodash": "^4.2.0" + "@vue/compiler-core": "3.0.11", + "@vue/shared": "3.0.11" } }, - "babel-traverse": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz", - "integrity": "sha1-qzZnP9NW+aCUhlnnszjV/q2zFpU=", + "@vue/compiler-sfc": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.11.tgz", + "integrity": "sha512-7fNiZuCecRleiyVGUWNa6pn8fB2fnuJU+3AGjbjl7r1P5wBivfl02H4pG+2aJP5gh2u+0wXov1W38tfWOphsXw==", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1", - "babylon": "^6.15.0", - "debug": "^2.2.0", - "globals": "^9.0.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "@babel/parser": "^7.13.9", + "@babel/types": "^7.13.0", + "@vue/compiler-core": "3.0.11", + "@vue/compiler-dom": "3.0.11", + "@vue/compiler-ssr": "3.0.11", + "@vue/shared": "3.0.11", + "consolidate": "^0.16.0", + "estree-walker": "^2.0.1", + "hash-sum": "^2.0.0", + "lru-cache": "^5.1.1", + "magic-string": "^0.25.7", + "merge-source-map": "^1.1.0", + "postcss": "^8.1.10", + "postcss-modules": "^4.0.0", + "postcss-selector-parser": "^6.0.4", + "source-map": "^0.6.1" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "@babel/parser": { + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", + "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", + "dev": true + }, + "consolidate": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz", + "integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==", "dev": true, "requires": { - "ms": "2.0.0" + "bluebird": "^3.7.2" + } + }, + "hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" } + }, + "nanoid": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", + "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", + "dev": true + }, + "postcss": { + "version": "8.2.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz", + "integrity": "sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==", + "dev": true, + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.22", + "source-map": "^0.6.1" + } + }, + "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 + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } }, - "babel-types": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz", - "integrity": "sha1-oTaHncFbNga9oNkMH8dDBML/CXU=", + "@vue/compiler-ssr": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.11.tgz", + "integrity": "sha512-66yUGI8SGOpNvOcrQybRIhl2M03PJ+OrDPm78i7tvVln86MHTKhM3ERbALK26F7tXl0RkjX4sZpucCpiKs3MnA==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^1.0.1" + "@vue/compiler-dom": "3.0.11", + "@vue/shared": "3.0.11" } }, - "babylon": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.16.1.tgz", - "integrity": "sha1-MMWiL0gZeKnn+M399JaxHZS0BNM=", - "dev": true + "@vue/reactivity": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.11.tgz", + "integrity": "sha512-SKM3YKxtXHBPMf7yufXeBhCZ4XZDKP9/iXeQSC8bBO3ivBuzAi4aZi0bNoeE2IF2iGfP/AHEt1OU4ARj4ao/Xw==", + "dev": true, + "requires": { + "@vue/shared": "3.0.11" + } }, - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true + "@vue/runtime-core": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.11.tgz", + "integrity": "sha512-87XPNwHfz9JkmOlayBeCCfMh9PT2NBnv795DSbi//C/RaAnc/bGZgECjmkD7oXJ526BZbgk9QZBPdFT8KMxkAg==", + "dev": true, + "requires": { + "@vue/reactivity": "3.0.11", + "@vue/shared": "3.0.11" + } }, - "bcryptjs": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.3.0.tgz", - "integrity": "sha1-WCaQDP73q680JccuTUZN5Qm4wuw=" + "@vue/runtime-dom": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.11.tgz", + "integrity": "sha512-jm3FVQESY3y2hKZ2wlkcmFDDyqaPyU3p1IdAX92zTNeCH7I8zZ37PtlE1b9NlCtzV53WjB4TZAYh9yDCMIEumA==", + "dev": true, + "requires": { + "@vue/runtime-core": "3.0.11", + "@vue/shared": "3.0.11", + "csstype": "^2.6.8" + } }, - "brace-expansion": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", - "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "@vue/server-renderer": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.0.11.tgz", + "integrity": "sha512-NtXRxCq+jJWohce7s2kgUdO7gD6LRrWhvpGUMrpp65ODxuwolVHVyacyvAnU9bxTj11xw+ErC7Q2+su9mJusEg==", "dev": true, "requires": { - "balanced-match": "^0.4.1", - "concat-map": "0.0.1" + "@vue/compiler-ssr": "3.0.11", + "@vue/shared": "3.0.11" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "@vue/shared": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.0.11.tgz", + "integrity": "sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA==", "dev": true }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } }, - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, - "buffer-shims": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "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 }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "callsites": "^0.2.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "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 }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "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 }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" + "color-convert": "^1.9.0" } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", "dev": true, "requires": { - "restore-cursor": "^1.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.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 - }, - "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" - } - } + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, - "code-point-at": { + "assertion-error": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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" + } + } + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.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" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserslist": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001181", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.649", + "escalade": "^3.1.1", + "node-releases": "^1.1.70" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001192", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001192.tgz", + "integrity": "sha512-63OrUnwJj5T1rUmoyqYTdRWBqFFxZFlyZnRRjDR8NSUQFB6A+j/uBORU/SyJ5WzDLg4SPiZH40hQCBNdZ/jmAw==", + "dev": true + }, + "chai": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/BFd2J30EcOwmdOgXvVsmM48l0Br0nmZPlO0uOW4XKh6kpsUumRXBgPV+IlaqFaqr9cYbeoZAM1Npx0i4A+aiA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "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" + }, + "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" + } + }, + "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" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "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" + } + }, + "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 + }, + "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": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", + "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", + "dev": true + }, + "clipboard": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", + "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "dev": true, + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, "color-convert": { @@ -1028,30 +1635,89 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "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=", + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "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==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "mime-db": ">= 1.43.0 < 2" } }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "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=", + "dev": true + }, "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", @@ -1075,18 +1741,27 @@ } } }, - "core-js": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", - "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1096,53 +1771,32 @@ "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, - "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true, - "requires": { - "es5-ext": "^0.10.9" - } + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "2.6.16", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.16.tgz", + "integrity": "sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q==", + "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "requires": { - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } + "ms": "2.1.2" } }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", - "dev": true - }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, "deep-eql": { @@ -1161,72 +1815,72 @@ "dev": true }, "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", "dev": true, "requires": { - "strip-bom": "^2.0.0" + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } } }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "clone": "^1.0.2" } }, - "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "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": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^3.0.9", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" + "object-keys": "^1.0.12" } }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - } + "optional": true }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } + "diacritics": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", + "integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E=", + "dev": true }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "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" @@ -1240,12 +1894,107 @@ "safe-buffer": "^5.0.1" } }, + "electron-to-chromium": { + "version": "1.3.675", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.675.tgz", + "integrity": "sha512-GEQw+6dNWjueXGkGfjgm7dAMtXfEqrfDG3uWcZdeaD4cZ3dKYdPRQVruVXQRXtPLtOr5GNVVlNLRMChOZ611pQ==", + "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, + "engine.io": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", + "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "~7.4.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "engine.io-client": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz", + "integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==", + "dev": true, + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "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" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1256,38 +2005,36 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "get-intrinsic": "^1.0.2", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.1", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" } }, "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "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.1", + "is-callable": "^1.1.4", "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" - } - }, - "es5-ext": { - "version": "0.10.45", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", - "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "1" + "is-symbol": "^1.0.2" } }, "es6-error": { @@ -1296,65 +2043,23 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } + "esbuild": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.9.7.tgz", + "integrity": "sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==", + "dev": true }, - "es6-symbol": { + "escalade": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, - "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -1362,114 +2067,92 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true, - "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, "eslint": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", - "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", - "dev": true, - "requires": { - "babel-code-frame": "^6.16.0", - "chalk": "^1.1.3", - "concat-stream": "^1.5.2", - "debug": "^2.1.1", - "doctrine": "^2.0.0", - "escope": "^3.6.0", - "espree": "^3.4.0", - "esquery": "^1.0.0", - "estraverse": "^4.2.0", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", + "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.0", + "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.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "glob": "^7.0.3", - "globals": "^9.14.0", - "ignore": "^3.2.0", + "file-entry-cache": "^6.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", - "inquirer": "^0.12.0", - "is-my-json-valid": "^2.10.0", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.5.1", - "json-stable-stringify": "^1.0.0", - "levn": "^0.3.0", - "lodash": "^4.0.0", - "mkdirp": "^0.5.0", + "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.20", + "minimatch": "^3.0.4", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.1", - "pluralize": "^1.2.1", - "progress": "^1.1.8", - "require-uncached": "^1.0.2", - "shelljs": "^0.7.5", - "strip-bom": "^3.0.0", - "strip-json-comments": "~2.0.1", - "table": "^3.7.8", - "text-table": "~0.2.0", - "user-home": "^2.0.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": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "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 }, - "user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, "requires": { - "os-homedir": "^1.0.0" + "lru-cache": "^6.0.0" } } } }, - "eslint-config-semistandard": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-11.0.0.tgz", - "integrity": "sha1-RO73z9/Uchnjp7gbkbVA6IC7JhU=", - "dev": true - }, "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "version": "16.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.2.tgz", + "integrity": "sha512-fx3f1rJDsl9bY7qzyX8SAtP8GBSk6MfXFaTfaGgk12aAYW4gJSyRm7dM790L6cbXv63fvjY4XeSzXnb4WM+SKw==", "dev": true }, - "eslint-config-standard-jsx": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.1.tgz", - "integrity": "sha1-zU5GPQJo4tnnB/YfQvc/WzMzxkI=", - "dev": true + "eslint-config-standard-with-typescript": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-20.0.0.tgz", + "integrity": "sha512-IoySf3r0a2+P3Z6GMjv8p1HuOQ6GWQbMpdt9G8uEbkGpnNWAGBXpgaiutbZHbaQAvG5pkVtYepCfHUxYbVDLCA==", + "dev": true, + "requires": { + "@typescript-eslint/parser": "^4.0.0", + "eslint-config-standard": "^16.0.0" + } }, "eslint-import-resolver-node": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", - "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "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.2.0", - "object-assign": "^4.0.1", - "resolve": "^1.1.6" + "debug": "^2.6.9", + "resolve": "^1.13.1" }, "dependencies": { "debug": { @@ -1480,17 +2163,23 @@ "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "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.8", - "pkg-dir": "^1.0.0" + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { @@ -1501,25 +2190,44 @@ "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, "eslint-plugin-import": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", - "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=", + "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": { - "builtin-modules": "^1.1.1", + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", "contains-path": "^0.1.0", - "debug": "^2.2.0", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.2.0", - "eslint-module-utils": "^2.0.0", - "has": "^1.0.1", - "lodash.cond": "^4.3.0", - "minimatch": "^3.0.3", - "pkg-up": "^1.0.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": { "debug": { @@ -1540,126 +2248,183 @@ "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 + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "eslint-plugin-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", - "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "requires": { - "ignore": "^3.0.11", - "minimatch": "^3.0.2", - "object-assign": "^4.0.1", - "resolve": "^1.1.7", - "semver": "5.3.0" + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.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 + } } }, "eslint-plugin-promise": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", - "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", + "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", "dev": true }, - "eslint-plugin-react": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", - "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "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": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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": { - "array.prototype.find": "^2.0.1", - "doctrine": "^1.2.2", - "has": "^1.0.1", - "jsx-ast-utils": "^1.3.4", - "object.assign": "^4.0.4" + "eslint-visitor-keys": "^1.1.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" - } + "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 } } }, - "eslint-plugin-standard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", - "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "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 }, "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.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 + } } }, + "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 + }, "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "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.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "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": "^4.1.0" + "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.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, - "esutils": { + "estree-walker": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1671,99 +2436,60 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "feathers-hooks-common": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/feathers-hooks-common/-/feathers-hooks-common-5.0.3.tgz", - "integrity": "sha512-Irw7mVecC2im9Pemr4yGyO8XXxFhlqn4rnsc5iSNMSmO78ta1QaHUfiZddmquA0u0KTFyk2crQK4mcHq8grzXA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/feathers-hooks-common/-/feathers-hooks-common-5.0.5.tgz", + "integrity": "sha512-GOHZ6W/ioEK5uCs4bCh21P/oLObVqIkbQ6WTKZMscJlykDptH3KOIMiUpFscO6uLQcKKZHY7a1PabLNFP2J7tA==", "requires": { "@feathers-plus/batch-loader": "^0.3.6", - "@feathersjs/commons": "^4.5.3", - "@feathersjs/errors": "^4.5.3", - "@feathersjs/feathers": "^4.5.3", - "ajv": "^6.12.2", - "debug": "^4.1.1", - "graphql": "^15.0.0", - "lodash": "^4.17.15", + "@feathersjs/commons": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "@feathersjs/feathers": "^4.5.11", + "ajv": "^6.12.6", + "debug": "^4.3.1", + "graphql": "^15.5.0", + "lodash": "^4.17.20", "process": "0.11.10", "traverse": "^0.6.6" - }, - "dependencies": { - "@feathersjs/commons": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-4.5.7.tgz", - "integrity": "sha512-qSN61eCOQbzk9zkzxNelCEo5x+p8rsa0kNvfe5JETAzNGf3xITstE66cs8s1XXPNFvlXEmqTefya27YKT1g/bw==" - }, - "@feathersjs/errors": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-4.5.7.tgz", - "integrity": "sha512-YCwcNmkXCHc8c8lJMoiBFzwda6W0o1sK7oSLk9rfaQWfacSvOos8zX+1v7bmeQYfHcgWmHhb6tLb2WsNqU+BVg==", - "requires": { - "debug": "^4.1.1" - } - }, - "@feathersjs/feathers": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-4.5.7.tgz", - "integrity": "sha512-Qbw5e5Y5mJkxZOrgbaZXj2w0smoBJf2goud1Du+kNRMJfcexZ/tQDtPj6aFOIl6dduyB/3Xka4XQQn/T+rHB4w==", - "requires": { - "@feathersjs/commons": "^4.5.7", - "debug": "^4.1.1", - "events": "^3.2.0", - "uberproto": "^2.0.6" - } - }, - "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" - }, - "uberproto": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.6.tgz", - "integrity": "sha512-68H97HffZoFaa3HFtpstahWorN9dSp5uTU6jo3GjIQ6JkJBR3hC2Nx/e/HFOoYHdUyT/Z1MRWfxN1EiQJZUyCQ==" - } } }, "feathers-memory": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/feathers-memory/-/feathers-memory-4.0.0.tgz", - "integrity": "sha512-atyq5t+YTQD0Vfe4lh1hUHD7kzx5uEIktSCOZmM7khYqAD4KwzYexIfKb6mFdk8jgFIoYLH+kryJojPyxh61sg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/feathers-memory/-/feathers-memory-4.1.0.tgz", + "integrity": "sha512-tR8DFqLsSk2w7tpSdHjA5RgPHTu3X5R3L3Kob2K+E3b/Q5cDkI6AYQarDQOiwekAyqxkkp/fm7Fg0qYdu4Ua6Q==", "dev": true, "requires": { - "@feathersjs/adapter-commons": "^4.0.0-pre.4", - "@feathersjs/commons": "^4.0.0-pre.4", - "@feathersjs/errors": "^4.0.0-pre.4", + "@feathersjs/adapter-commons": "^4.3.6", + "@feathersjs/commons": "^4.3.0", + "@feathersjs/errors": "^4.3.4", "sift": "^8.5.0" } }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^3.0.4" } }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "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": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" + "to-regex-range": "^5.0.1" } }, "find-cache-dir": { @@ -1837,47 +2563,35 @@ } } }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^2.0.0" } }, "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "foreground-child": { @@ -1891,9 +2605,9 @@ } }, "fromentries": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", - "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", "dev": true }, "fs.realpath": { @@ -1902,31 +2616,38 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "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==", "dev": true }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "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 }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "generic-names": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", + "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==", "dev": true, "requires": { - "is-property": "^1.0.0" + "loader-utils": "^1.1.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 }, "get-caller-file": { @@ -1941,62 +2662,109 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, - "get-stdin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", - "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", - "dev": true - }, "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.2", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, + "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==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", - "integrity": "sha1-DAymltm5u2lNLlRwvTd3fKrVAoY=", - "dev": true + "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": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "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" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dev": true, + "optional": true, + "requires": { + "delegate": "^3.1.2" } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "graphql": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.3.0.tgz", - "integrity": "sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==" + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.0.tgz", + "integrity": "sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==" + }, + "gray-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.2.tgz", + "integrity": "sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw==", + "dev": true, + "requires": { + "js-yaml": "^3.11.0", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + } }, "growl": { "version": "1.10.5", @@ -2004,50 +2772,6 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "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 - }, - "uglify-js": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.3.tgz", - "integrity": "sha512-r5ImcL6QyzQGVimQoov3aL2ZScywrOgBXGndbWrdehKoSvGe/RmiE5Jpw/v+GvxODt6l2tpBXwA7n+qZVlHBMA==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.3" - } - } - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2057,35 +2781,49 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "isarray": "2.0.1" } }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "hasha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", - "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", "dev": true, "requires": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" + }, + "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 + } } }, "he": { @@ -2094,18 +2832,46 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "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==", + "dev": true + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2118,6 +2884,18 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2129,175 +2907,145 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "ansi-regex": "^2.0.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "readline2": "^1.0.1", - "run-async": "^0.1.0", - "rx-lite": "^3.1.2", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } - }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, - "invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "has": "^1.0.3" } }, - "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=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "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==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" + "is-extglob": "^2.1.1" } }, - "is-path-cwd": { + "is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.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 }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", "dev": true, "requires": { - "has": "^1.0.1" + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "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 }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "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" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, "is-windows": { @@ -2307,9 +3055,9 @@ "dev": true }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", "dev": true }, "isexe": { @@ -2318,80 +3066,39 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "istanbul": { - "version": "1.1.0-alpha.1", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-1.1.0-alpha.1.tgz", - "integrity": "sha1-eBeVZWAYohdMX2DzZ+5dNhy1e3c=", - "dev": true, - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "istanbul-api": "^1.1.0-alpha", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - } - }, - "istanbul-api": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.7.tgz", - "integrity": "sha1-9vN/CfgAKxMPiRxka3DuSo5zRa4=", - "dev": true, - "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.0.2", - "istanbul-lib-hook": "^1.0.5", - "istanbul-lib-instrument": "^1.7.0", - "istanbul-lib-report": "^1.0.0", - "istanbul-lib-source-maps": "^1.1.1", - "istanbul-reports": "^1.0.2", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - }, - "dependencies": { - "async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.3.0.tgz", - "integrity": "sha1-EBPRBRBH3TIP4k5JTVxm7K9hR9k=", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } - } - } - }, "istanbul-lib-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz", - "integrity": "sha1-h6DAFbaRBlHLOxhIFN+zOTN+JeE=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", "dev": true }, "istanbul-lib-hook": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz", - "integrity": "sha1-bKPRbWDF9Agto598XNOOqKdyuI4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, "requires": { - "append-transform": "^0.4.0" + "append-transform": "^2.0.0" } }, "istanbul-lib-instrument": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz", - "integrity": "sha1-uODcJXCbtE4XM2q0e3u1yXwj9lk=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.13.0", - "istanbul-lib-coverage": "^1.0.2", - "semver": "^5.3.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.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 + } } }, "istanbul-lib-processinfo": { @@ -2409,124 +3116,91 @@ "uuid": "^3.3.3" }, "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } } } }, "istanbul-lib-report": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz", - "integrity": "sha1-2D2sfyZWa1IVhVaTZ/6EzPx6rss=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { - "istanbul-lib-coverage": "^1.0.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "dependencies": { + "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": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "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": "^1.0.0" + "has-flag": "^4.0.0" } } } }, "istanbul-lib-source-maps": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz", - "integrity": "sha1-+MjC6PIWDR2RUm2X5b1jsgea9xw=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { - "istanbul-lib-coverage": "^1.0.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.4.4", - "source-map": "^0.5.3" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "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 + } } }, "istanbul-reports": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.0.2.tgz", - "integrity": "sha1-ToNmq+b6dGzBzWYz8QjeEsxqxvo=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", "dev": true, "requires": { - "handlebars": "^4.0.3" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, "js-tokens": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", - "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" - }, - "dependencies": { - "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 - } } }, "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "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==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-schema-traverse": { @@ -2534,44 +3208,21 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stable-stringify": { + "json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } + "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 }, "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" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } + "minimist": "^1.2.0" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsonwebtoken": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", @@ -2587,26 +3238,8 @@ "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==" - } } }, - "jsx-ast-utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", - "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", - "dev": true - }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -2626,40 +3259,52 @@ "safe-buffer": "^5.0.1" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "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.2.1", + "type-check": "~0.4.0" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "uc.micro": "^1.0.1" } }, "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": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "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": { @@ -2670,25 +3315,17 @@ "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.cond": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", - "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", "dev": true }, "lodash.flattendeep": { @@ -2733,58 +3370,35 @@ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "chalk": "^2.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "chalk": "^4.0.0" } }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" + }, + "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" + } + }, + "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": { - "js-tokens": "^3.0.0" + "sourcemap-codec": "^1.4.4" } }, "make-dir": { @@ -2804,199 +3418,255 @@ } } }, - "minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "dev": true + }, + "markdown-it-container": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", + "integrity": "sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU=", + "dev": true + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=", + "dev": true + }, + "markdown-it-table-of-contents": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", + "dev": true + }, + "matchit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", + "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", + "dev": true, + "requires": { + "@arr/every": "^1.0.0" + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "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 + } + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "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" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", "dev": true, "requires": { - "brace-expansion": "^1.0.0" + "mime-db": "1.46.0" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "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 }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "minimist": "0.0.8" + "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", + "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", "dev": true, "requires": { - "ansi-colors": "3.2.3", + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } + "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==", + "dev": true }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "argparse": "^2.0.1" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "p-locate": "^5.0.0" } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^3.0.2" } }, - "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==", - "dev": true - }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "isexe": "^2.0.0" + "has-flag": "^4.0.0" } } } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", "dev": true }, "natural-compare": { @@ -3005,36 +3675,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -3044,19 +3690,28 @@ "process-on-spawn": "^1.0.0" } }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "node-releases": { + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "dev": true + }, + "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==", "dev": true, "requires": { - "abbrev": "1" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "nyc": { @@ -3094,30 +3749,20 @@ "yargs": "^15.0.2" }, "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.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, "cliui": { "version": "6.0.0", @@ -3145,28 +3790,10 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "find-up": { @@ -3179,91 +3806,6 @@ "path-exists": "^4.0.0" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.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-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -3273,21 +3815,6 @@ "p-locate": "^4.1.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "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 - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3324,62 +3851,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "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 - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -3391,10 +3862,16 @@ "strip-ansi": "^6.0.0" } }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "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", @@ -3407,7 +3884,7 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" + "yargs-parser": "^18.1.2" } }, "yargs-parser": { @@ -3421,126 +3898,49 @@ } } } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "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" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "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.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "dependencies": { - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - } - } - }, - "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" - } - }, - "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==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "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" - } - } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "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==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3551,30 +3951,56 @@ } }, "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "mimic-fn": "^2.1.0" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "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.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz", + "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + } + } }, "p-limit": { "version": "1.3.0", @@ -3619,47 +4045,50 @@ "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - } } }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "callsites": "^3.0.0" } }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "error-ex": "^1.2.0" } }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==", + "dev": true + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3667,15 +4096,27 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, "pify": { @@ -3684,94 +4125,128 @@ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "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": { - "pinkie": "^2.0.0" + "find-up": "^2.1.0" } }, - "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "polka": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", + "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", "dev": true, "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" + "@polka/url": "^0.5.0", + "trouter": "^2.0.1" + } + }, + "postcss-modules": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.0.0.tgz", + "integrity": "sha512-ghS/ovDzDqARm4Zj6L2ntadjyQMoyJmi0JkLlYtH2QFLrvNlxH5OAVRPWPeKilB0pY7SbuhO173KOWkPAxRJcw==", + "dev": true, + "requires": { + "generic-names": "^2.0.1", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" }, "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "icss-utils": "^5.0.0" } } } }, - "pkg-config": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", - "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", - "dev": true, - "requires": { - "debug-log": "^1.0.0", - "find-root": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", "dev": true, "requires": { - "find-up": "^1.0.0" + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" } }, - "pkg-up": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", - "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true }, - "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "preact": { + "version": "10.5.13", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.13.tgz", + "integrity": "sha512-q/vlKIGNwzTLu+jCcvywgGrt+H/1P/oIRSD6mV4ln3hmlC+Aa34C7yfPI4+5bzW8pONyVXYS7SvXosy2dKKtWQ==", "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 }, + "prismjs": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", + "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", + "dev": true, + "requires": { + "clipboard": "^2.0.0" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, "process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -3782,9 +4257,9 @@ } }, "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "punycode": { @@ -3792,35 +4267,65 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "queue-microtask": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", + "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "dev": true + }, "radix-router": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/radix-router/-/radix-router-3.0.1.tgz", "integrity": "sha512-jpHXHgP+ZmVzEfmZ7WVRSvc/EqMoAqYuMtBsHd9s47Hs9Iy8FDJhkweMrDH0wmdxanLzVIWhq0UpomLXNpW8tg==" }, - "readable-stream": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", - "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { - "buffer-shims": "~1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" + "safe-buffer": "^5.1.0" } }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "read-pkg": { + "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", + "path-type": "^2.0.0" + }, + "dependencies": { + "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": { + "pify": "^2.0.0" + } + } + } + }, + "read-pkg-up": { + "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": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readdirp": { + "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": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "mute-stream": "0.0.5" + "picomatch": "^2.2.1" } }, "rechoir": { @@ -3832,10 +4337,10 @@ "resolve": "^1.1.6" } }, - "regenerator-runtime": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz", - "integrity": "sha1-jENnqQS1HqYqkIrDEL+Z/5CoKj4=", + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, "release-zalgo": { @@ -3847,120 +4352,129 @@ "es6-error": "^4.0.1" } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "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": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" } }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, - "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "rollup": { + "version": "2.45.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz", + "integrity": "sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==", "dev": true, "requires": { - "once": "^1.3.0" + "fsevents": "~2.3.1" } }, "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "semistandard": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/semistandard/-/semistandard-11.0.0.tgz", - "integrity": "sha1-0tn8isOT3iExIZXgBuUMiGE5HEc=", + "section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", "dev": true, "requires": { - "eslint": "~3.19.0", - "eslint-config-semistandard": "^11.0.0", - "eslint-config-standard": "^10.2.1", - "eslint-config-standard-jsx": "4.0.1", - "eslint-plugin-import": "~2.2.0", - "eslint-plugin-node": "~4.2.2", - "eslint-plugin-promise": "~3.5.0", - "eslint-plugin-react": "~6.10.0", - "eslint-plugin-standard": "~3.0.1", - "standard-engine": "~7.0.0" + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.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" + } + } } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "dev": true, + "optional": true + }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "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": { + "randombytes": "^2.1.0" + } }, "set-blocking": { "version": "2.0.0", @@ -3984,9 +4498,9 @@ "dev": true }, "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "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", @@ -3994,10 +4508,20 @@ "rechoir": "^0.6.2" } }, + "shx": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", + "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", + "dev": true, + "requires": { + "minimist": "^1.2.3", + "shelljs": "^0.8.4" + } + }, "sift": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-8.5.0.tgz", - "integrity": "sha512-IdHwlvlDbHYmcPYOfkU89Qo29cPR7fLM0htfeUP9YxeU213oKYH/6d416z+vFj6ArCsH+AzQQ8/rd1TIzRE7LQ==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-8.5.1.tgz", + "integrity": "sha512-um2rEdXrc4YcRMzIliuip4i2o92mJONh5W1VD9vJlm1e0apVqMK4P2ZUijz8BIe1/oYLWmXwXaKFM+fOaO3Ysg==", "dev": true }, "signal-exit": { @@ -4006,563 +4530,375 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "standard-engine": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", - "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=", + "sirv": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.11.tgz", + "integrity": "sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==", "dev": true, "requires": { - "deglob": "^2.1.0", - "get-stdin": "^5.0.1", - "minimist": "^1.1.0", - "pkg-conf": "^2.0.0" + "@polka/url": "^1.0.0-next.9", + "mime": "^2.3.1", + "totalist": "^1.0.0" }, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "@polka/url": { + "version": "1.0.0-next.12", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz", + "integrity": "sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ==", + "dev": true + } } }, - "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==", + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { - "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" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "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": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "dependencies": { - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - } + "color-convert": "^2.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==", + "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": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "color-name": "~1.1.4" } }, - "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==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "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 - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "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" - } } } }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "socket.io": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", + "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" + "debug": "~4.1.0", + "engine.io": "~3.5.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.4.0", + "socket.io-parser": "~3.4.0" }, "dependencies": { - "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" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "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.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "dependencies": { - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - } + "ms": "^2.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==", + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "socket.io-client": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "ms": "2.0.0" } }, - "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==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "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==", + "socket.io-parser": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" } } } }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "socket.io-parser": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", + "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" }, "dependencies": { - "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" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "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.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "dependencies": { - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - } - } - }, - "es-to-primitive": { + "component-emitter": { "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" - } - }, - "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==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "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==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "ms": "^2.1.1" } } } }, - "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==", + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" }, "dependencies": { - "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" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "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.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "dependencies": { - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - } - } - }, - "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" - } - }, - "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==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "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 - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "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" - } } } }, - "string_decoder": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", - "integrity": "sha1-8G9BFXtmTYYGn4S9vcmw2KsoFmc=", + "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-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { - "buffer-shims": "~1.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "strip-ansi": { + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "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" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "ansi-regex": "^5.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "dev": true + }, "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 }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } }, "table": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", "dev": true, "requires": { - "ajv": "^4.7.0", - "ajv-keywords": "^1.0.0", - "chalk": "^1.1.1", - "lodash": "^4.0.0", - "slice-ansi": "0.0.4", - "string-width": "^2.0.0" + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" }, "dependencies": { "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", "dev": true, "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } }, - "ansi-regex": { - "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=", + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "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=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } } } }, @@ -4575,31 +4911,6 @@ "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } } }, "text-table": { @@ -4608,16 +4919,38 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "optional": true + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", "dev": true }, "to-fast-properties": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz", - "integrity": "sha1-8/XAw7pymafvmUJ+RGMyV63kMyA=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "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" + } + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", "dev": true }, "traverse": { @@ -4625,19 +4958,71 @@ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "trouter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", + "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", + "dev": true, + "requires": { + "matchit": "^1.0.0" + } + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", + "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "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": { @@ -4647,16 +5032,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==", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.2.tgz", + "integrity": "sha512-pvQl0WNazvfQ0rq2XDdhpWv49sohh2t+buFbglaJ9N9+Xj4BhFRpuo+uJxemeARteRxRloJ1m+8gBR6Z2Nfktg==" }, "typedarray-to-buffer": { "version": "3.1.5", @@ -4667,10 +5045,21 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", + "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==", + "dev": true + }, "uberproto": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.4.tgz", - "integrity": "sha512-c/5xjTcztW9XVhrkCycHQRBIAxww5JpDKk/q0zc2tVdQn6ZQvnChWgLvQaWAT1Al5JvRyvloUI15ad41m6dYwg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.6.tgz", + "integrity": "sha512-68H97HffZoFaa3HFtpstahWorN9dSp5uTU6jo3GjIQ6JkJBR3hC2Nx/e/HFOoYHdUyT/Z1MRWfxN1EiQJZUyCQ==" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, "uniq": { @@ -4680,9 +5069,9 @@ "dev": true }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } @@ -4694,165 +5083,202 @@ "dev": true }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "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 + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { - "isexe": "^2.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "vite": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.1.5.tgz", + "integrity": "sha512-tYU5iaYeUgQYvK/CNNz3tiJ8vYqPWfCE9IQ7K0iuzYovWw7lzty7KRYGWwV3CQPh0NKxWjOczAqiJsCL0Xb+Og==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "esbuild": "^0.9.3", + "fsevents": "~2.3.1", + "postcss": "^8.2.1", + "resolve": "^1.19.0", + "rollup": "^2.38.5" + }, + "dependencies": { + "nanoid": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", + "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", + "dev": true + }, + "postcss": { + "version": "8.2.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz", + "integrity": "sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==", + "dev": true, + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.22", + "source-map": "^0.6.1" + } + }, + "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 + } } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "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==", + "vitepress": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-0.13.0.tgz", + "integrity": "sha512-LTVxbHTZt46kKwxreKe3EFARuwtbsK5DyXFPvhQ8oUkKFFR9FDI/vt79ABFQWUQM1AokQEoa6RXsBr1qFv0s4Q==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "@docsearch/css": "^1.0.0-alpha.28", + "@docsearch/js": "^1.0.0-alpha.28", + "@vitejs/plugin-vue": "^1.1.4", + "@vue/compiler-sfc": "^3.0.5", + "@vue/server-renderer": "^3.0.5", + "chalk": "^4.1.0", + "compression": "^1.7.4", + "debug": "^4.1.1", + "diacritics": "^1.3.0", + "escape-html": "^1.0.3", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "gray-matter": "^4.0.2", + "lru-cache": "^6.0.0", + "markdown-it": "^10.0.0", + "markdown-it-anchor": "^5.2.7", + "markdown-it-container": "^2.0.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-table-of-contents": "^0.4.4", + "minimist": "^1.2.5", + "ora": "^5.3.0", + "polka": "^0.5.2", + "prismjs": "^1.23.0", + "sirv": "^1.0.11", + "vite": "^2.0.5", + "vue": "^3.0.5" }, "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==", + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, - "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 + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.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==", + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "vue": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.0.11.tgz", + "integrity": "sha512-3/eUi4InQz8MPzruHYSTQPxtM3LdZ1/S/BvaU021zBnZi0laRUyH6pfuE4wtUeLvI8wmUNwj5wrZFvbHUXL9dw==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "@vue/compiler-dom": "3.0.11", + "@vue/runtime-dom": "3.0.11", + "@vue/shared": "3.0.11" } } } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "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": { - "mkdirp": "^0.5.1" + "defaults": "^1.0.3" } }, - "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==", + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "isexe": "^2.0.0" } }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "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" + "string-width": "^1.0.2 || 2" }, "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 - }, - "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^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", @@ -4860,88 +5286,168 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "p-try": "^2.0.0" + "ansi-regex": "^3.0.0" } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.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": { - "p-limit": "^2.0.0" + "color-convert": "^2.0.1" } }, - "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==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "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==", + "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": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-name": "~1.1.4" } }, - "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" - } + "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 } } }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "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", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", + "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 3843ed2..3bacee1 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "feathers-authentication-management", - "description": "Adds sign up verification, forgotten password reset, and other capabilities to local feathers-authentication ", + "description": "Adds sign up verification, forgotten password reset, and other capabilities to local feathers-authentication", "version": "3.1.0", "repository": { "type": "git", @@ -27,20 +27,25 @@ "engines": { "node": ">= 8.12.0" }, - "main": "src/", + "main": "dist/", + "types": "dist/", "directories": { "src": "src" }, "scripts": { + "preversion": "npm run lint && npm run test && npm run compile", "publish": "git push origin --tags && npm run changelog && git push origin", + "release:pre": "npm version prerelease && npm publish --tag pre", "release:patch": "npm version patch && npm publish", "release:minor": "npm version minor && npm publish", "release:major": "npm version major && npm publish", "changelog": "github_changelog_generator -u feathersjs-ecosystem -p feathers-authentication-management && git add CHANGELOG.md && git commit -am \"Updating changelog\"", - "lint": "semistandard src/**/*.js --fix", - "mocha": "mocha --opts mocha.opts", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", + "mocha": "cross-env TS_NODE_PROJECT='tsconfig.test.json' mocha --require ts-node/register --timeout 40000", "coverage": "nyc npm run mocha", - "test": "npm run lint && npm run coverage" + "test": "npm run coverage", + "compile": "shx rm -rf dist/ && tsc", + "docs": "vitepress dev docs" }, "semistandard": { "env": [ @@ -48,20 +53,41 @@ ] }, "dependencies": { - "@feathersjs/authentication": "^4.3.0", - "@feathersjs/authentication-local": "^4.3.0", - "@feathersjs/errors": "^4.3.0", - "bcryptjs": "^2.3.0", - "debug": "^4.1.0", - "feathers-hooks-common": "^5.0.3" + "@feathersjs/authentication": "^4.5.11", + "@feathersjs/authentication-client": "^4.5.11", + "@feathersjs/authentication-local": "^4.5.11", + "@feathersjs/errors": "^4.5.11", + "bcryptjs": "^2.4.3", + "debug": "^4.3.1", + "feathers-hooks-common": "^5.0.5", + "lodash": "^4.17.21", + "type-fest": "^0.21.2" }, "devDependencies": { - "@feathersjs/feathers": "^4.3.0", - "chai": "^4.2.0", - "feathers-memory": "^4.0.0", - "istanbul": "^1.1.0-alpha.1", - "mocha": "^6.2.0", + "@feathersjs/feathers": "^4.5.11", + "@feathersjs/socketio": "^4.5.11", + "@feathersjs/transport-commons": "^4.5.11", + "@types/bcryptjs": "^2.4.2", + "@types/chai": "^4.2.15", + "@types/debug": "^4.1.5", + "@types/lodash": "^4.14.168", + "@types/mocha": "^8.2.1", + "@types/node": "^14.14.31", + "@typescript-eslint/eslint-plugin": "^4.15.2", + "@typescript-eslint/parser": "^4.15.2", + "chai": "^4.3.0", + "cross-env": "^7.0.3", + "eslint": "^7.20.0", + "eslint-config-standard-with-typescript": "^20.0.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.3.1", + "feathers-memory": "^4.1.0", + "mocha": "^8.3.0", "nyc": "^15.0.1", - "semistandard": "^11.0.0" + "shx": "^0.3.3", + "ts-node": "^9.1.1", + "typescript": "^4.1.5", + "vitepress": "^0.13.0" } } diff --git a/src/client.js b/src/client.js deleted file mode 100755 index f7999f3..0000000 --- a/src/client.js +++ /dev/null @@ -1,107 +0,0 @@ - -// Wrapper for client interface to feathers-authenticate-management - -function AuthManagement (app) { // eslint-disable-line no-unused-vars - if (!(this instanceof AuthManagement)) { - return new AuthManagement(app); - } - - const authManagement = app.service('authManagement'); - - this.checkUnique = async (identifyUser, ownId, ifErrMsg) => { - await authManagement.create({ - action: 'checkUnique', - value: identifyUser, - ownId, - meta: { noErrMsg: ifErrMsg } - }, {}); - }; - - this.resendVerifySignup = async (identifyUser, notifierOptions) => { - await authManagement.create({ - action: 'resendVerifySignup', - value: identifyUser, - notifierOptions - }, {}); - }; - - this.verifySignupLong = async (verifyToken) => { - await authManagement.create({ - action: 'verifySignupLong', - value: verifyToken - }, {}); - }; - - this.verifySignupShort = async (verifyShortToken, identifyUser) => { - await authManagement.create({ - action: 'verifySignupShort', - value: { user: identifyUser, token: verifyShortToken } - }, {}); - }; - - this.sendResetPwd = async (identifyUser, notifierOptions) => { - await authManagement.create({ - action: 'sendResetPwd', - value: identifyUser, - notifierOptions - }, {}); - }; - - this.resetPwdLong = async (resetToken, password) => { - await authManagement.create({ - action: 'resetPwdLong', - value: { token: resetToken, password } - }, {}); - }; - - this.resetPwdShort = async (resetShortToken, identifyUser, password) => { - await authManagement.create({ - action: 'resetPwdShort', - value: { user: identifyUser, token: resetShortToken, password } - }, {}); - }; - - this.passwordChange = async (oldPassword, password, identifyUser) => { - await authManagement.create({ - action: 'passwordChange', - value: { user: identifyUser, oldPassword, password } - }, {}); - }; - - this.identityChange = async (password, changesIdentifyUser, identifyUser) => { - await authManagement.create({ - action: 'identityChange', - value: { user: identifyUser, password, changes: changesIdentifyUser } - }, {}); - }; - - this.authenticate = async (email, password, cb) => { - let cbCalled = false; - - return app.authenticate({ type: 'local', email, password }) - .then(result => { - const user = result.data; - - if (!user || !user.isVerified) { - app.logout(); - return cb(new Error(user ? 'User\'s email is not verified.' : 'No user returned.')); - } - - if (cb) { - cbCalled = true; - return cb(null, user); - } - - return user; - }) - .catch((err) => { - if (!cbCalled) { - cb(err); - } - }); - }; -} - -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = AuthManagement; -} diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..4513458 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,148 @@ +import { AuthenticationClient } from '@feathersjs/authentication-client'; +import { Application, Id } from '@feathersjs/feathers'; +import { AuthenticationManagementService } from './services'; + +import { + AuthenticationManagementClient, + IdentifyUser, + User +} from './types'; +// Wrapper for client interface to feathers-authenticate-management + +declare module '@feathersjs/feathers' { + interface Application { + authenticate: AuthenticationClient['authenticate'] + logout: AuthenticationClient['logout'] + } +} + +function AuthManagement (app: Application): AuthenticationManagementClient { // eslint-disable-line no-unused-vars + /* if (!(this instanceof AuthManagement)) { + return new AuthManagement(app); + } */ + + const authManagement = app.service('authManagement') as AuthenticationManagementService; + + const client: AuthenticationManagementClient = { + checkUnique: async (identifyUser: IdentifyUser, ownId: Id, ifErrMsg: boolean) => { + await authManagement.create({ + action: 'checkUnique', + value: identifyUser, + ownId, + meta: { noErrMsg: ifErrMsg } + }); + }, + resendVerifySignup: async (identifyUser: IdentifyUser, notifierOptions = {}) => { + await authManagement.create({ + action: 'resendVerifySignup', + value: identifyUser, + notifierOptions + }); + }, + verifySignupLong: async (verifyToken: string) => { + await authManagement.create({ + action: 'verifySignupLong', + value: verifyToken + }); + }, + + verifySignupShort: async (verifyShortToken: string, identifyUser: IdentifyUser) => { + await authManagement.create({ + action: 'verifySignupShort', + value: { + token: verifyShortToken, + user: identifyUser + } + }); + }, + + sendResetPwd: async (identifyUser: IdentifyUser, notifierOptions = {}) => { + await authManagement.create({ + action: 'sendResetPwd', + value: identifyUser, + notifierOptions + }); + }, + + resetPwdLong: async (resetToken: string, password: string) => { + await authManagement.create({ + action: 'resetPwdLong', + value: { + password, + token: resetToken + } + }); + }, + + resetPwdShort: async (resetShortToken: string, identifyUser: IdentifyUser, password: string) => { + await authManagement.create({ + action: 'resetPwdShort', + value: { + password, + token: resetShortToken, + user: identifyUser + } + }); + }, + + passwordChange: async (oldPassword: string, password: string, identifyUser: IdentifyUser) => { + await authManagement.create({ + action: 'passwordChange', + value: { + oldPassword, + password, + user: identifyUser + } + }); + }, + + identityChange: async (password: string, changesIdentifyUser: Record, identifyUser: IdentifyUser) => { + await authManagement.create({ + action: 'identityChange', + value: { + user: identifyUser, + password, + changes: changesIdentifyUser + } + }); + }, + + authenticate: async ( + email: string, + password: string, + cb: (err: Error | null, user?: Partial) => void + ): Promise => { + let cbCalled = false; + + const authResult = await app.authenticate({ type: 'local', email, password }); + const user = authResult.data; + + try { + if (!user || !user.isVerified) { + await app.logout(); + return cb(new Error(user ? 'User\'s email is not verified.' : 'No user returned.')); + } + + if (cb) { + cbCalled = true; + return cb(null, user); + } + + return user; + } catch (err) { + if (!cbCalled && cb) { + cb(err); + } + } + } + }; + + return client; +} + +// TODO: client +export default AuthManagement; + +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = AuthManagement; +} diff --git a/src/configureAuthManagement.ts b/src/configureAuthManagement.ts new file mode 100644 index 0000000..9af4f17 --- /dev/null +++ b/src/configureAuthManagement.ts @@ -0,0 +1,136 @@ +import makeDebug from 'debug'; + +import actionServiceClassMap from './helpers/action-service-class-map'; +import { + AuthenticationManagementAction, + AuthenticationManagementConfigureOptions, + AuthenticationManagementServiceOptions, + AuthenticationManagementServiceOptionsDefault +} from './types'; +import { AuthenticationManagementService } from './services/AuthenticationManagementService'; +import { Application } from '@feathersjs/feathers'; +import { makeDefaultOptions } from './services'; + +const debug = makeDebug('authLocalMgnt:service'); + +const getSeparateServicesPaths = ( + path: string, + options?: Partial> +): Partial> => { + if (options?.useSeparateServices === false) { + return {}; + } + + if (path.endsWith('/')) { path = path.slice(0, -1); } + const servicePaths: Record, string> = { + checkUnique: `${path}/check-unique`, + identityChange: `${path}/identity-change`, + passwordChange: `${path}/password-change`, + resendVerifySignup: `${path}/resend-verify-signup`, + resetPwdLong: `${path}/reset-password-long`, + resetPwdShort: `${path}/reset-password-short`, + sendResetPwd: `${path}/send-reset-pwd`, + verifySignupLong: `${path}/verify-signup-long`, + verifySignupSetPasswordLong: `${path}/verify-signup-set-password-long`, + verifySignupSetPasswordShort: `${path}/verify-signup-set-password-short`, + verifySignupShort: `${path}/verify-signup-short` + }; + + if ( + !options || + !Object.prototype.hasOwnProperty.call(options, 'useSeparateServices') || + options?.useSeparateServices === true + ) { + return servicePaths; + } + + const customKeys = (typeof options.useSeparateServices === 'object') + ? Object.keys(options.useSeparateServices) + : []; + + for (const key of customKeys) { + const val = options.useSeparateServices[key]; + if (val === true || !servicePaths[key]) { continue; } + if (val === false) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete servicePaths[key]; + } + if (typeof val === 'string') { + servicePaths[key] = val; + } + } + + return servicePaths; +}; + +const defaultPath = 'authManagement'; + +export const defaultConfigureOptions = { + path: defaultPath, + useSeparateServices: { + checkUnique: `${defaultPath}/check-unique`, + identityChange: `${defaultPath}/identity-change`, + passwordChange: `${defaultPath}/password-change`, + resendVerifySignup: `${defaultPath}/resend-verify-signup`, + resetPwdLong: `${defaultPath}/reset-password-long`, + resetPwdShort: `${defaultPath}/reset-password-short`, + sendResetPwd: `${defaultPath}/send-reset-pwd`, + verifySignupLong: `${defaultPath}/verify-signup-long`, + verifySignupSetPasswordLong: `${defaultPath}/verify-signup-set-password-long`, + verifySignupSetPasswordShort: `${defaultPath}/verify-signup-set-password-short`, + verifySignupShort: `${defaultPath}/verify-signup-short` + } +}; + +export const makeDefaultConfigureOptions = (): AuthenticationManagementConfigureOptions => { + const defaultServiceOptions: AuthenticationManagementServiceOptionsDefault = makeDefaultOptions([ + 'service', + 'notifier', + 'longTokenLen', + 'shortTokenLen', + 'shortTokenDigits', + 'resetDelay', + 'delay', + 'resetAttempts', + 'reuseResetToken', + 'identifyUserProps', + 'sanitizeUserForClient', + 'skipIsVerifiedCheck', + 'passwordField' + ]); + + return Object.assign({}, defaultServiceOptions, defaultConfigureOptions); +}; + +export default function authenticationLocalManagement ( + providedOptions?: Partial, + docs?: Record +): (app: Application) => void { + debug('service being configured.'); + + docs = docs ?? {}; + + return function (app) { + const defaultOptions = makeDefaultConfigureOptions(); + const options: AuthenticationManagementServiceOptions & AuthenticationManagementConfigureOptions = Object.assign( + {}, + defaultOptions, + providedOptions, + { + app + }); + const { path } = options; + const useSeparateServices = getSeparateServicesPaths(path, providedOptions); + options.useSeparateServices = useSeparateServices; + + app.use(options.path, new AuthenticationManagementService(options, docs)); + + // separate paths + for (const [action, path] of Object.entries(useSeparateServices)) { + const Service = actionServiceClassMap[action]; + app.use(path, new Service(options)); + } + }; +} + +export { AuthenticationManagementService }; diff --git a/src/helpers/action-service-class-map.ts b/src/helpers/action-service-class-map.ts new file mode 100644 index 0000000..40ea7ac --- /dev/null +++ b/src/helpers/action-service-class-map.ts @@ -0,0 +1,31 @@ +import { Class } from 'type-fest'; + +import { AuthenticationManagementBase } from '../services/AuthenticationManagementBase'; +import { AuthenticationManagementAction } from '../types'; +import { CheckUniqueService } from '../services/CheckUniqueService'; +import { IdentityChangeService } from '../services/IdentityChangeService'; +import { PasswordChangeService } from '../services/PasswordChangeService'; +import { ResendVerifySignupService } from '../services/ResendVerifySignupService'; +import { ResetPwdLongService } from '../services/ResetPwdLongService'; +import { ResetPwdShortService } from '../services/ResetPwdShortService'; +import { SendResetPwdService } from '../services/SendResetPwdService'; +import { VerifySignupLongService } from '../services/VerifySignupLongService'; +import { VerifySignupSetPasswordLongService } from '../services/VerifySignupSetPasswordLongService'; +import { VerifySignupSetPasswordShortService } from '../services/VerifySignupSetPasswordShortService'; +import { VerifySignupShortService } from '../services/VerifySignupShort'; + +const actionServiceClassMap: Record, Class>> = { + checkUnique: CheckUniqueService, + identityChange: IdentityChangeService, + passwordChange: PasswordChangeService, + resendVerifySignup: ResendVerifySignupService, + resetPwdLong: ResetPwdLongService, + resetPwdShort: ResetPwdShortService, + sendResetPwd: SendResetPwdService, + verifySignupLong: VerifySignupLongService, + verifySignupSetPasswordLong: VerifySignupSetPasswordLongService, + verifySignupSetPasswordShort: VerifySignupSetPasswordShortService, + verifySignupShort: VerifySignupShortService +}; + +export default actionServiceClassMap; diff --git a/src/helpers/clone-object.js b/src/helpers/clone-object.ts old mode 100755 new mode 100644 similarity index 63% rename from src/helpers/clone-object.js rename to src/helpers/clone-object.ts index 2ed6caf..2f11c33 --- a/src/helpers/clone-object.js +++ b/src/helpers/clone-object.ts @@ -1,6 +1,3 @@ - -module.exports = cloneObject; - /** * Returns new object with values cloned from the original object. Some objects * (like Sequelize or MongoDB model instances) contain circular references @@ -10,19 +7,20 @@ module.exports = cloneObject; * is to use result of custom toJSON() or toObject() (if accessible) * for Object.assign(), but only in case of serialization failure. * - * @param {Object?} obj - Object to clone - * @returns {Object} Cloned object + * @param obj - Object to clone + * @returns Cloned object */ -function cloneObject (obj) { - let obj1 = obj; - +export default function cloneObject> (obj: T): T { if (typeof obj.toJSON === 'function' || typeof obj.toObject === 'function') { try { - JSON.stringify(Object.assign({}, obj1)); + JSON.stringify(Object.assign({}, obj)); } catch (err) { - obj1 = obj1.toJSON ? obj1.toJSON() : obj1.toObject(); + return (typeof obj.toJSON === 'function') + ? obj.toJSON() + // @ts-expect-error does not know about toObject() + : obj.toObject(); } } - return Object.assign({}, obj1); + return Object.assign({}, obj); } diff --git a/src/helpers/compare-passwords.js b/src/helpers/compare-passwords.js deleted file mode 100755 index d095f88..0000000 --- a/src/helpers/compare-passwords.js +++ /dev/null @@ -1,12 +0,0 @@ - -const bcrypt = require('bcryptjs'); - -module.exports = comparePasswords; - -function comparePasswords (oldPassword, password, getError) { - return new Promise((resolve, reject) => { - bcrypt.compare(oldPassword, password, (err, data1) => - (err || !data1) ? reject(getError() || err) : resolve() - ); - }); -} diff --git a/src/helpers/compare-passwords.ts b/src/helpers/compare-passwords.ts new file mode 100644 index 0000000..5b524ef --- /dev/null +++ b/src/helpers/compare-passwords.ts @@ -0,0 +1,14 @@ + +import bcrypt from 'bcryptjs'; + +export default async function comparePasswords (oldPassword: string, password: string, getError?: () => unknown): Promise { + if (!getError) { + // eslint-disable-next-line @typescript-eslint/no-empty-function + getError = () => {}; + } + return await new Promise((resolve, reject) => { + bcrypt.compare(oldPassword, password, (err, data1) => + (err || !data1) ? reject(getError() ?? err) : resolve() + ); + }); +} diff --git a/src/helpers/concat-id-and-hash.js b/src/helpers/concat-id-and-hash.js deleted file mode 100755 index ddb48d5..0000000 --- a/src/helpers/concat-id-and-hash.js +++ /dev/null @@ -1,6 +0,0 @@ - -module.exports = concatIDAndHash; - -function concatIDAndHash (id, token) { - return `${id}___${token}`; -} diff --git a/src/helpers/concat-id-and-hash.ts b/src/helpers/concat-id-and-hash.ts new file mode 100644 index 0000000..aa27760 --- /dev/null +++ b/src/helpers/concat-id-and-hash.ts @@ -0,0 +1,5 @@ +import { Id } from '@feathersjs/feathers'; + +export default function concatIDAndHash (id: Id, token: string): string { + return `${id}___${token}`; +} diff --git a/src/helpers/deconstruct-id.js b/src/helpers/deconstruct-id.js deleted file mode 100755 index 3c2250a..0000000 --- a/src/helpers/deconstruct-id.js +++ /dev/null @@ -1,14 +0,0 @@ - -const errors = require('@feathersjs/errors'); - -module.exports = deconstructId; - -function deconstructId (token) { - if (!token.includes('___')) { - throw new errors.BadRequest('Token is not in the correct format.', - { errors: { $className: 'badParams' } } - ); - } - - return token.slice(0, token.indexOf('___')); -} diff --git a/src/helpers/deconstruct-id.ts b/src/helpers/deconstruct-id.ts new file mode 100644 index 0000000..b4b27e0 --- /dev/null +++ b/src/helpers/deconstruct-id.ts @@ -0,0 +1,12 @@ + +import { BadRequest } from '@feathersjs/errors'; + +export default function deconstructId (token: string): string { + if (!token.includes('___')) { + throw new BadRequest('Token is not in the correct format.', + { errors: { $className: 'badParams' } } + ); + } + + return token.slice(0, token.indexOf('___')); +} diff --git a/src/helpers/ensure-field-has-changed.js b/src/helpers/ensure-field-has-changed.js deleted file mode 100755 index d19bc85..0000000 --- a/src/helpers/ensure-field-has-changed.js +++ /dev/null @@ -1,12 +0,0 @@ - -const isNullsy = require('./is-nullsy'); - -module.exports = ensureFieldHasChanged; - -// Verify that obj1 and obj2 have different 'field' field -// Returns false if either object is null/undefined -function ensureFieldHasChanged (obj1, obj2) { - return isNullsy(obj1) || isNullsy(obj2) - ? () => false - : field => obj1[field] !== obj2[field]; -} diff --git a/src/helpers/ensure-field-has-changed.ts b/src/helpers/ensure-field-has-changed.ts new file mode 100644 index 0000000..4bff891 --- /dev/null +++ b/src/helpers/ensure-field-has-changed.ts @@ -0,0 +1,15 @@ + +import isNullsy from './is-nullsy'; + +/** + * Verify that obj1 and obj2 have different 'field' field + * Returns false if either object is null/undefined + * + * @param obj1 + * @param obj2 + */ +export default function ensureFieldHasChanged (obj1: Record, obj2: Record): (field: string) => boolean { + return (isNullsy(obj1) || isNullsy(obj2)) + ? () => false + : field => obj1[field] !== obj2[field]; +} diff --git a/src/helpers/ensure-has-all-keys.ts b/src/helpers/ensure-has-all-keys.ts new file mode 100644 index 0000000..19ffbd8 --- /dev/null +++ b/src/helpers/ensure-has-all-keys.ts @@ -0,0 +1,9 @@ +import { GeneralError } from '@feathersjs/errors'; + +export default function ensureHasAllKeys (obj: Record, keys: K[], identifier: string): void { + const missingKeys = keys.filter(key => !Object.prototype.hasOwnProperty.call(obj, key)); + + if (missingKeys.length) { + throw new GeneralError(`Missing keys: '${missingKeys.join(' ')}'! for ${identifier}`); + } +} diff --git a/src/helpers/ensure-obj-props-valid.js b/src/helpers/ensure-obj-props-valid.js deleted file mode 100755 index ba1da16..0000000 --- a/src/helpers/ensure-obj-props-valid.js +++ /dev/null @@ -1,15 +0,0 @@ - -const errors = require('@feathersjs/errors'); - -module.exports = ensureObjPropsValid; - -function ensureObjPropsValid (obj, props, allowNone) { - const keys = Object.keys(obj); - const valid = keys.every(key => props.includes(key) && typeof obj[key] === 'string'); - - if (!valid || (keys.length === 0 && !allowNone)) { - throw new errors.BadRequest('User info is not valid. (authLocalMgnt)', - { errors: { $className: 'badParams' } } - ); - } -} diff --git a/src/helpers/ensure-obj-props-valid.ts b/src/helpers/ensure-obj-props-valid.ts new file mode 100644 index 0000000..ab851cd --- /dev/null +++ b/src/helpers/ensure-obj-props-valid.ts @@ -0,0 +1,13 @@ + +import { BadRequest } from '@feathersjs/errors'; + +export default function ensureObjPropsValid (obj: Record, props: string[], allowNone?: boolean): void { + const keys = Object.keys(obj); + const valid = keys.every(key => props.includes(key) && typeof obj[key] === 'string'); + + if (!valid || (keys.length === 0 && !allowNone)) { + throw new BadRequest('User info is not valid. (authLocalMgnt)', + { errors: { $className: 'badParams' } } + ); + } +} diff --git a/src/helpers/ensure-values-are-strings.js b/src/helpers/ensure-values-are-strings.js deleted file mode 100755 index f360d80..0000000 --- a/src/helpers/ensure-values-are-strings.js +++ /dev/null @@ -1,12 +0,0 @@ - -const errors = require('@feathersjs/errors'); - -module.exports = ensureValuesAreStrings; - -function ensureValuesAreStrings (...rest) { - if (!rest.every(str => typeof str === 'string')) { - throw new errors.BadRequest('Expected string value. (authLocalMgnt)', - { errors: { $className: 'badParams' } } - ); - } -} diff --git a/src/helpers/ensure-values-are-strings.ts b/src/helpers/ensure-values-are-strings.ts new file mode 100644 index 0000000..883632d --- /dev/null +++ b/src/helpers/ensure-values-are-strings.ts @@ -0,0 +1,10 @@ + +import { BadRequest } from '@feathersjs/errors'; + +export default function ensureValuesAreStrings (...rest: string[]): void { + if (!rest.every(str => typeof str === 'string')) { + throw new BadRequest('Expected string value. (authLocalMgnt)', + { errors: { $className: 'badParams' } } + ); + } +} diff --git a/src/helpers/get-long-token.js b/src/helpers/get-long-token.js deleted file mode 100755 index 6349142..0000000 --- a/src/helpers/get-long-token.js +++ /dev/null @@ -1,4 +0,0 @@ - -const randomBytes = require('./random-bytes'); - -module.exports = len => randomBytes(len); diff --git a/src/helpers/get-long-token.ts b/src/helpers/get-long-token.ts new file mode 100644 index 0000000..8e420b5 --- /dev/null +++ b/src/helpers/get-long-token.ts @@ -0,0 +1,4 @@ + +import randomBytes from './random-bytes'; + +export default async (len: number): Promise => await randomBytes(len); diff --git a/src/helpers/get-short-token.js b/src/helpers/get-short-token.ts old mode 100755 new mode 100644 similarity index 60% rename from src/helpers/get-short-token.js rename to src/helpers/get-short-token.ts index 82ad3f4..0468bba --- a/src/helpers/get-short-token.js +++ b/src/helpers/get-short-token.ts @@ -1,10 +1,8 @@ -const randomBytes = require('./random-bytes'); -const randomDigits = require('./random-digits'); +import randomBytes from './random-bytes'; +import randomDigits from './random-digits'; -module.exports = getShortToken; - -async function getShortToken (len, ifDigits) { +export default async function getShortToken (len: number, ifDigits: boolean): Promise { if (ifDigits) { return randomDigits(len); } diff --git a/src/helpers/get-user-data.js b/src/helpers/get-user-data.ts old mode 100755 new mode 100644 similarity index 56% rename from src/helpers/get-user-data.js rename to src/helpers/get-user-data.ts index 5588b38..8b21ca6 --- a/src/helpers/get-user-data.js +++ b/src/helpers/get-user-data.ts @@ -1,46 +1,49 @@ - -const errors = require('@feathersjs/errors'); - -module.exports = getUserData; - -function getUserData (data, checks = []) { +import { BadRequest } from '@feathersjs/errors'; +import { + HookResult, + User +} from '../types'; + +export default function getUserData (data: HookResult, checks?: string[]): User { + checks = checks ?? []; if (Array.isArray(data) ? data.length === 0 : data.total === 0) { - throw new errors.BadRequest('User not found.', + throw new BadRequest('User not found.', { errors: { $className: 'badParams' } }); } - const users = Array.isArray(data) ? data : data.data || [ data ]; + const users = Array.isArray(data) ? data : data.data || [data]; const user = users[0]; + // @ts-expect-error does not know that it is an array if (users.length !== 1) { - throw new errors.BadRequest('More than 1 user selected.', + throw new BadRequest('More than 1 user selected.', { errors: { $className: 'badParams' } }); } if (checks.includes('isNotVerified') && user.isVerified) { - throw new errors.BadRequest('User is already verified.', + throw new BadRequest('User is already verified.', { errors: { $className: 'isNotVerified' } }); } if (checks.includes('isNotVerifiedOrHasVerifyChanges') && user.isVerified && !Object.keys(user.verifyChanges || {}).length ) { - throw new errors.BadRequest('User is already verified & not awaiting changes.', + throw new BadRequest('User is already verified & not awaiting changes.', { errors: { $className: 'nothingToVerify' } }); } if (checks.includes('isVerified') && !user.isVerified) { - throw new errors.BadRequest('User is not verified.', + throw new BadRequest('User is not verified.', { errors: { $className: 'isVerified' } }); } if (checks.includes('verifyNotExpired') && user.verifyExpires < Date.now()) { - throw new errors.BadRequest('Verification token has expired.', + throw new BadRequest('Verification token has expired.', { errors: { $className: 'verifyExpired' } }); } if (checks.includes('resetNotExpired') && user.resetExpires < Date.now()) { - throw new errors.BadRequest('Password reset token has expired.', + throw new BadRequest('Password reset token has expired.', { errors: { $className: 'resetExpired' } }); } diff --git a/src/helpers/hash-password.js b/src/helpers/hash-password.js deleted file mode 100755 index fcccb2e..0000000 --- a/src/helpers/hash-password.js +++ /dev/null @@ -1,15 +0,0 @@ -const auth = require('@feathersjs/authentication-local').hooks; - -module.exports = hashPassword; - -async function hashPassword (app, password, field) { - if (!field) throw new Error('Field is missing'); - const context = { - type: 'before', - data: { [field]: password }, - params: { provider: null }, - app - }; - const newContext = await auth.hashPassword(field)(context); - return newContext.data[field]; -} diff --git a/src/helpers/hash-password.ts b/src/helpers/hash-password.ts new file mode 100644 index 0000000..348b366 --- /dev/null +++ b/src/helpers/hash-password.ts @@ -0,0 +1,14 @@ +import { hooks as authLocalHooks } from '@feathersjs/authentication-local'; +import { Application, HookContext } from '@feathersjs/feathers'; + +export default async function hashPassword (app: Application, password: string, field: string): Promise { + if (!field) throw new Error('Field is missing'); + const context = { + type: 'before', + data: { [field]: password }, + params: { provider: null }, + app + }; + const newContext = await authLocalHooks.hashPassword(field)(context as HookContext); + return newContext.data[field]; +} diff --git a/src/helpers/index.js b/src/helpers/index.js deleted file mode 100755 index 1f03984..0000000 --- a/src/helpers/index.js +++ /dev/null @@ -1,38 +0,0 @@ - -const cloneObject = require('./clone-object'); -const comparePasswords = require('./compare-passwords'); -const concatIDAndHash = require('./concat-id-and-hash'); -const deconstructId = require('./deconstruct-id'); -const ensureFieldHasChanged = require('./ensure-field-has-changed'); -const ensureObjPropsValid = require('./ensure-obj-props-valid'); -const ensureValuesAreStrings = require('./ensure-values-are-strings'); -const getLongToken = require('./get-long-token'); -const getShortToken = require('./get-short-token'); -const getUserData = require('./get-user-data'); -const hashPassword = require('./hash-password'); -const isNullsy = require('./is-nullsy'); -const notifier = require('./notifier'); -const randomBytes = require('./random-bytes'); -const randomDigits = require('./random-digits'); -const sanitizeUserForClient = require('./sanitize-user-for-client'); -const sanitizeUserForNotifier = require('./sanitize-user-for-notifier'); - -module.exports = { - cloneObject, - comparePasswords, - concatIDAndHash, - deconstructId, - ensureFieldHasChanged, - ensureObjPropsValid, - ensureValuesAreStrings, - getLongToken, - getShortToken, - getUserData, - hashPassword, - isNullsy, - notifier, - randomBytes: (...args) => randomBytes(...args), // for testing, make safe from hacking - randomDigits: (...args) => randomDigits(...args), // for testing, make safe from hacking - sanitizeUserForClient, - sanitizeUserForNotifier -}; diff --git a/src/helpers/index.ts b/src/helpers/index.ts new file mode 100644 index 0000000..b6d5588 --- /dev/null +++ b/src/helpers/index.ts @@ -0,0 +1,65 @@ + +import cloneObject from './clone-object'; +import comparePasswords from './compare-passwords'; +import concatIDAndHash from './concat-id-and-hash'; +import deconstructId from './deconstruct-id'; +import ensureFieldHasChanged from './ensure-field-has-changed'; +import ensureObjPropsValid from './ensure-obj-props-valid'; +import ensureValuesAreStrings from './ensure-values-are-strings'; +import getLongToken from './get-long-token'; +import getShortToken from './get-short-token'; +import getUserData from './get-user-data'; +import hashPassword from './hash-password'; +import isNullsy from './is-nullsy'; +import notifier from './notifier'; +import randomBytes from './random-bytes'; +import randomDigits from './random-digits'; +import sanitizeUserForClient from './sanitize-user-for-client'; +import sanitizeUserForNotifier from './sanitize-user-for-notifier'; + +const helpers = { + cloneObject, + comparePasswords, + concatIDAndHash, + deconstructId, + ensureFieldHasChanged, + ensureObjPropsValid, + ensureValuesAreStrings, + getLongToken, + getShortToken, + getUserData, + hashPassword, + isNullsy, + notifier, + randomBytes, // for testing, make safe from hacking + randomDigits, // for testing, make safe from hacking + sanitizeUserForClient, + sanitizeUserForNotifier +}; + +export { + cloneObject, + comparePasswords, + concatIDAndHash, + deconstructId, + ensureFieldHasChanged, + ensureObjPropsValid, + ensureValuesAreStrings, + getLongToken, + getShortToken, + getUserData, + hashPassword, + isNullsy, + notifier, + randomBytes, // for testing, make safe from hacking + randomDigits, // for testing, make safe from hacking + sanitizeUserForClient, + sanitizeUserForNotifier +}; + +export default helpers; + +// commonjs +if (typeof module !== 'undefined') { + module.exports = Object.assign(helpers, module.exports); +} diff --git a/src/helpers/is-date-after-now.ts b/src/helpers/is-date-after-now.ts new file mode 100644 index 0000000..90d271b --- /dev/null +++ b/src/helpers/is-date-after-now.ts @@ -0,0 +1,5 @@ +export default function isDateAfterNow (date: number | Date): boolean { + if (date instanceof Date) date = date.getTime(); + + return date > Date.now(); +} diff --git a/src/helpers/is-nullsy.js b/src/helpers/is-nullsy.js deleted file mode 100755 index 15f6b04..0000000 --- a/src/helpers/is-nullsy.js +++ /dev/null @@ -1,6 +0,0 @@ - -module.exports = isNullsy; - -function isNullsy (obj) { - return obj === null || obj === undefined; -} diff --git a/src/helpers/is-nullsy.ts b/src/helpers/is-nullsy.ts new file mode 100644 index 0000000..8317d04 --- /dev/null +++ b/src/helpers/is-nullsy.ts @@ -0,0 +1,3 @@ +export default function isNullsy (obj: unknown): boolean { + return obj === null || obj === undefined; +} diff --git a/src/helpers/notifier.js b/src/helpers/notifier.js deleted file mode 100755 index eabb19f..0000000 --- a/src/helpers/notifier.js +++ /dev/null @@ -1,13 +0,0 @@ - -const makeDebug = require('debug'); -const sanitizeUserForNotifier = require('./sanitize-user-for-notifier'); - -const debug = makeDebug('authLocalMgnt:notifier'); - -module.exports = notifier; - -async function notifier (optionsNotifier, type, user, notifierOptions) { - debug('notifier', type); - await optionsNotifier(type, sanitizeUserForNotifier(user), notifierOptions || {}); - return user; -} diff --git a/src/helpers/notifier.ts b/src/helpers/notifier.ts new file mode 100644 index 0000000..2fdb9a6 --- /dev/null +++ b/src/helpers/notifier.ts @@ -0,0 +1,12 @@ +import makeDebug from 'debug'; +import { User, Notifier, NotificationType } from '../types'; +import sanitizeUserForNotifier from './sanitize-user-for-notifier'; + +const debug = makeDebug('authLocalMgnt:notifier'); + +// TODO: notifierOptions +export default async function notifier (optionsNotifier: Notifier, type: NotificationType, user: User, notifierOptions: Record): Promise { + debug('notifier', type); + await optionsNotifier(type, sanitizeUserForNotifier(user), notifierOptions || {}); + return user; +} diff --git a/src/helpers/random-bytes.js b/src/helpers/random-bytes.js deleted file mode 100755 index 53a46f6..0000000 --- a/src/helpers/random-bytes.js +++ /dev/null @@ -1,10 +0,0 @@ - -const crypto = require('crypto'); - -module.exports = randomBytes; - -function randomBytes (len) { - return new Promise((resolve, reject) => { - crypto.randomBytes(len, (err, buf) => err ? reject(err) : resolve(buf.toString('hex'))); - }); -} diff --git a/src/helpers/random-bytes.ts b/src/helpers/random-bytes.ts new file mode 100644 index 0000000..5fd076e --- /dev/null +++ b/src/helpers/random-bytes.ts @@ -0,0 +1,7 @@ +import crypto from 'crypto'; + +export default async function randomBytes (len: number): Promise { + return await new Promise((resolve, reject) => { + crypto.randomBytes(len, (err, buf) => err ? reject(err) : resolve(buf.toString('hex'))); + }); +} diff --git a/src/helpers/random-digits.js b/src/helpers/random-digits.ts old mode 100755 new mode 100644 similarity index 62% rename from src/helpers/random-digits.js rename to src/helpers/random-digits.ts index 213d6ec..478905d --- a/src/helpers/random-digits.js +++ b/src/helpers/random-digits.ts @@ -1,9 +1,6 @@ +import crypto from 'crypto'; -const crypto = require('crypto'); - -module.exports = randomDigits; - -function randomDigits (len) { +export default function randomDigits (len: number): string { let str = ''; while (str.length < len) { diff --git a/src/helpers/sanitize-user-for-client.js b/src/helpers/sanitize-user-for-client.ts old mode 100755 new mode 100644 similarity index 54% rename from src/helpers/sanitize-user-for-client.js rename to src/helpers/sanitize-user-for-client.ts index 8291d55..069b9bb --- a/src/helpers/sanitize-user-for-client.js +++ b/src/helpers/sanitize-user-for-client.ts @@ -1,10 +1,11 @@ -const cloneObject = require('./clone-object'); +import cloneObject from './clone-object'; +import { + User +} from '../types'; -module.exports = sanitizeUserForClient; - -function sanitizeUserForClient (user1) { - const user = cloneObject(user1); +export default function sanitizeUserForClient (user1: User): Record { + const user = cloneObject(user1); delete user.password; delete user.verifyExpires; diff --git a/src/helpers/sanitize-user-for-notifier.js b/src/helpers/sanitize-user-for-notifier.js deleted file mode 100755 index a92f269..0000000 --- a/src/helpers/sanitize-user-for-notifier.js +++ /dev/null @@ -1,10 +0,0 @@ - -const cloneObject = require('./clone-object'); - -module.exports = sanitizeUserForNotifier; - -function sanitizeUserForNotifier (user1) { - const user = cloneObject(user1); - delete user.password; - return user; -} diff --git a/src/helpers/sanitize-user-for-notifier.ts b/src/helpers/sanitize-user-for-notifier.ts new file mode 100644 index 0000000..9be38a7 --- /dev/null +++ b/src/helpers/sanitize-user-for-notifier.ts @@ -0,0 +1,12 @@ + +import cloneObject from './clone-object'; + +import { + User +} from '../types'; + +export default function sanitizeUserForNotifier (user1: User): Record { + const user = cloneObject(user1); + delete user.password; + return user; +} diff --git a/src/hooks/add-verification.js b/src/hooks/add-verification.js deleted file mode 100755 index b82f52a..0000000 --- a/src/hooks/add-verification.js +++ /dev/null @@ -1,44 +0,0 @@ - -const errors = require('@feathersjs/errors'); -const { checkContext } = require('feathers-hooks-common'); -const { getLongToken, getShortToken, ensureFieldHasChanged } = require('../helpers'); - -module.exports = addVerification; - -function addVerification (path) { - return hook => { - checkContext(hook, 'before', ['create', 'patch', 'update']); - - return Promise.resolve() - .then(() => hook.app.service(path || 'authManagement').create({ action: 'options' })) - .then(options => Promise.all([ - options, - getLongToken(options.longTokenLen), - getShortToken(options.shortTokenLen, options.shortTokenDigits) - ])) - .then(([options, longToken, shortToken]) => { - // We do NOT add verification fields if the 3 following conditions are fulfilled: - // - hook is PATCH or PUT - // - user is authenticated - // - user's identifyUserProps fields did not change - if ( - (hook.method === 'patch' || hook.method === 'update') && - !!hook.params.user && - !options.identifyUserProps.some(ensureFieldHasChanged(hook.data, hook.params.user)) - ) { - return hook; - } - - hook.data.isVerified = false; - hook.data.verifyExpires = Date.now() + options.delay; - hook.data.verifyToken = longToken; - hook.data.verifyShortToken = shortToken; - hook.data.verifyChanges = {}; - - return hook; - }) - .catch(err => { - throw new errors.GeneralError(err); - }); - }; -} diff --git a/src/hooks/add-verification.ts b/src/hooks/add-verification.ts new file mode 100644 index 0000000..f65266b --- /dev/null +++ b/src/hooks/add-verification.ts @@ -0,0 +1,43 @@ +import { GeneralError } from '@feathersjs/errors'; +import { HookContext } from '@feathersjs/feathers'; +import { checkContext } from 'feathers-hooks-common'; +import getLongToken from '../helpers/get-long-token'; +import getShortToken from '../helpers/get-short-token'; +import ensureFieldHasChanged from '../helpers/ensure-field-has-changed'; +import { AuthenticationManagementService } from '../services'; +import { defaultConfigureOptions } from '../configureAuthManagement'; + +export default function addVerification (path?: string): ((hook: HookContext) => Promise) { + path = path || defaultConfigureOptions.path; // default: 'authManagement' + return async (hook: HookContext): Promise => { + checkContext(hook, 'before', ['create', 'patch', 'update']); + + try { + const { options } = (hook.app.service(path) as AuthenticationManagementService); + + const [longToken, shortToken] = await Promise.all([ + getLongToken(options.longTokenLen), + getShortToken(options.shortTokenLen, options.shortTokenDigits) + ]); + + if ( + (hook.method === 'patch' || hook.method === 'update') && + !!hook.params.user && + !options.identifyUserProps.some(ensureFieldHasChanged(hook.data, hook.params.user)) + ) { + return hook; + } + + hook.data.isVerified = false; + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + hook.data.verifyExpires = Date.now() + options.delay; + hook.data.verifyToken = longToken; + hook.data.verifyShortToken = shortToken; + hook.data.verifyChanges = {}; + + return hook; + } catch (err) { + throw new GeneralError(err); + } + }; +} diff --git a/src/hooks/index.js b/src/hooks/index.js deleted file mode 100755 index 2d88574..0000000 --- a/src/hooks/index.js +++ /dev/null @@ -1,10 +0,0 @@ - -const addVerification = require('./add-verification'); -const isVerified = require('./is-verified'); -const removeVerification = require('./remove-verification'); - -module.exports = { - addVerification, - isVerified, - removeVerification -}; diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..d8bb2df --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,23 @@ + +import addVerification from './add-verification'; +import isVerified from './is-verified'; +import removeVerification from './remove-verification'; + +const hooks = { + addVerification, + isVerified, + removeVerification +}; + +export { + addVerification, + isVerified, + removeVerification +}; + +export default hooks; + +// commonjs +if (typeof module !== 'undefined') { + module.exports = Object.assign(hooks, module.exports); +} diff --git a/src/hooks/is-verified.js b/src/hooks/is-verified.js deleted file mode 100755 index 9adbe48..0000000 --- a/src/hooks/is-verified.js +++ /dev/null @@ -1,15 +0,0 @@ - -const errors = require('@feathersjs/errors'); -const { checkContext } = require('feathers-hooks-common'); - -module.exports = isVerified; - -function isVerified () { - return hook => { - checkContext(hook, 'before'); - - if (!hook.params.user || !hook.params.user.isVerified) { - throw new errors.BadRequest('User\'s email is not yet verified.'); - } - }; -} diff --git a/src/hooks/is-verified.ts b/src/hooks/is-verified.ts new file mode 100644 index 0000000..bd50fdb --- /dev/null +++ b/src/hooks/is-verified.ts @@ -0,0 +1,15 @@ + +import { BadRequest } from '@feathersjs/errors'; +import { HookContext } from '@feathersjs/feathers'; +import { checkContext } from 'feathers-hooks-common'; + +export default function isVerified (): ((hook: HookContext) => HookContext) { + return (hook: HookContext): HookContext => { + checkContext(hook, 'before'); + + if (!hook.params?.user?.isVerified) { + throw new BadRequest('User\'s email is not yet verified.'); + } + return hook; + }; +} diff --git a/src/hooks/remove-verification.js b/src/hooks/remove-verification.ts old mode 100755 new mode 100644 similarity index 66% rename from src/hooks/remove-verification.js rename to src/hooks/remove-verification.ts index c76dc41..ecdfc9c --- a/src/hooks/remove-verification.js +++ b/src/hooks/remove-verification.ts @@ -1,16 +1,18 @@ +import { HookContext } from '@feathersjs/feathers'; -const { checkContext, getItems, replaceItems } = require('feathers-hooks-common'); +import { checkContext, getItems, replaceItems } from 'feathers-hooks-common'; +import { User } from '../types'; -module.exports = removeVerification; - -function removeVerification (ifReturnTokens) { - return hook => { +export default function removeVerification ( + ifReturnTokens?: boolean +): ((hook: HookContext) => HookContext) { + return (hook: HookContext): HookContext => { checkContext(hook, 'after'); // Retrieve the items from the hook - let users = getItems(hook); - if (!users) return; - const isArray = Array.isArray(users); - users = (isArray ? users : [users]); + const items: User | User[] = getItems(hook); + if (!items) return; + const isArray = Array.isArray(items); + const users = ((isArray) ? items : [items]) as User[]; users.forEach(user => { if (!('isVerified' in user) && hook.method === 'create') { @@ -35,5 +37,6 @@ function removeVerification (ifReturnTokens) { }); // Replace the items within the hook replaceItems(hook, isArray ? users : users[0]); + return hook; }; } diff --git a/src/identity-change.js b/src/identity-change.js deleted file mode 100755 index 044ad1f..0000000 --- a/src/identity-change.js +++ /dev/null @@ -1,44 +0,0 @@ - -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); -const comparePasswords = require('./helpers/compare-passwords'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const getLongToken = require('./helpers/get-long-token'); -const getShortToken = require('./helpers/get-short-token'); -const getUserData = require('./helpers/get-user-data'); -const notifier = require('./helpers/notifier'); - -const debug = makeDebug('authLocalMgnt:identityChange'); - -module.exports = identityChange; - -async function identityChange (options, identifyUser, password, changesIdentifyUser, notifierOptions = {}) { - // note this call does not update the authenticated user info in hooks.params.user. - debug('identityChange', password, changesIdentifyUser); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - - ensureObjPropsValid(identifyUser, options.identifyUserProps); - ensureObjPropsValid(changesIdentifyUser, options.identifyUserProps); - - const users = await usersService.find({ query: identifyUser }); - const user1 = getUserData(users); - - try { - await comparePasswords(password, user1.password, () => {}); - } catch (err) { - throw new errors.BadRequest('Password is incorrect.', - { errors: { password: 'Password is incorrect.', $className: 'badParams' } } - ); - } - - const user2 = await usersService.patch(user1[usersServiceIdName], { - verifyExpires: Date.now() + options.delay, - verifyToken: await getLongToken(options.longTokenLen), - verifyShortToken: await getShortToken(options.shortTokenLen, options.shortTokenDigits), - verifyChanges: changesIdentifyUser - }); - - const user3 = await notifier(options.notifier, 'identityChange', user2, notifierOptions); - return options.sanitizeUserForClient(user3); -} diff --git a/src/index.js b/src/index.js deleted file mode 100755 index 7f8c504..0000000 --- a/src/index.js +++ /dev/null @@ -1,6 +0,0 @@ - -const service = require('./service'); -const hooks = require('./hooks'); - -service.hooks = hooks; -module.exports = service; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..037b9df --- /dev/null +++ b/src/index.ts @@ -0,0 +1,26 @@ +import configure from './configureAuthManagement'; +import hooks from './hooks'; + +// @ts-expect-error assign object to a function +configure.hooks = hooks; + +export default configure; +export { hooks }; + +export { AuthenticationManagementService } from './services/AuthenticationManagementService'; +export { CheckUniqueService } from './services/CheckUniqueService'; +export { IdentityChangeService } from './services/IdentityChangeService'; +export { PasswordChangeService } from './services/PasswordChangeService'; +export { ResendVerifySignupService } from './services/ResendVerifySignupService'; +export { ResetPwdLongService } from './services/ResetPwdLongService'; +export { ResetPwdShortService } from './services/ResetPwdShortService'; +export { SendResetPwdService } from './services/SendResetPwdService'; +export { VerifySignupLongService } from './services/VerifySignupLongService'; +export { VerifySignupSetPasswordLongService } from './services/VerifySignupSetPasswordLongService'; +export { VerifySignupSetPasswordShortService } from './services/VerifySignupSetPasswordShortService'; +export { VerifySignupShortService } from './services/VerifySignupShort'; + +// commonjs +if (typeof module !== 'undefined') { + module.exports = Object.assign(configure, module.exports); +} diff --git a/src/check-unique.js b/src/methods/check-unique.ts old mode 100755 new mode 100644 similarity index 61% rename from src/check-unique.js rename to src/methods/check-unique.ts index ddbaeca..0ef3c65 --- a/src/check-unique.js +++ b/src/methods/check-unique.ts @@ -1,48 +1,58 @@ - -const errors = require('@feathersjs/errors'); -const isNullsy = require('./helpers/is-nullsy'); -const makeDebug = require('debug'); - -const debug = makeDebug('authLocalMgnt:checkUnique'); - -module.exports = checkUnique; - -// This module is usually called from the UI to check username, email, etc. are unique. -async function checkUnique (options, identifyUser, ownId, meta) { - debug('checkUnique', identifyUser, ownId, meta); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - const allProps = []; - - const keys = Object.keys(identifyUser).filter( - key => !isNullsy(identifyUser[key]) - ); - - try { - for (let i = 0, ilen = keys.length; i < ilen; i++) { - const prop = keys[i]; - const users = await usersService.find({ query: { [prop]: identifyUser[prop].trim() } }); - const items = Array.isArray(users) ? users : users.data; - const isNotUnique = items.length > 1 || - (items.length === 1 && items[0][usersServiceIdName] !== ownId); - allProps.push(isNotUnique ? prop : null); - } - } catch (err) { - throw new errors.BadRequest(meta.noErrMsg ? null : 'checkUnique unexpected error.', - { errors: { msg: err.message, $className: 'unexpected' } } - ); - } - - const errProps = allProps.filter(prop => prop); - - if (errProps.length) { - const errs = {}; - errProps.forEach(prop => { errs[prop] = 'Already taken.'; }); - - throw new errors.BadRequest(meta.noErrMsg ? null : 'Values already taken.', - { errors: errs } - ); - } - - return null; -} +import { BadRequest } from '@feathersjs/errors'; +import isNullsy from '../helpers/is-nullsy'; +import makeDebug from 'debug'; +import { Id } from '@feathersjs/feathers'; +import { CheckUniqueOptions, IdentifyUser } from '../types'; + +const debug = makeDebug('authLocalMgnt:checkUnique'); + +/** + * This module is usually called from the UI to check username, email, etc. are unique. + */ +export default async function checkUnique ( + options: CheckUniqueOptions, + identifyUser: IdentifyUser, + ownId?: Id, + meta?: { noErrMsg?: boolean} +): Promise { + debug('checkUnique', identifyUser, ownId, meta); + + ownId = ownId || null; + meta = meta || {}; + + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + const allProps = []; + + const keys = Object.keys(identifyUser).filter( + key => !isNullsy(identifyUser[key]) + ); + + try { + for (let i = 0, ilen = keys.length; i < ilen; i++) { + const prop = keys[i]; + const users = await usersService.find({ query: { [prop]: identifyUser[prop].trim() } }); + const items = Array.isArray(users) ? users : users.data; + const isNotUnique = items.length > 1 || + (items.length === 1 && items[0][usersServiceIdName] !== ownId); + allProps.push(isNotUnique ? prop : null); + } + } catch (err) { + throw new BadRequest(meta.noErrMsg ? null : 'checkUnique unexpected error.', + { errors: { msg: err.message, $className: 'unexpected' } } + ); + } + + const errProps = allProps.filter(prop => prop); + + if (errProps.length) { + const errs = {}; + errProps.forEach(prop => { errs[prop] = 'Already taken.'; }); + + throw new BadRequest(meta.noErrMsg ? null : 'Values already taken.', + { errors: errs } + ); + } + + return null; +} diff --git a/src/methods/identity-change.ts b/src/methods/identity-change.ts new file mode 100644 index 0000000..3e59d6d --- /dev/null +++ b/src/methods/identity-change.ts @@ -0,0 +1,59 @@ + +import { BadRequest } from '@feathersjs/errors'; +import makeDebug from 'debug'; +import comparePasswords from '../helpers/compare-passwords'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import getLongToken from '../helpers/get-long-token'; +import getShortToken from '../helpers/get-short-token'; +import getUserData from '../helpers/get-user-data'; +import notifier from '../helpers/notifier'; +import { IdentifyUser, IdentityChangeOptions, SanitizedUser } from '../types'; + +const debug = makeDebug('authLocalMgnt:identityChange'); + +// TODO: identifyUser + +export default async function identityChange ( + options: IdentityChangeOptions, + identifyUser: IdentifyUser, + password: string, + changesIdentifyUser: Record, + notifierOptions: Record = {} +): Promise { + // note this call does not update the authenticated user info in hooks.params.user. + debug('identityChange', password, changesIdentifyUser); + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + const { + delay, + identifyUserProps, + longTokenLen, + shortTokenLen, + shortTokenDigits, + passwordField + } = options; + + ensureObjPropsValid(identifyUser, identifyUserProps); + ensureObjPropsValid(changesIdentifyUser, identifyUserProps); + + const users = await usersService.find({ query: identifyUser }); + const user1 = getUserData(users); + + try { + await comparePasswords(password, user1[passwordField] as string); + } catch (err) { + throw new BadRequest('Password is incorrect.', + { errors: { [passwordField]: 'Password is incorrect.', $className: 'badParams' } } + ); + } + + const user2 = await usersService.patch(user1[usersServiceIdName], { + verifyExpires: Date.now() + delay, + verifyToken: await getLongToken(longTokenLen), + verifyShortToken: await getShortToken(shortTokenLen, shortTokenDigits), + verifyChanges: changesIdentifyUser + }); + + const user3 = await notifier(options.notifier, 'identityChange', user2, notifierOptions); + return options.sanitizeUserForClient(user3); +} diff --git a/src/methods/password-change.ts b/src/methods/password-change.ts new file mode 100644 index 0000000..d8e59b2 --- /dev/null +++ b/src/methods/password-change.ts @@ -0,0 +1,45 @@ + +import { BadRequest } from '@feathersjs/errors'; +import makeDebug from 'debug'; +import comparePasswords from '../helpers/compare-passwords'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import ensureValuesAreStrings from '../helpers/ensure-values-are-strings'; +import getUserData from '../helpers/get-user-data'; +import hashPassword from '../helpers/hash-password'; +import notifier from '../helpers/notifier'; +import { IdentifyUser, PasswordChangeOptions, SanitizedUser } from '../types'; + +const debug = makeDebug('authLocalMgnt:passwordChange'); + +export default async function passwordChange ( + options: PasswordChangeOptions, + identifyUser: IdentifyUser, + oldPassword: string, + password: string, + notifierOptions = {} +): Promise { + debug('passwordChange', oldPassword, password); + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + + ensureValuesAreStrings(oldPassword, password); + ensureObjPropsValid(identifyUser, options.identifyUserProps); + + const users = await usersService.find({ query: identifyUser }); + const user1 = getUserData(users); + + try { + await comparePasswords(oldPassword, user1.password); + } catch (err) { + throw new BadRequest('Current password is incorrect.', { + errors: { oldPassword: 'Current password is incorrect.' } + }); + } + + const user2 = await usersService.patch(user1[usersServiceIdName], { + password: await hashPassword(options.app, password, options.passwordField) + }); + + const user3 = await notifier(options.notifier, 'passwordChange', user2, notifierOptions); + return options.sanitizeUserForClient(user3); +} diff --git a/src/resend-verify-signup.js b/src/methods/resend-verify-signup.ts old mode 100755 new mode 100644 similarity index 63% rename from src/resend-verify-signup.js rename to src/methods/resend-verify-signup.ts index aa7365b..ab9d898 --- a/src/resend-verify-signup.js +++ b/src/methods/resend-verify-signup.ts @@ -1,34 +1,38 @@ - -const makeDebug = require('debug'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const getLongToken = require('./helpers/get-long-token'); -const getShortToken = require('./helpers/get-short-token'); -const getUserData = require('./helpers/get-user-data'); -const notifier = require('./helpers/notifier'); - -const debug = makeDebug('authLocalMgnt:resendVerifySignup'); - -// {email}, {cellphone}, {verifyToken}, {verifyShortToken}, -// {email, cellphone, verifyToken, verifyShortToken} -module.exports = async function resendVerifySignup (options, identifyUser, notifierOptions) { - debug('identifyUser=', identifyUser); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - - ensureObjPropsValid(identifyUser, - options.identifyUserProps.concat('verifyToken', 'verifyShortToken') - ); - - const users = await usersService.find({ query: identifyUser }); - const user1 = getUserData(users, ['isNotVerified']); - - const user2 = await usersService.patch(user1[usersServiceIdName], { - isVerified: false, - verifyExpires: Date.now() + options.delay, - verifyToken: await getLongToken(options.longTokenLen), - verifyShortToken: await getShortToken(options.shortTokenLen, options.shortTokenDigits) - }); - - const user3 = await notifier(options.notifier, 'resendVerifySignup', user2, notifierOptions); - return options.sanitizeUserForClient(user3); -}; +import makeDebug from 'debug'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import getLongToken from '../helpers/get-long-token'; +import getShortToken from '../helpers/get-short-token'; +import getUserData from '../helpers/get-user-data'; +import notifier from '../helpers/notifier'; +import { IdentifyUser, ResendVerifySignupOptions, SanitizedUser } from '../types'; + +const debug = makeDebug('authLocalMgnt:resendVerifySignup'); + +// {email}, {cellphone}, {verifyToken}, {verifyShortToken}, +// {email, cellphone, verifyToken, verifyShortToken} +export default async function resendVerifySignup ( + options: ResendVerifySignupOptions, + identifyUser: IdentifyUser, + notifierOptions: Record +): Promise { + debug('identifyUser=', identifyUser); + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + + ensureObjPropsValid(identifyUser, + options.identifyUserProps.concat('verifyToken', 'verifyShortToken') + ); + + const users = await usersService.find({ query: identifyUser }); + const user1 = getUserData(users, ['isNotVerified']); + + const user2 = await usersService.patch(user1[usersServiceIdName], { + isVerified: false, + verifyExpires: Date.now() + options.delay, + verifyToken: await getLongToken(options.longTokenLen), + verifyShortToken: await getShortToken(options.shortTokenLen, options.shortTokenDigits) + }); + + const user3 = await notifier(options.notifier, 'resendVerifySignup', user2, notifierOptions); + return options.sanitizeUserForClient(user3); +} diff --git a/src/methods/reset-password.ts b/src/methods/reset-password.ts new file mode 100644 index 0000000..b7665f4 --- /dev/null +++ b/src/methods/reset-password.ts @@ -0,0 +1,118 @@ +import { BadRequest } from '@feathersjs/errors'; +import { Query } from '@feathersjs/feathers'; +import makeDebug from 'debug'; +import comparePasswords from '../helpers/compare-passwords'; +import deconstructId from '../helpers/deconstruct-id'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import ensureValuesAreStrings from '../helpers/ensure-values-are-strings'; +import getUserData from '../helpers/get-user-data'; +import hashPassword from '../helpers/hash-password'; +import notifier from '../helpers/notifier'; +import { HookResult, IdentifyUser, ResetPasswordOptions, ResetPwdWithShortTokenOptions, SanitizedUser, Tokens } from '../types'; + +const debug = makeDebug('authLocalMgnt:resetPassword'); + +export async function resetPwdWithLongToken ( + options: ResetPasswordOptions, + resetToken: string, + password: string, + notifierOptions = {} +): Promise { + ensureValuesAreStrings(resetToken, password); + + return await resetPassword(options, { resetToken }, { resetToken }, password, notifierOptions); +} + +export async function resetPwdWithShortToken ( + options: ResetPwdWithShortTokenOptions, + resetShortToken: string, + identifyUser: IdentifyUser, + password: string, + notifierOptions = {} +): Promise { + ensureValuesAreStrings(resetShortToken, password); + ensureObjPropsValid(identifyUser, options.identifyUserProps); + + return await resetPassword(options, identifyUser, { resetShortToken }, password, notifierOptions); +} + +async function resetPassword ( + options: ResetPasswordOptions, + query: Query, + tokens: Tokens, + password: string, + notifierOptions = {} +): Promise { + debug('resetPassword', query, tokens, password); + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + let users: HookResult; + + if (tokens.resetToken) { + const id = deconstructId(tokens.resetToken); + users = await usersService.get(id); + } else if (tokens.resetShortToken) { + users = await usersService.find({ query }); + } else { + throw new BadRequest('resetToken and resetShortToken are missing. (authLocalMgnt)', { + errors: { $className: 'missingToken' } + }); + } + + const checkProps = options.skipIsVerifiedCheck ? ['resetNotExpired'] : ['resetNotExpired', 'isVerified']; + const user1 = getUserData(users, checkProps); + + const tokenChecks = Object.keys(tokens).map(async key => { + if (options.reuseResetToken) { + // Comparing token directly as reused resetToken is not hashed + if (tokens[key] !== user1[key]) { + throw new BadRequest('Reset Token is incorrect. (authLocalMgnt)', { + errors: { $className: 'incorrectToken' } + }); + } + } else { + return await comparePasswords( + tokens[key], + user1[key] as string, + () => + new BadRequest('Reset Token is incorrect. (authLocalMgnt)', { + errors: { $className: 'incorrectToken' } + }) + ); + } + }); + + try { + await Promise.all(tokenChecks); + } catch (err) { + if (user1.resetAttempts > 0) { + await usersService.patch(user1[usersServiceIdName], { + resetAttempts: user1.resetAttempts - 1 + }); + + throw err; + } else { + await usersService.patch(user1[usersServiceIdName], { + resetToken: null, + resetAttempts: null, + resetShortToken: null, + resetExpires: null + }); + + throw new BadRequest('Invalid token. Get for a new one. (authLocalMgnt)', { + errors: { $className: 'invalidToken' } + }); + } + } + + const user2 = await usersService.patch(user1[usersServiceIdName], { + password: await hashPassword(options.app, password, options.passwordField), + resetExpires: null, + resetAttempts: null, + resetToken: null, + resetShortToken: null + }); + + const user3 = await notifier(options.notifier, 'resetPwd', user2, notifierOptions); + return options.sanitizeUserForClient(user3); +} diff --git a/src/send-reset-pwd.js b/src/methods/send-reset-pwd.ts old mode 100755 new mode 100644 similarity index 62% rename from src/send-reset-pwd.js rename to src/methods/send-reset-pwd.ts index 54206ed..c065bf0 --- a/src/send-reset-pwd.js +++ b/src/methods/send-reset-pwd.ts @@ -1,17 +1,21 @@ -const makeDebug = require('debug'); -const concatIDAndHash = require('./helpers/concat-id-and-hash'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const getLongToken = require('./helpers/get-long-token'); -const getShortToken = require('./helpers/get-short-token'); -const getUserData = require('./helpers/get-user-data'); -const hashPassword = require('./helpers/hash-password'); -const notifier = require('./helpers/notifier'); +import makeDebug from 'debug'; +import concatIDAndHash from '../helpers/concat-id-and-hash'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import getLongToken from '../helpers/get-long-token'; +import getShortToken from '../helpers/get-short-token'; +import getUserData from '../helpers/get-user-data'; +import hashPassword from '../helpers/hash-password'; +import notifier from '../helpers/notifier'; +import { Id } from '@feathersjs/feathers'; +import { IdentifyUser, SanitizedUser, SendResetPwdOptions } from '../types'; const debug = makeDebug('authLocalMgnt:sendResetPwd'); -module.exports = sendResetPwd; - -async function sendResetPwd (options, identifyUser, field, notifierOptions = {}) { +export default async function sendResetPwd ( + options: SendResetPwdOptions, + identifyUser: IdentifyUser, + notifierOptions = {} +): Promise { debug('sendResetPwd'); const usersService = options.app.service(options.service); const usersServiceIdName = usersService.id; @@ -34,7 +38,7 @@ async function sendResetPwd (options, identifyUser, field, notifierOptions = {}) const user2 = Object.assign(user1, { resetExpires: Date.now() + options.resetDelay, resetAttempts: options.resetAttempts, - resetToken: concatIDAndHash(user1[usersServiceIdName], await getLongToken(options.longTokenLen)), + resetToken: concatIDAndHash(user1[usersServiceIdName] as Id, await getLongToken(options.longTokenLen)), resetShortToken: await getShortToken(options.shortTokenLen, options.shortTokenDigits) }); @@ -45,11 +49,11 @@ async function sendResetPwd (options, identifyUser, field, notifierOptions = {}) resetToken: options.reuseResetToken ? user2.resetToken - : await hashPassword(options.app, user2.resetToken, field), + : await hashPassword(options.app, user2.resetToken, options.passwordField), resetShortToken: options.reuseResetToken ? user2.resetShortToken - : await hashPassword(options.app, user2.resetShortToken, field) + : await hashPassword(options.app, user2.resetShortToken, options.passwordField) }); return options.sanitizeUserForClient(user3); diff --git a/src/verify-signup-set-password.js b/src/methods/verify-signup-set-password.ts old mode 100755 new mode 100644 similarity index 57% rename from src/verify-signup-set-password.js rename to src/methods/verify-signup-set-password.ts index 2c60e60..e36c235 --- a/src/verify-signup-set-password.js +++ b/src/methods/verify-signup-set-password.ts @@ -1,25 +1,28 @@ -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const ensureValuesAreStrings = require('./helpers/ensure-values-are-strings'); -const getUserData = require('./helpers/get-user-data'); -const hashPassword = require('./helpers/hash-password'); -const notifier = require('./helpers/notifier'); +import { BadRequest } from '@feathersjs/errors'; +import makeDebug from 'debug'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import ensureValuesAreStrings from '../helpers/ensure-values-are-strings'; +import getUserData from '../helpers/get-user-data'; +import hashPassword from '../helpers/hash-password'; +import notifier from '../helpers/notifier'; +import { + IdentifyUser, + SanitizedUser, + Tokens, + User, + VerifyChanges, + VerifySignupSetPasswordOptions, + VerifySignupSetPasswordWithShortTokenOptions +} from '../types'; const debug = makeDebug('authLocalMgnt:verifySignupSetPassword'); -module.exports = { - verifySignupSetPasswordWithLongToken, - verifySignupSetPasswordWithShortToken -}; - -async function verifySignupSetPasswordWithLongToken ( - options, - verifyToken, - password, - field, +export async function verifySignupSetPasswordWithLongToken ( + options: VerifySignupSetPasswordOptions, + verifyToken: string, + password: string, notifierOptions = {} -) { +): Promise { ensureValuesAreStrings(verifyToken, password); const result = await verifySignupSetPassword( @@ -27,20 +30,18 @@ async function verifySignupSetPasswordWithLongToken ( { verifyToken }, { verifyToken }, password, - field, notifierOptions ); return result; } -async function verifySignupSetPasswordWithShortToken ( - options, - verifyShortToken, - identifyUser, - password, - field, +export async function verifySignupSetPasswordWithShortToken ( + options: VerifySignupSetPasswordWithShortTokenOptions, + verifyShortToken: string, + identifyUser: IdentifyUser, + password: string, notifierOptions = {} -) { +): Promise { ensureValuesAreStrings(verifyShortToken, password); ensureObjPropsValid(identifyUser, options.identifyUserProps); @@ -51,13 +52,18 @@ async function verifySignupSetPasswordWithShortToken ( verifyShortToken }, password, - field, notifierOptions ); return result; } -async function verifySignupSetPassword (options, query, tokens, password, field, notifierOptions = {}) { +async function verifySignupSetPassword ( + options: VerifySignupSetPasswordOptions, + query: IdentifyUser, + tokens: Tokens, + password: string, + notifierOptions = {} +): Promise { debug('verifySignupSetPassword', query, tokens, password); const usersService = options.app.service(options.service); const usersServiceIdName = usersService.id; @@ -69,9 +75,9 @@ async function verifySignupSetPassword (options, query, tokens, password, field, ]); if (!Object.keys(tokens).every((key) => tokens[key] === user1[key])) { - await eraseVerifyPropsSetPassword(user1, user1.isVerified, {}, password, field); + await eraseVerifyPropsSetPassword(user1, user1.isVerified, {}, password); - throw new errors.BadRequest( + throw new BadRequest( 'Invalid token. Get for a new one. (authLocalMgnt)', { errors: { $className: 'badParam' } } ); @@ -81,15 +87,19 @@ async function verifySignupSetPassword (options, query, tokens, password, field, user1, user1.verifyExpires > Date.now(), user1.verifyChanges || {}, - password, - field + password ); const user3 = await notifier(options.notifier, 'verifySignupSetPassword', user2, notifierOptions); return options.sanitizeUserForClient(user3); - async function eraseVerifyPropsSetPassword (user, isVerified, verifyChanges, password, field) { - const hashedPassword = await hashPassword(options.app, password, field); + async function eraseVerifyPropsSetPassword ( + user: User, + isVerified: boolean, + verifyChanges: VerifyChanges, + password: string + ): Promise { + const hashedPassword = await hashPassword(options.app, password, options.passwordField); const patchToUser = Object.assign({}, verifyChanges || {}, { isVerified, diff --git a/src/methods/verify-signup.ts b/src/methods/verify-signup.ts new file mode 100644 index 0000000..63cb855 --- /dev/null +++ b/src/methods/verify-signup.ts @@ -0,0 +1,74 @@ +import { BadRequest } from '@feathersjs/errors'; +import { Query } from '@feathersjs/feathers'; +import makeDebug from 'debug'; +import ensureObjPropsValid from '../helpers/ensure-obj-props-valid'; +import ensureValuesAreStrings from '../helpers/ensure-values-are-strings'; +import getUserData from '../helpers/get-user-data'; +import notifier from '../helpers/notifier'; +import isDateAfterNow from '../helpers/is-date-after-now'; +import { SanitizedUser, VerifySignupOptions, VerifySignupWithShortTokenOptions, Tokens, User, VerifyChanges, IdentifyUser } from '../types'; + +const debug = makeDebug('authLocalMgnt:verifySignup'); + +export async function verifySignupWithLongToken ( + options: VerifySignupOptions, + verifyToken: string, + notifierOptions = {} +): Promise { + ensureValuesAreStrings(verifyToken); + + const result = await verifySignup(options, { verifyToken }, { verifyToken }, notifierOptions); + return result; +} + +export async function verifySignupWithShortToken ( + options: VerifySignupWithShortTokenOptions, + verifyShortToken: string, + identifyUser: IdentifyUser, + notifierOptions = {} +): Promise { + ensureValuesAreStrings(verifyShortToken); + ensureObjPropsValid(identifyUser, options.identifyUserProps); + + const result = await verifySignup(options, identifyUser, { verifyShortToken }, notifierOptions); + return result; +} + +async function verifySignup ( + options: VerifySignupOptions, + query: Query, + tokens: Tokens, + notifierOptions = {} +): Promise { + debug('verifySignup', query, tokens); + const usersService = options.app.service(options.service); + const usersServiceIdName = usersService.id; + + const users = await usersService.find({ query }); + const user1 = getUserData(users, ['isNotVerifiedOrHasVerifyChanges', 'verifyNotExpired']); + + if (!Object.keys(tokens).every(key => tokens[key] === user1[key])) { + await eraseVerifyProps(user1, user1.isVerified); + + throw new BadRequest('Invalid token. Get for a new one. (authLocalMgnt)', + { errors: { $className: 'badParam' } } + ); + } + + const user2 = await eraseVerifyProps(user1, isDateAfterNow(user1.verifyExpires), user1.verifyChanges || {}); + const user3 = await notifier(options.notifier, 'verifySignup', user2, notifierOptions); + return options.sanitizeUserForClient(user3); + + async function eraseVerifyProps (user: User, isVerified: boolean, verifyChanges?: VerifyChanges): Promise { + const patchToUser = Object.assign({}, verifyChanges ?? {}, { + isVerified, + verifyToken: null, + verifyShortToken: null, + verifyExpires: null, + verifyChanges: {} + }); + + const result = await usersService.patch(user[usersServiceIdName], patchToUser, {}); + return result; + } +} diff --git a/src/password-change.js b/src/password-change.js deleted file mode 100755 index e52b967..0000000 --- a/src/password-change.js +++ /dev/null @@ -1,40 +0,0 @@ - -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); -const comparePasswords = require('./helpers/compare-passwords'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const ensureValuesAreStrings = require('./helpers/ensure-values-are-strings'); -const getUserData = require('./helpers/get-user-data'); -const hashPassword = require('./helpers/hash-password'); -const notifier = require('./helpers/notifier'); - -const debug = makeDebug('authLocalMgnt:passwordChange'); - -module.exports = passwordChange; - -async function passwordChange (options, identifyUser, oldPassword, password, field, notifierOptions = {}) { - debug('passwordChange', oldPassword, password); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - - ensureValuesAreStrings(oldPassword, password); - ensureObjPropsValid(identifyUser, options.identifyUserProps); - - const users = await usersService.find({ query: identifyUser }); - const user1 = getUserData(users); - - try { - await comparePasswords(oldPassword, user1.password, () => { }); - } catch (err) { - throw new errors.BadRequest('Current password is incorrect.', { - errors: { oldPassword: 'Current password is incorrect.' } - }); - } - - const user2 = await usersService.patch(user1[usersServiceIdName], { - password: await hashPassword(options.app, password, field) - }); - - const user3 = await notifier(options.notifier, 'passwordChange', user2, notifierOptions); - return options.sanitizeUserForClient(user3); -} diff --git a/src/reset-password.js b/src/reset-password.js deleted file mode 100755 index 778685f..0000000 --- a/src/reset-password.js +++ /dev/null @@ -1,104 +0,0 @@ -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); -const comparePasswords = require('./helpers/compare-passwords'); -const deconstructId = require('./helpers/deconstruct-id'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const ensureValuesAreStrings = require('./helpers/ensure-values-are-strings'); -const getUserData = require('./helpers/get-user-data'); -const hashPassword = require('./helpers/hash-password'); -const notifier = require('./helpers/notifier'); - -const debug = makeDebug('authLocalMgnt:resetPassword'); - -module.exports = { - resetPwdWithLongToken, - resetPwdWithShortToken -}; - -async function resetPwdWithLongToken (options, resetToken, password, field, notifierOptions = {}) { - ensureValuesAreStrings(resetToken, password); - - return resetPassword(options, { resetToken }, { resetToken }, password, field, notifierOptions); -} - -async function resetPwdWithShortToken (options, resetShortToken, identifyUser, password, field, notifierOptions = {}) { - ensureValuesAreStrings(resetShortToken, password); - ensureObjPropsValid(identifyUser, options.identifyUserProps); - - return resetPassword(options, identifyUser, { resetShortToken }, password, field, notifierOptions); -} - -async function resetPassword (options, query, tokens, password, field, notifierOptions = {}) { - debug('resetPassword', query, tokens, password); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - let users; - - if (tokens.resetToken) { - let id = deconstructId(tokens.resetToken); - users = await usersService.get(id); - } else if (tokens.resetShortToken) { - users = await usersService.find({ query }); - } else { - throw new errors.BadRequest('resetToken and resetShortToken are missing. (authLocalMgnt)', { - errors: { $className: 'missingToken' } - }); - } - - const checkProps = options.skipIsVerifiedCheck ? ['resetNotExpired'] : ['resetNotExpired', 'isVerified']; - const user1 = getUserData(users, checkProps); - - const tokenChecks = Object.keys(tokens).map(async key => { - if (options.reuseResetToken) { - // Comparing token directly as reused resetToken is not hashed - if (tokens[key] !== user1[key]) { - throw new errors.BadRequest('Reset Token is incorrect. (authLocalMgnt)', { - errors: {$className: 'incorrectToken'} - }); - } - } else { - return comparePasswords( - tokens[key], - user1[key], - () => - new errors.BadRequest('Reset Token is incorrect. (authLocalMgnt)', { - errors: {$className: 'incorrectToken'} - }) - ); - } - }); - - try { - await Promise.all(tokenChecks); - } catch (err) { - if (user1.resetAttempts > 0) { - await usersService.patch(user1[usersServiceIdName], { - resetAttempts: user1.resetAttempts - 1 - }); - - throw err; - } else { - await usersService.patch(user1[usersServiceIdName], { - resetToken: null, - resetAttempts: null, - resetShortToken: null, - resetExpires: null - }); - - throw new errors.BadRequest('Invalid token. Get for a new one. (authLocalMgnt)', { - errors: { $className: 'invalidToken' } - }); - } - } - - const user2 = await usersService.patch(user1[usersServiceIdName], { - password: await hashPassword(options.app, password, field), - resetExpires: null, - resetAttempts: null, - resetToken: null, - resetShortToken: null - }); - - const user3 = await notifier(options.notifier, 'resetPwd', user2, notifierOptions); - return options.sanitizeUserForClient(user3); -} diff --git a/src/service.js b/src/service.js deleted file mode 100755 index c8ec149..0000000 --- a/src/service.js +++ /dev/null @@ -1,197 +0,0 @@ -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); - -const debug = makeDebug('authLocalMgnt:service'); - -const checkUnique = require('./check-unique'); -const identityChange = require('./identity-change'); -const passwordChange = require('./password-change'); -const resendVerifySignup = require('./resend-verify-signup'); -const sanitizeUserForClient = require('./helpers/sanitize-user-for-client'); -const sendResetPwd = require('./send-reset-pwd'); -const { - resetPwdWithLongToken, - resetPwdWithShortToken -} = require('./reset-password'); -const { - verifySignupWithLongToken, - verifySignupWithShortToken -} = require('./verify-signup'); -const { - verifySignupSetPasswordWithLongToken, - verifySignupSetPasswordWithShortToken -} = require('./verify-signup-set-password'); -const passwordField = 'password'; - -const optionsDefault = { - app: null, // value set during configuration - service: '/users', // need exactly this for test suite - path: 'authManagement', - notifier: async () => {}, - longTokenLen: 15, // token's length will be twice this - shortTokenLen: 6, - shortTokenDigits: true, - resetDelay: 1000 * 60 * 60 * 2, // 2 hours - delay: 1000 * 60 * 60 * 24 * 5, // 5 days - resetAttempts: 0, - reuseResetToken: false, - identifyUserProps: ['email'], - sanitizeUserForClient -}; - -module.exports = authenticationLocalManagement; - -function authenticationLocalManagement (options1 = {}, docs = {}) { - debug('service being configured.'); - - return function () { - const options = Object.assign({}, optionsDefault, options1, { app: this }); - options.app.use(options.path, Object.assign(authLocalMgntMethods(options), { docs })); - }; -} - -function authLocalMgntMethods (options) { - return { - async create (data) { - debug(`create called. action=${data.action}`); - - switch (data.action) { - case 'checkUnique': - try { - return await checkUnique( - options, - data.value, - data.ownId || null, - data.meta || {} - ); - } catch (err) { - return Promise.reject(err); // support both async and Promise interfaces - } - case 'resendVerifySignup': - try { - return await resendVerifySignup( - options, - data.value, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'verifySignupLong': - try { - return await verifySignupWithLongToken( - options, - data.value, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'verifySignupShort': - try { - return await verifySignupWithShortToken( - options, - data.value.token, - data.value.user, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'verifySignupSetPasswordLong': - try { - return await verifySignupSetPasswordWithLongToken( - options, - data.value.token, - data.value.password, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'verifySignupSetPasswordShort': - try { - return await verifySignupSetPasswordWithShortToken( - options, - data.value.token, - data.value.user, - data.value.password, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'sendResetPwd': - try { - return await sendResetPwd( - options, - data.value, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'resetPwdLong': - try { - return await resetPwdWithLongToken( - options, - data.value.token, - data.value.password, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'resetPwdShort': - try { - return await resetPwdWithShortToken( - options, - data.value.token, - data.value.user, - data.value.password, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'passwordChange': - try { - return await passwordChange( - options, - data.value.user, - data.value.oldPassword, - data.value.password, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'identityChange': - try { - return await identityChange( - options, - data.value.user, - data.value.password, - data.value.changes, - passwordField, - data.notifierOptions - ); - } catch (err) { - return Promise.reject(err); - } - case 'options': - return options; - default: - throw new errors.BadRequest(`Action '${data.action}' is invalid.`, { - errors: { $className: 'badParams' } - }); - } - } - }; -} diff --git a/src/services/AuthenticationManagementBase.ts b/src/services/AuthenticationManagementBase.ts new file mode 100644 index 0000000..632a2e9 --- /dev/null +++ b/src/services/AuthenticationManagementBase.ts @@ -0,0 +1,22 @@ +import { MethodNotAllowed } from '@feathersjs/errors'; +import { Params } from '@feathersjs/feathers'; + +export abstract class AuthenticationManagementBase { + publish: unknown; + + abstract _create (data: T, params?: Params): Promise; + + async create (data: T, params?: Params): Promise { + if (Array.isArray(data)) { + return await Promise.reject(new MethodNotAllowed('authManagement does not handle multiple entries')); + } + + return await this._create(data, params); + } + + setup (): void { + if (typeof this.publish === 'function') { + this.publish(() => null); + } + } +} diff --git a/src/services/AuthenticationManagementService.ts b/src/services/AuthenticationManagementService.ts new file mode 100644 index 0000000..ae360e2 --- /dev/null +++ b/src/services/AuthenticationManagementService.ts @@ -0,0 +1,303 @@ +import makeDebug from 'debug'; +import { BadRequest } from '@feathersjs/errors'; +import { SetRequired } from 'type-fest'; + +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +import { + AuthenticationManagementData, + AuthenticationManagementServiceOptions, + DataCheckUnique, + DataCheckUniqueWithAction, + DataIdentityChange, + DataIdentityChangeWithAction, + DataOptions, + DataPasswordChange, + DataPasswordChangeWithAction, + DataResendVerifySignup, + DataResendVerifySignupWithAction, + DataResetPwdLong, + DataResetPwdLongWithAction, + DataResetPwdShort, + DataResetPwdShortWithAction, + DataSendResetPwd, + DataSendResetPwdWithAction, + DataVerifySignupLong, + DataVerifySignupLongWithAction, + DataVerifySignupSetPasswordLong, + DataVerifySignupSetPasswordLongWithAction, + DataVerifySignupSetPasswordShort, + DataVerifySignupSetPasswordShortWithAction, + DataVerifySignupShort, + DataVerifySignupShortWithAction, + SanitizedUser +} from '../types'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { makeDefaultOptions } from '.'; +import checkUnique from '../methods/check-unique'; +import identityChange from '../methods/identity-change'; +import passwordChange from '../methods/password-change'; +import resendVerifySignup from '../methods/resend-verify-signup'; +import { resetPwdWithLongToken, resetPwdWithShortToken } from '../methods/reset-password'; +import sendResetPwd from '../methods/send-reset-pwd'; +import { verifySignupWithLongToken, verifySignupWithShortToken } from '../methods/verify-signup'; +import { verifySignupSetPasswordWithLongToken, verifySignupSetPasswordWithShortToken } from '../methods/verify-signup-set-password'; + +const debug = makeDebug('authLocalMgnt:service'); + +type AllResultTypes = null | SanitizedUser | AuthenticationManagementServiceOptions | unknown; + +export class AuthenticationManagementService extends AuthenticationManagementBase { + docs: unknown; + options: AuthenticationManagementServiceOptions; + + constructor ( + options: SetRequired, 'app'>, + docs?: unknown + ) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'skipIsVerifiedCheck', + 'notifier', + 'longTokenLen', + 'shortTokenLen', + 'shortTokenDigits', + 'resetDelay', + 'delay', + 'resetAttempts', + 'reuseResetToken', + 'identifyUserProps', + 'sanitizeUserForClient', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + + this.docs = docs; + } + + async _checkUnique (data: DataCheckUnique): Promise { + return await checkUnique( + this.options, + data.value, + data.ownId, + data.meta + ); + } + + async _identityChange (data: DataIdentityChange): Promise { + return await identityChange( + this.options, + data.value.user, + data.value.password, + data.value.changes, + data.notifierOptions + ); + } + + async _passwordChange (data: DataPasswordChange): Promise { + return await passwordChange( + this.options, + data.value.user, + data.value.oldPassword, + data.value.password, + data.notifierOptions + ); + } + + async _resendVerifySignup (data: DataResendVerifySignup): Promise { + return await resendVerifySignup( + this.options, + data.value, + data.notifierOptions + ); + } + + async _resetPasswordLong (data: DataResetPwdLong): Promise { + return await resetPwdWithLongToken( + this.options, + data.value.token, + data.value.password, + data.notifierOptions + ); + } + + async _resetPasswordShort (data: DataResetPwdShort): Promise { + return await resetPwdWithShortToken( + this.options, + data.value.token, + data.value.user, + data.value.password, + data.notifierOptions + ); + } + + async _sendResetPassword (data: DataSendResetPwd): Promise { + return await sendResetPwd( + this.options, + data.value, + data.notifierOptions + ); + } + + async _verifySignupLong (data: DataVerifySignupLong): Promise { + return await verifySignupWithLongToken( + this.options, + data.value, + data.notifierOptions + ); + } + + async _verifySignupShort (data: DataVerifySignupShort): Promise { + return await verifySignupWithShortToken( + this.options, + data.value.token, + data.value.user, + data.notifierOptions + ); + } + + async _verifySignupSetPasswordLong (data: DataVerifySignupSetPasswordLong): Promise { + return await verifySignupSetPasswordWithLongToken( + this.options, + data.value.token, + data.value.password, + data.notifierOptions + ); + } + + async _verifySignupSetPasswordShort (data: DataVerifySignupSetPasswordShort): Promise { + return await verifySignupSetPasswordWithShortToken( + this.options, + data.value.token, + data.value.user, + data.value.password, + data.notifierOptions + ); + } + + /** + * check props are unique in the users items. + * @param data.action action is 'checkUnique' + * @param data.value {IdentifyUser} the user with properties, e.g. {email, username}. Props with null or undefined are ignored. + * @param data.ownId excludes your current user from the search + * @param data.meta.noErrMsg if return an error.message if not unique + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async _create ({ action, value, ownId, meta }: DataCheckUniqueWithAction): Promise + /** + * change communications + * @param action action is 'identityChange' + * @param value { changes, password, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataIdentityChangeWithAction): Promise + /** + * change password + * @param action action is 'passwordChange' + * @param value { oldPassword, password, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataPasswordChangeWithAction): Promise + /** + * resend sign up verification notification + * @param action action is 'resendVerifySignup' + * @param value {IdentifyUser} the user with properties, e.g. {email}, {token: verifyToken} + * @param notifierOptions options passed to options.notifier, e.g. {preferredComm: 'cellphone'} + */ + async _create ({ action, value, notifierOptions }: DataResendVerifySignupWithAction): Promise + /** + * forgotten password verification with long token + * @param action action is 'resetPwdLong' + * @param value { password, token, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataResetPwdLongWithAction): Promise + /** + * forgotten password verification with short token + * @param action action is 'resetPwdShort' + * @param value { password, token, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataResetPwdShortWithAction): Promise + /** + * send forgotten password notification + * @param action action is 'sendResetPwd' + * @param value { password, token } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataSendResetPwdWithAction): Promise + /** + * sign up or identityChange verification with long token + * @param action action is 'verifySignupLong' + * @param value // compares to user.verifyToken + * @param notifierOptions options passed to options.notifier, e.g. {preferredComm: 'cellphone'} + */ + async _create ({ action, value, notifierOptions }: DataVerifySignupLongWithAction): Promise + /** + * sign up or identityChange verification with short token + * @param action action is 'verifySignupShort' + * @param value { token, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataVerifySignupShortWithAction): Promise + /** + * sign up verification and set password with long token + * @param action action is 'verifySignupSetPasswordLong' + * @param value { password, token } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataVerifySignupSetPasswordLongWithAction): Promise + /** + * sign up verification and set password with short token + * @param action action is 'verifySignupSetPasswordShort' + * @param value { password, token, user } + * @param notifierOptions + */ + async _create ({ action, value, notifierOptions }: DataVerifySignupSetPasswordShortWithAction): Promise + /** + * get options for AuthenticationManagement + * @param action action is 'options' + */ + async _create ({ action }: DataOptions): Promise + async _create (data: AuthenticationManagementData): Promise { + debug(`create called. action=${data.action}`); + + try { + if (data.action === 'checkUnique') { + return await this._checkUnique(data); + } else if (data.action === 'resendVerifySignup') { + return await this._resendVerifySignup(data); + } else if (data.action === 'verifySignupLong') { + return await this._verifySignupLong(data); + } else if (data.action === 'verifySignupShort') { + return await this._verifySignupShort(data); + } else if (data.action === 'verifySignupSetPasswordLong') { + return await this._verifySignupSetPasswordLong(data); + } else if (data.action === 'verifySignupSetPasswordShort') { + return await this._verifySignupSetPasswordShort(data); + } else if (data.action === 'sendResetPwd') { + return await this._sendResetPassword(data); + } else if (data.action === 'resetPwdLong') { + return await this._resetPasswordLong(data); + } else if (data.action === 'resetPwdShort') { + return await this._resetPasswordShort(data); + } else if (data.action === 'passwordChange') { + return await this._passwordChange(data); + } else if (data.action === 'identityChange') { + return await this._identityChange(data); + } else if (data.action === 'options') { + return this.options; + } + } catch (err) { + return await Promise.reject(err); + } + + // @ts-expect-error this should not be reached + throw new BadRequest(`Action '${data.action}' is invalid.`, { // eslint-disable-line + errors: { $className: 'badParams' } + }); + } +} diff --git a/src/services/CheckUniqueService.ts b/src/services/CheckUniqueService.ts new file mode 100644 index 0000000..e7b8fd9 --- /dev/null +++ b/src/services/CheckUniqueService.ts @@ -0,0 +1,27 @@ +import { SetRequired } from 'type-fest'; + +import checkUnique from '../methods/check-unique'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { DataCheckUnique, CheckUniqueOptions } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; +import { makeDefaultOptions } from './index'; + +export class CheckUniqueService extends AuthenticationManagementBase { + options: CheckUniqueOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions(['service']); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataCheckUnique): Promise { + return await checkUnique( + this.options, + data.value, + data.ownId, + data.meta + ); + } +} diff --git a/src/services/IdentityChangeService.ts b/src/services/IdentityChangeService.ts new file mode 100644 index 0000000..fc81752 --- /dev/null +++ b/src/services/IdentityChangeService.ts @@ -0,0 +1,39 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import identityChange from '../methods/identity-change'; +import { SanitizedUser, IdentityChangeOptions, DataIdentityChange } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class IdentityChangeService extends AuthenticationManagementBase { + options: IdentityChangeOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'longTokenLen', + 'shortTokenLen', + 'shortTokenDigits', + 'delay', + 'identifyUserProps', + 'sanitizeUserForClient', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataIdentityChange): Promise { + return await identityChange( + this.options, + data.value.user, + data.value.password, + data.value.changes, + data.notifierOptions + ); + } +} diff --git a/src/services/PasswordChangeService.ts b/src/services/PasswordChangeService.ts new file mode 100644 index 0000000..171645b --- /dev/null +++ b/src/services/PasswordChangeService.ts @@ -0,0 +1,35 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import passwordChange from '../methods/password-change'; +import { SanitizedUser, DataPasswordChange, PasswordChangeOptions } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class PasswordChangeService extends AuthenticationManagementBase { + options: PasswordChangeOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'identifyUserProps', + 'sanitizeUserForClient', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataPasswordChange): Promise { + return await passwordChange( + this.options, + data.value.user, + data.value.oldPassword, + data.value.password, + data.notifierOptions + ); + } +} diff --git a/src/services/ResendVerifySignupService.ts b/src/services/ResendVerifySignupService.ts new file mode 100644 index 0000000..79bd89f --- /dev/null +++ b/src/services/ResendVerifySignupService.ts @@ -0,0 +1,36 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import resendVerifySignup from '../methods/resend-verify-signup'; +import { SanitizedUser, ResendVerifySignupOptions, DataResendVerifySignup } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class ResendVerifySignupService extends AuthenticationManagementBase { + options: ResendVerifySignupOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'longTokenLen', + 'shortTokenLen', + 'shortTokenDigits', + 'delay', + 'identifyUserProps', + 'sanitizeUserForClient' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataResendVerifySignup): Promise { + return await resendVerifySignup( + this.options, + data.value, + data.notifierOptions + ); + } +} diff --git a/src/services/ResetPwdLongService.ts b/src/services/ResetPwdLongService.ts new file mode 100644 index 0000000..07ddd26 --- /dev/null +++ b/src/services/ResetPwdLongService.ts @@ -0,0 +1,35 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { resetPwdWithLongToken } from '../methods/reset-password'; +import { SanitizedUser, ResetPasswordOptions, DataResetPwdLong } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class ResetPwdLongService extends AuthenticationManagementBase { + options: ResetPasswordOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'skipIsVerifiedCheck', + 'notifier', + 'reuseResetToken', + 'sanitizeUserForClient', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataResetPwdLong): Promise { + return await resetPwdWithLongToken( + this.options, + data.value.token, + data.value.password, + data.notifierOptions + ); + } +} diff --git a/src/services/ResetPwdShortService.ts b/src/services/ResetPwdShortService.ts new file mode 100644 index 0000000..1fd5a24 --- /dev/null +++ b/src/services/ResetPwdShortService.ts @@ -0,0 +1,42 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { resetPwdWithShortToken } from '../methods/reset-password'; +import { + DataResetPwdShort, + SanitizedUser, + ResetPwdWithShortTokenOptions +} from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class ResetPwdShortService extends AuthenticationManagementBase { + options: ResetPwdWithShortTokenOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'skipIsVerifiedCheck', + 'reuseResetToken', + 'notifier', + 'reuseResetToken', + 'sanitizeUserForClient', + 'passwordField', + 'identifyUserProps' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataResetPwdShort): Promise { + return await resetPwdWithShortToken( + this.options, + data.value.token, + data.value.user, + data.value.password, + data.notifierOptions + ); + } +} diff --git a/src/services/SendResetPwdService.ts b/src/services/SendResetPwdService.ts new file mode 100644 index 0000000..f6d2f10 --- /dev/null +++ b/src/services/SendResetPwdService.ts @@ -0,0 +1,40 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import sendResetPwd from '../methods/send-reset-pwd'; +import { DataSendResetPwd, SanitizedUser, SendResetPwdOptions } from '../types'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class SendResetPwdService extends AuthenticationManagementBase { + options: SendResetPwdOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'identifyUserProps', + 'skipIsVerifiedCheck', + 'reuseResetToken', + 'resetDelay', + 'sanitizeUserForClient', + 'resetAttempts', + 'shortTokenLen', + 'longTokenLen', + 'shortTokenDigits', + 'notifier', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataSendResetPwd): Promise { + return await sendResetPwd( + this.options, + data.value, + data.notifierOptions + ); + } +} diff --git a/src/services/VerifySignupLongService.ts b/src/services/VerifySignupLongService.ts new file mode 100644 index 0000000..36e9870 --- /dev/null +++ b/src/services/VerifySignupLongService.ts @@ -0,0 +1,31 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { DataVerifySignupLong, SanitizedUser, VerifySignupOptions } from '../types'; +import { verifySignupWithLongToken } from '../methods/verify-signup'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class VerifySignupLongService extends AuthenticationManagementBase { + options: VerifySignupOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'sanitizeUserForClient' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataVerifySignupLong): Promise { + return await verifySignupWithLongToken( + this.options, + data.value, + data.notifierOptions + ); + } +} diff --git a/src/services/VerifySignupSetPasswordLongService.ts b/src/services/VerifySignupSetPasswordLongService.ts new file mode 100644 index 0000000..407dcb0 --- /dev/null +++ b/src/services/VerifySignupSetPasswordLongService.ts @@ -0,0 +1,33 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { DataVerifySignupSetPasswordLong, SanitizedUser, VerifySignupSetPasswordOptions } from '../types'; +import { verifySignupSetPasswordWithLongToken } from '../methods/verify-signup-set-password'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class VerifySignupSetPasswordLongService extends AuthenticationManagementBase { + options: VerifySignupSetPasswordOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'sanitizeUserForClient', + 'passwordField' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataVerifySignupSetPasswordLong): Promise { + return await verifySignupSetPasswordWithLongToken( + this.options, + data.value.token, + data.value.password, + data.notifierOptions + ); + } +} diff --git a/src/services/VerifySignupSetPasswordShortService.ts b/src/services/VerifySignupSetPasswordShortService.ts new file mode 100644 index 0000000..67601d2 --- /dev/null +++ b/src/services/VerifySignupSetPasswordShortService.ts @@ -0,0 +1,35 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { DataVerifySignupSetPasswordShort, SanitizedUser, VerifySignupSetPasswordWithShortTokenOptions } from '../types'; +import { verifySignupSetPasswordWithShortToken } from '../methods/verify-signup-set-password'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class VerifySignupSetPasswordShortService extends AuthenticationManagementBase { + options: VerifySignupSetPasswordWithShortTokenOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'sanitizeUserForClient', + 'passwordField', + 'identifyUserProps' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataVerifySignupSetPasswordShort): Promise { + return await verifySignupSetPasswordWithShortToken( + this.options, + data.value.token, + data.value.user, + data.value.password, + data.notifierOptions + ); + } +} diff --git a/src/services/VerifySignupShort.ts b/src/services/VerifySignupShort.ts new file mode 100644 index 0000000..39ceb67 --- /dev/null +++ b/src/services/VerifySignupShort.ts @@ -0,0 +1,34 @@ +import { SetRequired } from 'type-fest'; + +import { makeDefaultOptions } from '.'; +import ensureHasAllKeys from '../helpers/ensure-has-all-keys'; +import { DataVerifySignupShort, SanitizedUser, VerifySignupWithShortTokenOptions } from '../types'; +import { verifySignupWithShortToken } from '../methods/verify-signup'; +import { AuthenticationManagementBase } from './AuthenticationManagementBase'; + +export class VerifySignupShortService extends AuthenticationManagementBase { + options: VerifySignupWithShortTokenOptions; + + constructor (options: SetRequired, 'app'>) { + super(); + + ensureHasAllKeys(options, ['app'], this.constructor.name); + const defaultOptions: Omit = makeDefaultOptions([ + 'service', + 'notifier', + 'sanitizeUserForClient', + 'passwordField', + 'identifyUserProps' + ]); + this.options = Object.assign(defaultOptions, options); + } + + async _create (data: DataVerifySignupShort): Promise { + return await verifySignupWithShortToken( + this.options, + data.value.token, + data.value.user, + data.notifierOptions + ); + } +} diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..ffd74ae --- /dev/null +++ b/src/services/index.ts @@ -0,0 +1,84 @@ +import _cloneDeep from 'lodash/cloneDeep'; +import _pick from 'lodash/pick'; + +import { AuthenticationManagementService } from './AuthenticationManagementService'; + +import { CheckUniqueService } from './CheckUniqueService'; + +import { IdentityChangeService } from './IdentityChangeService'; +import { PasswordChangeService } from './PasswordChangeService'; +import { ResendVerifySignupService } from './ResendVerifySignupService'; +import { ResetPwdLongService } from './ResetPwdLongService'; +import { ResetPwdShortService } from './ResetPwdShortService'; +import { SendResetPwdService } from './SendResetPwdService'; +import { VerifySignupLongService } from './VerifySignupLongService'; +import { VerifySignupSetPasswordLongService } from './VerifySignupSetPasswordLongService'; +import { VerifySignupSetPasswordShortService } from './VerifySignupSetPasswordShortService'; +import { VerifySignupShortService } from './VerifySignupShort'; + +import { + AuthenticationManagementServiceOptionsDefault, + NotificationType, + User +} from '../types'; +import sanitizeUserForClient from '../helpers/sanitize-user-for-client'; + +const services = { + AuthenticationManagementService, + IdentityChangeService, + PasswordChangeService, + ResendVerifySignupService, + ResetPwdLongService, + ResetPwdShortService, + SendResetPwdService, + VerifySignupLongService, + VerifySignupSetPasswordLongService, + VerifySignupSetPasswordShortService, + VerifySignupShortService, + CheckUniqueService +}; + +export { + AuthenticationManagementService, + IdentityChangeService, + PasswordChangeService, + ResendVerifySignupService, + ResetPwdLongService, + ResetPwdShortService, + SendResetPwdService, + VerifySignupLongService, + VerifySignupSetPasswordLongService, + VerifySignupSetPasswordShortService, + VerifySignupShortService, + CheckUniqueService +}; + +export default services; + +export const optionsDefault: AuthenticationManagementServiceOptionsDefault = { + service: '/users', // need exactly this for test suite + // eslint-disable-next-line @typescript-eslint/no-empty-function + notifier: async (type: NotificationType, user: User, notifierOptions) => {}, + longTokenLen: 15, // token's length will be twice this + shortTokenLen: 6, + shortTokenDigits: true, + resetDelay: 1000 * 60 * 60 * 2, // 2 hours + delay: 1000 * 60 * 60 * 24 * 5, // 5 days + resetAttempts: 0, + reuseResetToken: false, + identifyUserProps: ['email'], + sanitizeUserForClient, + skipIsVerifiedCheck: false, + passwordField: 'password' +}; + +export function makeDefaultOptions (keys: K[]): Pick { + const options = _cloneDeep(optionsDefault); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return _pick(options, keys); +} + +// commonjs +if (typeof module !== 'undefined') { + module.exports = Object.assign(services, module.exports); +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..e5b18a3 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,352 @@ +import { Application, Id } from '@feathersjs/feathers'; + +//#region general + +export interface User { + isVerified: boolean + verifyToken: string + verifyShortToken: string + verifyExpires: Date | number // unix + verifyChanges: VerifyChanges + resetToken: string + resetShortToken: string + resetExpires: Date | number // unix + resetAttempts: number + password: string + [key: string]: unknown + [key: number]: unknown +} + +export type HookResult = User | User[] | { data: User | User[], total: number }; + +export interface VerifyChanges { + [key: string]: unknown + [key: number]: unknown +} + +// TODO: explicit +export interface Tokens { + resetToken?: string + resetShortToken?: string + verifyShortToken?: string + verifyToken?: string +} + +export interface IdentifyUser { + [key: string]: string + [key: number]: string +} + +export type Notifier = (type: NotificationType, user: Partial, notifierOptions: Record) => unknown; +export type SanitizeUserForClient = (user: Partial) => SanitizedUser; + +export type SanitizedUser = Partial; + +export type NotificationType = + 'resendVerifySignup' | + 'verifySignup' | + 'verifySignupSetPassword' | + 'sendResetPwd' | + 'resetPwd' | + 'passwordChange' | + 'identityChange'; + +// #endregion + +export type AuthenticationManagementAction = + 'checkUnique' | + 'resendVerifySignup' | + 'verifySignupLong' | + 'verifySignupShort' | + 'verifySignupSetPasswordLong' | + 'verifySignupSetPasswordShort' | + 'sendResetPwd' | + 'resetPwdLong' | + 'resetPwdShort' | + 'passwordChange' | + 'identityChange' | + 'options'; + +export type ActionPathMap = { + [key in Exclude]: T +}; + +export type UseSeparateServicesOption = boolean | Partial>; + +//#region options + +export interface AuthenticationManagementConfigureOptions { + service: string + path: string + skipIsVerifiedCheck: boolean + notifier: Notifier + longTokenLen: number + shortTokenLen: number + shortTokenDigits: boolean + resetDelay: number + delay: number + resetAttempts: number + reuseResetToken: boolean + identifyUserProps: string[] + sanitizeUserForClient: (user: User) => Partial + passwordField: string + // identifyUser: IdentifyUser // TODO ? + useSeparateServices: UseSeparateServicesOption +} + +export interface AuthenticationManagementServiceOptions extends Omit { + app: Application +} + +export type AuthenticationManagementServiceOptionsDefault = Omit; + +export type VerifySignupOptions = Pick; + +export interface VerifySignupWithShortTokenOptions extends VerifySignupOptions { + identifyUserProps: string[] +} + +export type VerifySignupSetPasswordOptions = Pick; + +export type PasswordChangeOptions = Pick; + +export type VerifySignupSetPasswordWithShortTokenOptions = +VerifySignupSetPasswordOptions & Pick; + +export type ResetPasswordOptions = Pick; + +export interface ResetPwdWithShortTokenOptions extends ResetPasswordOptions { + identifyUserProps: string[] +} + +export type ResendVerifySignupOptions = Pick; + +export type IdentityChangeOptions = Pick; + +export type CheckUniqueOptions = Pick; + +export type SendResetPwdOptions = Pick; + +//#endregion + +//#region client +export interface AuthenticationManagementClient { + checkUnique: (identifyUser: IdentifyUser, ownId: Id, ifErrMsg: boolean) => Promise + resendVerifySignup: (identifyUser: IdentifyUser, notifierOptions: Record) => Promise + verifySignupLong: (verifyToken: string) => Promise + verifySignupShort: (verifyToken: string, identifyUser: IdentifyUser) => Promise + sendResetPwd: (IdentifyUser: IdentifyUser, notifierOptions: Record) => Promise + resetPwdLong: (resetToken: string, password: string) => Promise + resetPwdShort: (resetShortToken: string, identifyUser: IdentifyUser, password: string) => Promise + passwordChange: (oldPassword: string, password: string, identifyUser: IdentifyUser) => Promise + identityChange: (password: string, changesIdentifyUser: Record, identifyUser: IdentifyUser) => Promise + authenticate: (email: string, password: string, cb?: (err: Error | null, user?: Partial) => void) => Promise +} + +//#endregion + +//#region service data + +export type AuthenticationManagementData = + DataCheckUniqueWithAction | + DataIdentityChangeWithAction | + DataOptions | + DataPasswordChangeWithAction | + DataResendVerifySignupWithAction | + DataResetPwdLongWithAction | + DataResetPwdShortWithAction | + DataSendResetPwdWithAction | + DataVerifySignupLongWithAction | + DataVerifySignupSetPasswordLongWithAction | + DataVerifySignupSetPasswordShortWithAction | + DataVerifySignupShortWithAction; + +export interface DataCheckUnique { + value: IdentifyUser + ownId?: Id + meta?: { + noErrMsg: boolean + } +} + +export interface DataCheckUniqueWithAction extends DataCheckUnique { + action: 'checkUnique' +} + +export interface DataIdentityChange { + value: { + changes: Record + password: string + user: IdentifyUser + } + notifierOptions?: Record +} + +export interface DataIdentityChangeWithAction extends DataIdentityChange { + action: 'identityChange' +} + +export interface DataPasswordChange { + value: { + oldPassword: string + password: string + user: IdentifyUser + } + notifierOptions?: Record +} + +export interface DataPasswordChangeWithAction extends DataPasswordChange { + action: 'passwordChange' +} + +// TODO: notifierOptions +export interface DataResendVerifySignup { + value: IdentifyUser + notifierOptions?: Record +} + +export interface DataResendVerifySignupWithAction extends DataResendVerifySignup { + action: 'resendVerifySignup' +} + +export interface DataResetPwdLong { + value: { + password: string + token: string + } + notifierOptions?: Record +} + +export interface DataResetPwdLongWithAction extends DataResetPwdLong { + action: 'resetPwdLong' +} + +export interface DataResetPwdShort { + value: { + password: string + token: string + user: IdentifyUser + } + notifierOptions?: Record +} + +export interface DataResetPwdShortWithAction extends DataResetPwdShort { + action: 'resetPwdShort' +} + +export interface DataSendResetPwd { + value: IdentifyUser + notifierOptions?: Record +} + +export interface DataSendResetPwdWithAction extends DataSendResetPwd { + action: 'sendResetPwd' +} + +export interface DataVerifySignupLong { + value: string + notifierOptions?: Record +} + +export interface DataVerifySignupLongWithAction extends DataVerifySignupLong { + action: 'verifySignupLong' +} + +export interface DataVerifySignupSetPasswordLong { + value: { + password: string + token: string + } + notifierOptions?: Record +} + +export interface DataVerifySignupSetPasswordLongWithAction extends DataVerifySignupSetPasswordLong { + action: 'verifySignupSetPasswordLong' +} + +export interface DataVerifySignupSetPasswordShort { + value: { + password: string + token: string + user: IdentifyUser + } + notifierOptions?: Record +} + +export interface DataVerifySignupSetPasswordShortWithAction extends DataVerifySignupSetPasswordShort { + action: 'verifySignupSetPasswordShort' +} + +export interface DataVerifySignupShort { + value: { + token: string + user: IdentifyUser + } + notifierOptions?: Record +} + +export interface DataVerifySignupShortWithAction extends DataVerifySignupShort { + action: 'verifySignupShort' +} + +export interface DataOptions { + action: 'options' +} + +//#endregion diff --git a/src/verify-signup.js b/src/verify-signup.js deleted file mode 100755 index d0c04a3..0000000 --- a/src/verify-signup.js +++ /dev/null @@ -1,63 +0,0 @@ - -const errors = require('@feathersjs/errors'); -const makeDebug = require('debug'); -const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid'); -const ensureValuesAreStrings = require('./helpers/ensure-values-are-strings'); -const getUserData = require('./helpers/get-user-data'); -const notifier = require('./helpers/notifier'); - -const debug = makeDebug('authLocalMgnt:verifySignup'); - -module.exports = { - verifySignupWithLongToken, - verifySignupWithShortToken -}; - -async function verifySignupWithLongToken (options, verifyToken, notifierOptions = {}) { - ensureValuesAreStrings(verifyToken); - - const result = await verifySignup(options, { verifyToken }, { verifyToken }, notifierOptions); - return result; -} - -async function verifySignupWithShortToken (options, verifyShortToken, identifyUser, notifierOptions = {}) { - ensureValuesAreStrings(verifyShortToken); - ensureObjPropsValid(identifyUser, options.identifyUserProps); - - const result = await verifySignup(options, identifyUser, { verifyShortToken }, notifierOptions); - return result; -} - -async function verifySignup (options, query, tokens, notifierOptions = {}) { - debug('verifySignup', query, tokens); - const usersService = options.app.service(options.service); - const usersServiceIdName = usersService.id; - - const users = await usersService.find({ query }); - const user1 = getUserData(users, ['isNotVerifiedOrHasVerifyChanges', 'verifyNotExpired']); - - if (!Object.keys(tokens).every(key => tokens[key] === user1[key])) { - await eraseVerifyProps(user1, user1.isVerified); - - throw new errors.BadRequest('Invalid token. Get for a new one. (authLocalMgnt)', - { errors: { $className: 'badParam' } } - ); - } - - const user2 = await eraseVerifyProps(user1, user1.verifyExpires > Date.now(), user1.verifyChanges || {}); - const user3 = await notifier(options.notifier, 'verifySignup', user2, notifierOptions); - return options.sanitizeUserForClient(user3); - - async function eraseVerifyProps (user, isVerified, verifyChanges) { - const patchToUser = Object.assign({}, verifyChanges || {}, { - isVerified, - verifyToken: null, - verifyShortToken: null, - verifyExpires: null, - verifyChanges: {} - }); - - const result = await usersService.patch(user[usersServiceIdName], patchToUser, {}); - return result; - } -} diff --git a/test/add-verification.test.js b/test/add-verification.test.ts old mode 100755 new mode 100644 similarity index 85% rename from test/add-verification.test.js rename to test/add-verification.test.ts index 9bbb044..f283704 --- a/test/add-verification.test.js +++ b/test/add-verification.test.ts @@ -1,257 +1,264 @@ - -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const authLocalMgnt = require('../src/index'); -const { addVerification } = require('../src/index').hooks; -const { defaultVerifyDelay, timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); - -describe('add-verification.test.js', function () { - this.timeout(timeoutEachTest); - - let app; - let context; - - beforeEach(() => { - app = feathers(); - - context = { - type: 'before', - method: 'create', - data: { email: 'a@a.com', password: '0000000000' }, - app, - params: { - user: { email: 'b@b.com' } - } - }; - }); - - describe('basics', () => { - it('works with no options', async () => { - app.configure(authLocalMgnt()); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('delay option works', async () => { - const options = { delay: 1000 * 60 * 60 * 24 * 5 }; // 5 days - app.configure(authLocalMgnt(options)); - app.setup(); - - context = { - type: 'before', - method: 'create', - data: { email: 'a@a.com', password: '0000000000' }, - app - }; - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - }); - - describe('long token', () => { - it('length option works', async () => { - const options = { longTokenLen: 10 }; - app.configure(authLocalMgnt(options)); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal(user.verifyToken.length, (options.len || options.longTokenLen) * 2, 'verify token wrong length'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); // small chance of false negative - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - }); - - describe('shortToken', () => { - it('produces digit short token', async () => { - const options = { shortTokenDigits: true }; - app.configure(authLocalMgnt(options)); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('produces alpha short token', async () => { - const options = { shortTokenDigits: false }; - app.configure(authLocalMgnt(options)); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.notMatch(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('length option works with digits', async () => { - const options = { shortTokenLen: 7 }; - app.configure(authLocalMgnt(options)); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.equal(user.verifyShortToken.length, 7, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('length option works with alpha', async () => { - const options = { shortTokenLen: 9, shortTokenDigits: false }; - app.configure(authLocalMgnt(options)); - app.setup(); - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.equal(user.verifyShortToken.length, 9, 'verify short token wrong length'); - assert.notMatch(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - }); - - describe('patch & update', () => { - it('works with patch', async () => { - app.configure(authLocalMgnt()); - app.setup(); - context.method = 'patch'; - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('works with update', async () => { - app.configure(authLocalMgnt()); - app.setup(); - context.method = 'update'; - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); - assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - - it('does not modify context if email not updated', async () => { - app.configure(authLocalMgnt()); - app.setup(); - context.method = 'update'; - context.params.user.email = 'a@a.com'; - - try { - const ctx = await addVerification()(context); - const user = ctx.data; - - assert.deepEqual(user, { email: 'a@a.com', password: '0000000000' }, 'ctx.data modified'); - } catch (err) { - console.log(err); - assert(false, 'unexpected error'); - } - }); - }); -}); - -function makeDateTime (options1 = {}) { - return Date.now() + (options1.delay || defaultVerifyDelay); -} - -function aboutEqualDateTime (time1, time2, msg, delta = 500) { - const diff = Math.abs(time1 - time2); - assert.isAtMost(diff, delta, msg || `times differ by ${diff}ms`); -} +import { assert } from 'chai'; +import feathers, { Application, HookContext } from '@feathersjs/feathers'; +import authLocalMgnt from "../src/index"; +import { addVerification } from '../src/hooks'; +import { timeoutEachTest } from './helpers/config'; +import { + makeDateTime, + aboutEqualDateTime +} from './helpers'; + +describe('add-verification.test.js', function () { + this.timeout(timeoutEachTest); + + let app: Application; + let context: Partial; + + beforeEach(() => { + app = feathers(); + + context = { + type: 'before', + method: 'create', + data: { email: 'a@a.com', password: '0000000000' }, + app, + params: { + user: { email: 'b@b.com' } + } + }; + }); + + describe('basics', () => { + it('works with no options', async () => { + app.configure(authLocalMgnt()); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('delay option works', async () => { + const options = { delay: 1000 * 60 * 60 * 24 * 5 }; // 5 days + app.configure(authLocalMgnt(options)); + app.setup(); + + context = { + type: 'before', + method: 'create', + data: { email: 'a@a.com', password: '0000000000' }, + app + }; + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime(options)); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + }); + + describe('long token', () => { + it('length option works', async () => { + const options = { longTokenLen: 10 }; + app.configure(authLocalMgnt(options)); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal(user.verifyToken.length, (options.longTokenLen) * 2, 'verify token wrong length'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); // small chance of false negative + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + }); + + describe('shortToken', () => { + it('produces digit short token', async () => { + const options = { shortTokenDigits: true }; + app.configure(authLocalMgnt(options)); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('produces alpha short token', async () => { + const options = { shortTokenDigits: false }; + app.configure(authLocalMgnt(options)); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.notMatch(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('length option works with digits', async () => { + const options = { shortTokenLen: 7 }; + app.configure(authLocalMgnt(options)); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.equal(user.verifyShortToken.length, 7, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('length option works with alpha', async () => { + const options = { shortTokenLen: 9, shortTokenDigits: false }; + app.configure(authLocalMgnt(options)); + app.setup(); + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.equal(user.verifyShortToken.length, 9, 'verify short token wrong length'); + assert.notMatch(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + }); + + describe('patch & update', () => { + it('works with patch', async () => { + app.configure(authLocalMgnt()); + app.setup(); + //@ts-ignore + context.method = 'patch'; + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('works with update', async () => { + app.configure(authLocalMgnt()); + app.setup(); + //@ts-ignore + context.method = 'update'; + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal(user.verifyToken.length, 30, 'verify token wrong length'); + assert.equal(user.verifyShortToken.length, 6, 'verify short token wrong length'); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + assert.deepEqual(user.verifyChanges, {}, 'verifyChanges not empty object'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + + it('does not modify context if email not updated', async () => { + app.configure(authLocalMgnt()); + app.setup(); + //@ts-ignore + context.method = 'update'; + context.params.user.email = 'a@a.com'; + + try { + //@ts-ignore + const ctx = await addVerification()(context); + const user = ctx.data; + + assert.deepEqual(user, { email: 'a@a.com', password: '0000000000' }, 'ctx.data modified'); + } catch (err) { + console.log(err); + assert(false, 'unexpected error'); + } + }); + }); +}); diff --git a/test/check-unique.test.js b/test/check-unique.test.ts old mode 100755 new mode 100644 similarity index 91% rename from test/check-unique.test.js rename to test/check-unique.test.ts index c8d118a..c9fadfe --- a/test/check-unique.test.js +++ b/test/check-unique.test.ts @@ -1,210 +1,211 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const { timeoutEachTest } = require('./helpers/config'); - -const makeUsersService = options => - function (app) { - app.use('/users', feathersMemory(options)); - }; - -const usersId = [ - { id: 'a', email: 'a', username: 'john a' }, - { id: 'b', email: 'b', username: 'john b' }, - { id: 'c', email: 'c', username: 'john b' } -]; - -const users_Id = [ - { _id: 'a', email: 'a', username: 'john a' }, - { _id: 'b', email: 'b', username: 'john b' }, - { _id: 'c', email: 'c', username: 'john b' } -]; - -['_id', 'id'].forEach(idType => { - ['paginated', 'non-paginated'].forEach(pagination => { - describe(`check-unique.test.js ${pagination} ${idType}`, function () { - this.timeout(timeoutEachTest); - - describe('standard', () => { - let app; - let usersService; - let authLocalMgntService; - - beforeEach(async () => { - app = feathers(); - app.configure(authLocalMgnt()); - app.configure( - makeUsersService({ - multi: true, - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - await usersService.create( - clone(idType === '_id' ? users_Id : usersId) - ); - }); - - it('returns a promise', async () => { - const res = authLocalMgntService - .create({ - action: 'checkUnique', - value: { username: 'john a' } - }) - .then(() => { }) - .catch(() => { }); - - assert.isOk(res, 'no promise returned'); - assert.isFunction(res.then, 'not a function'); - }); - - it('handles empty query', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: {} - }); - } catch (err) { - console.log(err); - assert(false, `unexpectedly failed: ${err.message}`); - } - }); - - it('handles empty query returning nothing', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'hjhjhj' } - }); - } catch (err) { - console.log(err); - assert(false, `unexpectedly failed: ${err.message}`); - } - }); - - it('finds single query on single item', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john a' } - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Values already taken.'); - assert.equal(err.errors.username, 'Already taken.'); - } - }); - - it('handles noErrMsg option', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john a' }, - meta: { noErrMsg: true } - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Error'); // feathers default for no error message - assert.equal(err.errors.username, 'Already taken.'); - } - }); - - it('finds single query on multiple items', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john b' } - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Values already taken.'); - assert.equal(err.errors.username, 'Already taken.'); - } - }); - - it('finds multiple queries on same item', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john a', email: 'a' } - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Values already taken.'); - assert.equal(err.errors.username, 'Already taken.'); - } - }); - - it('finds multiple queries on different item', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john a', email: 'b' } - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Values already taken.'); - assert.equal(err.errors.username, 'Already taken.'); - } - }); - - it('ignores null & undefined queries', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: undefined, email: null } - }); - } catch (err) { - console.log(err); - assert.fail(true, false, 'test unexpectedly failed'); - } - }); - - it('ignores current user on single item', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john a' }, - ownId: 'a' - }); - } catch (err) { - console.log(err); - assert.fail(true, false, 'test unexpectedly failed'); - } - }); - - it('cannot ignore current user on multiple items', async () => { - try { - await authLocalMgntService.create({ - action: 'checkUnique', - value: { username: 'john b' }, - ownId: 'b' - }); - - assert.fail(true, false, 'test unexpectedly succeeded'); - } catch (err) { - assert.equal(err.message, 'Values already taken.'); - assert.equal(err.errors.username, 'Already taken.'); - } - }); - }); - }); - }); -}); - -// Helpers - -function clone (obj) { - return JSON.parse(JSON.stringify(obj)); -} +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import { timeoutEachTest } from './helpers/config'; +import { AuthenticationManagementService } from '../src/services'; + +const makeUsersService = options => + function (app: Application) { + app.use('/users', feathersMemory(options)); + }; + +const usersId = [ + { id: 'a', email: 'a', username: 'john a' }, + { id: 'b', email: 'b', username: 'john b' }, + { id: 'c', email: 'c', username: 'john b' } +]; + +const users_Id = [ + { _id: 'a', email: 'a', username: 'john a' }, + { _id: 'b', email: 'b', username: 'john b' }, + { _id: 'c', email: 'c', username: 'john b' } +]; + +['_id', 'id'].forEach(idType => { + ['paginated', 'non-paginated'].forEach(pagination => { + describe(`check-unique.test.js ${pagination} ${idType}`, function () { + this.timeout(timeoutEachTest); + + describe('standard', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + + beforeEach(async () => { + app = feathers(); + app.configure(authLocalMgnt()); + app.configure( + makeUsersService({ + multi: true, + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + await usersService.create( + clone(idType === '_id' ? users_Id : usersId) + ); + }); + + it('returns a promise', async () => { + const res = authLocalMgntService + .create({ + action: 'checkUnique', + value: { username: 'john a' } + }) + .then(() => { }) + .catch(() => { }); + + assert.isOk(res, 'no promise returned'); + assert.isFunction(res.then, 'not a function'); + }); + + it('handles empty query', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: {} + }); + } catch (err) { + console.log(err); + assert(false, `unexpectedly failed: ${err.message}`); + } + }); + + it('handles empty query returning nothing', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'hjhjhj' } + }); + } catch (err) { + console.log(err); + assert(false, `unexpectedly failed: ${err.message}`); + } + }); + + it('finds single query on single item', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john a' } + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Values already taken.'); + assert.equal(err.errors.username, 'Already taken.'); + } + }); + + it('handles noErrMsg option', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john a' }, + meta: { noErrMsg: true } + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Error'); // feathers default for no error message + assert.equal(err.errors.username, 'Already taken.'); + } + }); + + it('finds single query on multiple items', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john b' } + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Values already taken.'); + assert.equal(err.errors.username, 'Already taken.'); + } + }); + + it('finds multiple queries on same item', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john a', email: 'a' } + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Values already taken.'); + assert.equal(err.errors.username, 'Already taken.'); + } + }); + + it('finds multiple queries on different item', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john a', email: 'b' } + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Values already taken.'); + assert.equal(err.errors.username, 'Already taken.'); + } + }); + + it('ignores null & undefined queries', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: undefined, email: null } + }); + } catch (err) { + console.log(err); + assert.fail(true, false, 'test unexpectedly failed'); + } + }); + + it('ignores current user on single item', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john a' }, + ownId: 'a' + }); + } catch (err) { + console.log(err); + assert.fail(true, false, 'test unexpectedly failed'); + } + }); + + it('cannot ignore current user on multiple items', async () => { + try { + await authLocalMgntService.create({ + action: 'checkUnique', + value: { username: 'john b' }, + ownId: 'b' + }); + + assert.fail(true, false, 'test unexpectedly succeeded'); + } catch (err) { + assert.equal(err.message, 'Values already taken.'); + assert.equal(err.errors.username, 'Already taken.'); + } + }); + }); + }); + }); +}); + +// Helpers + +function clone (obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/client.test.js b/test/client.test.ts old mode 100755 new mode 100644 similarity index 87% rename from test/client.test.js rename to test/client.test.ts index 3439b99..1520b53 --- a/test/client.test.js +++ b/test/client.test.ts @@ -1,171 +1,172 @@ - -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const AuthManagement = require('../src/client'); - -// users DB -const usersDb = [ - { _id: 'a', email: 'bad', password: 'aa', isVerified: false }, - { _id: 'b', email: 'ok', password: 'bb', isVerified: true } -]; - -let spyData = null; -let spyParams = null; -let spyAuthenticateEmail; -let spyAuthenticatePassword; - -// Fake for authManagementService service -const authLocalMgntFake = function () { - return function authManagement () { // 'function' needed as we use 'this' - const app = this; - const path = 'authManagement'; - - app.use(path, { - create (data, params1, cb) { - spyData = data; - spyParams = params1; - - return cb ? cb(null) : Promise.resolve(); - } - }); - - app.authenticate = (obj) => { - spyAuthenticateEmail = obj.email; - spyAuthenticatePassword = obj.password; - - const index = usersDb[0].email === obj.email ? 0 : 1; - - return Promise.resolve({ data: usersDb[index] }); - }; - - app.log = () => {}; - }; -}; - -// Tests -describe('client.test.js', () => { - describe('instantiate', () => { - it('exists', () => { - assert.isFunction(AuthManagement); - }); - }); - - describe(' methods', () => { - let app; - let authManagement; - - beforeEach(() => { - app = feathers(); - app.configure(authLocalMgntFake()); - app.setup(); - authManagement = new AuthManagement(app); - }); - - it('checkUnique', async () => { - await authManagement.checkUnique({ username: 'john a' }, null, true); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'checkUnique', value: { username: 'john a' }, ownId: null, meta: { noErrMsg: true } - }); - }); - - it('resendVerify', async () => { - await authManagement.resendVerifySignup('a@a.com', { b: 'b' }); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'resendVerifySignup', - value: 'a@a.com', - notifierOptions: { b: 'b' } - }); - }); - - it('verifySignupLong', async () => { - await authManagement.verifySignupLong('000'); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { action: 'verifySignupLong', value: '000' }); - }); - - it('verifySignupShort', async () => { - await authManagement.verifySignupShort('000', { email: 'a@a.com' }); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'verifySignupShort', - value: { token: '000', user: { email: 'a@a.com' } } - }); - }); - - it('sendResetPwd', async () => { - await authManagement.sendResetPwd('a@a.com', { b: 'b' }); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'sendResetPwd', - value: 'a@a.com', - notifierOptions: { b: 'b' } - }); - }); - - it('resetPwdLong', async () => { - await authManagement.resetPwdLong('000', '12345678'); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'resetPwdLong', - value: { token: '000', password: '12345678' } - }); - }); - - it('resetPwdShort', async () => { - await authManagement.resetPwdShort('000', { email: 'a@a.com' }, '12345678'); - - assert.deepEqual(spyParams, {}); - assert.deepEqual(spyData, { - action: 'resetPwdShort', - value: { token: '000', user: { email: 'a@a.com' }, password: '12345678' } - }); - }); - - it('passwordChange', async () => { - await authManagement.passwordChange('12345678', 'password', { email: 'a' }); - - assert.deepEqual(spyData, { - action: 'passwordChange', value: { user: { email: 'a' }, oldPassword: '12345678', password: 'password' } - }); - }); - - it('identityChange', async () => { - await authManagement.identityChange('12345678', { email: 'b@b.com' }, { username: 'q' }); - - assert.deepEqual(spyData, { + +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import AuthManagement from '../src/client'; +import { AuthenticationManagementClient } from '../src/types'; + +// users DB +const usersDb = [ + { _id: 'a', email: 'bad', password: 'aa', isVerified: false }, + { _id: 'b', email: 'ok', password: 'bb', isVerified: true } +]; + +let spyData = null; +let spyParams = null; +let spyAuthenticateEmail; +let spyAuthenticatePassword; + +// Fake for authManagementService service +const authLocalMgntFake = function () { + return function authManagement () { // 'function' needed as we use 'this' + const app = this; + const path = 'authManagement'; + + app.use(path, { + create (data, params1, cb) { + spyData = data; + spyParams = params1; + + return cb ? cb(null) : Promise.resolve(); + } + }); + + app.authenticate = (obj) => { + spyAuthenticateEmail = obj.email; + spyAuthenticatePassword = obj.password; + + const index = usersDb[0].email === obj.email ? 0 : 1; + + return Promise.resolve({ data: usersDb[index] }); + }; + + app.log = () => {}; + }; +}; + +// Tests +describe('client.test.js', () => { + describe('instantiate', () => { + it('exists', () => { + assert.isFunction(AuthManagement); + }); + }); + + describe('methods', () => { + let app: Application; + let authManagement: AuthenticationManagementClient; + + beforeEach(() => { + app = feathers(); + app.configure(authLocalMgntFake()); + app.setup(); + authManagement = AuthManagement(app); + }); + + it('checkUnique', async () => { + await authManagement.checkUnique({ username: 'john a' }, null, true); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'checkUnique', value: { username: 'john a' }, ownId: null, meta: { noErrMsg: true } + }); + }); + + it('resendVerify', async () => { + await authManagement.resendVerifySignup({ email: 'a@a.com'}, { b: 'b' }); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'resendVerifySignup', + value: { email: 'a@a.com' }, + notifierOptions: { b: 'b' } + }); + }); + + it('verifySignupLong', async () => { + await authManagement.verifySignupLong('000'); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { action: 'verifySignupLong', value: '000' }); + }); + + it('verifySignupShort', async () => { + await authManagement.verifySignupShort('000', { email: 'a@a.com' }); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'verifySignupShort', + value: { token: '000', user: { email: 'a@a.com' } } + }); + }); + + it('sendResetPwd', async () => { + await authManagement.sendResetPwd({ email: 'a@a.com'}, { b: 'b' }); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'sendResetPwd', + value: { email: 'a@a.com' }, + notifierOptions: { b: 'b' } + }); + }); + + it('resetPwdLong', async () => { + await authManagement.resetPwdLong('000', '12345678'); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'resetPwdLong', + value: { token: '000', password: '12345678' } + }); + }); + + it('resetPwdShort', async () => { + await authManagement.resetPwdShort('000', { email: 'a@a.com' }, '12345678'); + + assert.deepEqual(spyParams, {}); + assert.deepEqual(spyData, { + action: 'resetPwdShort', + value: { token: '000', user: { email: 'a@a.com' }, password: '12345678' } + }); + }); + + it('passwordChange', async () => { + await authManagement.passwordChange('12345678', 'password', { email: 'a' }); + + assert.deepEqual(spyData, { + action: 'passwordChange', value: { user: { email: 'a' }, oldPassword: '12345678', password: 'password' } + }); + }); + + it('identityChange', async () => { + await authManagement.identityChange('12345678', { email: 'b@b.com' }, { username: 'q' }); + + assert.deepEqual(spyData, { action: 'identityChange', value: { user: { username: 'q' }, - password: '12345678', - changes: { email: 'b@b.com' } } - }); - }); - - it('authenticate is verified', async () => { - const result = await authManagement.authenticate('ok', 'bb'); - - assert.equal(spyAuthenticateEmail, 'ok'); - assert.equal(spyAuthenticatePassword, 'bb'); - assert.deepEqual(result, usersDb[1]); - }); - - it('authenticate is not verified', async () => { - try { - await authManagement.authenticate('bad', '12345678'); - - assert(false, 'unexpected succeeded.'); - } catch (err) { - assert.equal(spyAuthenticateEmail, 'bad'); - assert.equal(spyAuthenticatePassword, '12345678'); - assert.notEqual(err, null); - } - }); - }); -}); + password: '12345678', + changes: { email: 'b@b.com' } } + }); + }); + + it('authenticate is verified', async () => { + const result = await authManagement.authenticate('ok', 'bb'); + + assert.equal(spyAuthenticateEmail, 'ok'); + assert.equal(spyAuthenticatePassword, 'bb'); + assert.deepEqual(result, usersDb[1]); + }); + + it('authenticate is not verified', async () => { + try { + await authManagement.authenticate('bad', '12345678'); + + assert(false, 'unexpected succeeded.'); + } catch (err) { + assert.equal(spyAuthenticateEmail, 'bad'); + assert.equal(spyAuthenticatePassword, '12345678'); + assert.notEqual(err, null); + } + }); + }); +}); diff --git a/test/errors-async-await.test.js b/test/errors-async-await.test.ts old mode 100755 new mode 100644 similarity index 97% rename from test/errors-async-await.test.js rename to test/errors-async-await.test.ts index ea218c0..11a1be6 --- a/test/errors-async-await.test.js +++ b/test/errors-async-await.test.ts @@ -1,6 +1,6 @@ -const assert = require('chai').assert; -const errors = require('@feathersjs/errors'); +import { assert } from 'chai'; +import errors from '@feathersjs/errors'; describe('errors-async-await.js', () => { describe('1 deep', () => { @@ -136,7 +136,7 @@ describe('errors-async-await.js', () => { }); }); -async function service (action, param1, param2) { +async function service (action, param1?, param2?) { switch (action) { case 'ok': return 'service ok'; diff --git a/test/helpers.test.js b/test/helpers.test.ts old mode 100755 new mode 100644 similarity index 85% rename from test/helpers.test.js rename to test/helpers.test.ts index 3b93d1c..a1d10b6 --- a/test/helpers.test.js +++ b/test/helpers.test.ts @@ -1,9 +1,10 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const helpers = require('../src/helpers'); -const authManagementService = require('../src/index'); +import { assert } from 'chai'; +import feathers from '@feathersjs/feathers'; +import feathersMemory from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import helpers from '../src/helpers'; +import authManagementService from '../src/index'; +import { User } from '../src/types'; const makeUsersService = options => function (app) { @@ -17,14 +18,16 @@ const users_Id = [ describe('helpers.js - sanitization', () => { it('allows to stringify sanitized user object', () => { - const user = { + const user: Partial = { id: 1, email: 'test@test.test', password: '0000000000', resetToken: 'aaa' }; + //@ts-ignore const result1 = helpers.sanitizeUserForClient(user); + //@ts-ignore const result2 = helpers.sanitizeUserForNotifier(user); assert.doesNotThrow(() => JSON.stringify(result1)); @@ -39,9 +42,12 @@ describe('helpers.js - sanitization', () => { resetToken: 'aaa' }; + //@ts-ignore user.self = user; + //@ts-ignore const result1 = helpers.sanitizeUserForClient(user); + //@ts-ignore const result2 = helpers.sanitizeUserForNotifier(user); assert.throws(() => JSON.stringify(result1), TypeError); @@ -59,9 +65,12 @@ describe('helpers.js - sanitization', () => { } }; + //@ts-ignore user.self = user; + //@ts-ignore const result1 = helpers.sanitizeUserForClient(user); + //@ts-ignore const result2 = helpers.sanitizeUserForNotifier(user); assert.doesNotThrow(() => JSON.stringify(result1)); @@ -79,9 +88,12 @@ describe('helpers.js - sanitization', () => { } }; + //@ts-ignore user.self = user; + //@ts-ignore const result1 = helpers.sanitizeUserForClient(user); + //@ts-ignore const result2 = helpers.sanitizeUserForNotifier(user); assert.doesNotThrow(() => JSON.stringify(result1)); diff --git a/test/helpers/about-equal-date-time.ts b/test/helpers/about-equal-date-time.ts new file mode 100644 index 0000000..034ee70 --- /dev/null +++ b/test/helpers/about-equal-date-time.ts @@ -0,0 +1,9 @@ +import { assert } from "chai"; + +function aboutEqualDateTime (time1: number, time2: number, msg?: string, delta?: number) { + delta = delta || 600; + const diff = Math.abs(time1 - time2); + assert.isAtMost(diff, delta, msg || `times differ by ${diff}ms`); +} + +export default aboutEqualDateTime; diff --git a/test/helpers/authenticationService.js b/test/helpers/authenticationService.js deleted file mode 100644 index 4181519..0000000 --- a/test/helpers/authenticationService.js +++ /dev/null @@ -1,14 +0,0 @@ -const { AuthenticationService } = require('@feathersjs/authentication'); -const { LocalStrategy } = require('@feathersjs/authentication-local'); -const { authentication: config } = require('./config'); -module.exports = (app, options) => { - if (options) { - app.set('authentication', options); - } else { - app.set('authentication', config); - } - const authService = new AuthenticationService(app); - - authService.register('local', new LocalStrategy()); - return authService; -}; diff --git a/test/helpers/authenticationService.ts b/test/helpers/authenticationService.ts new file mode 100644 index 0000000..83fe436 --- /dev/null +++ b/test/helpers/authenticationService.ts @@ -0,0 +1,16 @@ +import { AuthenticationService } from '@feathersjs/authentication'; +import { LocalStrategy } from '@feathersjs/authentication-local'; +import { Application } from '@feathersjs/feathers'; +import { authentication as config } from './config'; + +export default (app: Application, options?) => { + if (options) { + app.set('authentication', options); + } else { + app.set('authentication', config); + } + const authService = new AuthenticationService(app); + + authService.register('local', new LocalStrategy()); + return authService; +}; diff --git a/test/helpers/basic-spy.js b/test/helpers/basic-spy.ts old mode 100755 new mode 100644 similarity index 91% rename from test/helpers/basic-spy.js rename to test/helpers/basic-spy.ts index a3c60bf..49d22cd --- a/test/helpers/basic-spy.js +++ b/test/helpers/basic-spy.ts @@ -1,80 +1,81 @@ - -/** - * Create a light weight spy on functions. - * - * @param {Function} fcn - to spy on - * @returns {Object} spy. Call fcn with spy.callWith(...). Get params and results with spy.result(). - * @class - * - * (1) To test a function without a callback: - * - * function test(a, b, c) { return ['y', false, [a, b, c]]; } - * const spyTest = new feathersStub.SpyOn(test); - * spyTest.callWith(1, 2, 3); - * spyTest.callWith(4, 5, 6); - * - * spyTest.result(); - * // [ { args: [1, 2, 3], result: ['y', false, [1, 2, 3]] }, - * // { args: [4, 5, 6], result: ['y', false, [4, 5, 6]] } ] - * - * (2) To test a function with a callback as the last param: - * - * function testCb(a, b, c, cb) { setTimeout(() => { return cb('a', true, [a, b, c]); }, 0); } - * const spyTestCb = new SpyOn(testCb); - * spyTestCb.callWithCb(1, 2, 3, (x, y, z) => { - * spyTestCb.callWithCb(8, 9, 0, (x, y, z) => { - * - * spyTestCb.result() - * // [ { args: [1, 2, 3], result: ['a', true, [1, 2, 3]] }, - * // { args: [8, 9, 0], result: ['a', true, [8, 9, 0]] } ] - * }); - * }); - */ - -function SpyOn (fcn) { - if (!(this instanceof SpyOn)) { return new SpyOn(fcn); } - const stack = []; - - // spy on function without a callback - // not being part of prototype chain allows callers to set 'this' - - this.callWith = function (...args) { - const myStackOffset = stack.length; - stack.push({ args: clone(args) }); - const result = fcn.apply(this, args); - stack[myStackOffset].result = result; // can handle recursion - - return result; - }; - - // spy on function with a callback - // not being part of prototype chain allows callers to set 'this' - - this.callWithCb = function (...args) { - const myStackOffset = stack.length; - stack.push({ args: args.slice(0, -1) }); - - args[args.length - 1] = cbWrapper(args[args.length - 1]); - fcn.apply(this, args); - - function cbWrapper (fcnCb) { - return function cbWrapperInner (...args1) { - stack[myStackOffset].result = args1; - - fcnCb.apply(this, args1); - }; - } - }; - - // return spy info - - this.result = function () { - return stack; - }; -} - -module.exports = SpyOn; - -function clone (obj) { - return JSON.parse(JSON.stringify(obj)); -} + +/** + * Create a light weight spy on functions. + * + * @param {Function} fcn - to spy on + * @returns {Object} spy. Call fcn with spy.callWith(...). Get params and results with spy.result(). + * @class + * + * (1) To test a function without a callback: + * + * function test(a, b, c) { return ['y', false, [a, b, c]]; } + * const spyTest = new feathersStub.SpyOn(test); + * spyTest.callWith(1, 2, 3); + * spyTest.callWith(4, 5, 6); + * + * spyTest.result(); + * // [ { args: [1, 2, 3], result: ['y', false, [1, 2, 3]] }, + * // { args: [4, 5, 6], result: ['y', false, [4, 5, 6]] } ] + * + * (2) To test a function with a callback as the last param: + * + * function testCb(a, b, c, cb) { setTimeout(() => { return cb('a', true, [a, b, c]); }, 0); } + * const spyTestCb = SpyOn(testCb); + * spyTestCb.callWithCb(1, 2, 3, (x, y, z) => { + * spyTestCb.callWithCb(8, 9, 0, (x, y, z) => { + * + * spyTestCb.result() + * // [ { args: [1, 2, 3], result: ['a', true, [1, 2, 3]] }, + * // { args: [8, 9, 0], result: ['a', true, [8, 9, 0]] } ] + * }); + * }); + */ + +function SpyOn (fcn) { + const stack = []; + + // spy on function without a callback + // not being part of prototype chain allows callers to set 'this' + + this.callWith = function (...args) { + const myStackOffset = stack.length; + stack.push({ args: clone(args) }); + const result = fcn.apply(this, args); + stack[myStackOffset].result = result; // can handle recursion + + return result; + }; + + // spy on function with a callback + // not being part of prototype chain allows callers to set 'this' + + this.callWithCb = function (...args) { + const myStackOffset = stack.length; + stack.push({ args: args.slice(0, -1) }); + + args[args.length - 1] = cbWrapper(args[args.length - 1]); + fcn.apply(this, args); + + function cbWrapper (fcnCb) { + return function cbWrapperInner (...args1) { + stack[myStackOffset].result = args1; + + fcnCb.apply(this, args1); + }; + } + }; + + // return spy info + + this.result = function () { + return stack; + }; + + return this; +} + +export default SpyOn; + +function clone (obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/helpers/config.js b/test/helpers/config.ts old mode 100755 new mode 100644 similarity index 59% rename from test/helpers/config.js rename to test/helpers/config.ts index fb77947..52eb188 --- a/test/helpers/config.js +++ b/test/helpers/config.ts @@ -1,4 +1,4 @@ -module.exports = { +const config = { timeoutEachTest: 40000, maxTimeAllTests: 1000 * 60 * 60 * 2, // 2 hours defaultVerifyDelay: 1000 * 60 * 60 * 24 * 5, // 5 days @@ -13,3 +13,10 @@ module.exports = { } } }; + +export default config; + +export const timeoutEachTest = config.timeoutEachTest; +export const maxTimeAllTests = config.maxTimeAllTests; +export const defaultVerifyDelay = config.defaultVerifyDelay; +export const authentication = config.authentication; diff --git a/test/helpers/index.ts b/test/helpers/index.ts new file mode 100644 index 0000000..407fea0 --- /dev/null +++ b/test/helpers/index.ts @@ -0,0 +1,13 @@ +import aboutEqualDateTime from "./about-equal-date-time"; +import authenticationService from "./authenticationService"; +import SpyOn from "./basic-spy"; +import config from "./config"; +import makeDateTime from "./make-date-time"; + +export { + aboutEqualDateTime, + authenticationService, + SpyOn, + config, + makeDateTime +} diff --git a/test/helpers/make-date-time.ts b/test/helpers/make-date-time.ts new file mode 100644 index 0000000..be440ee --- /dev/null +++ b/test/helpers/make-date-time.ts @@ -0,0 +1,8 @@ +import { defaultVerifyDelay } from './config'; + +function makeDateTime (options1?: { delay?: number }): number { + options1 = options1 || {}; + return Date.now() + (options1.delay || defaultVerifyDelay); +} + +export default makeDateTime; diff --git a/test/helpers/types.ts b/test/helpers/types.ts new file mode 100644 index 0000000..da01320 --- /dev/null +++ b/test/helpers/types.ts @@ -0,0 +1,16 @@ +import { User } from "../../src/types" + +interface UserTest extends Partial { + email: string, + plainPassword?: string, + plainNewPassword?: string + newPassword?: string +} + +export interface UserTestDB extends UserTest { + _id: string +} + +export interface UserTestLocal extends UserTest { + id: string +} diff --git a/test/identity-change.test.js b/test/identity-change.test.ts old mode 100755 new mode 100644 similarity index 87% rename from test/identity-change.test.js rename to test/identity-change.test.ts index 51870de..a536735 --- a/test/identity-change.test.js +++ b/test/identity-change.test.ts @@ -1,12 +1,15 @@ -const assert = require('chai').assert; -const bcrypt = require('bcryptjs'); -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const SpyOn = require('./helpers/basic-spy'); -const authService = require('./helpers/authenticationService'); -const { hashPassword } = require('../src/helpers'); -const { timeoutEachTest } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import { + SpyOn, + authenticationService as authService +} from './helpers'; +import hashPassword from '../src/helpers/hash-password'; +import { timeoutEachTest } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; const makeUsersService = options => function (app) { @@ -14,12 +17,12 @@ const makeUsersService = options => }; // users DB -const users_Id = [ +const users_Id: UserTestDB[] = [ { _id: 'a', email: 'a', plainPassword: 'aa', isVerified: false }, { _id: 'b', email: 'b', plainPassword: 'bb', isVerified: true } ]; -const usersId = [ +const usersId: UserTestLocal[] = [ { id: 'a', email: 'a', plainPassword: 'aa', isVerified: false }, { id: 'b', email: 'b', plainPassword: 'bb', isVerified: true } ]; @@ -31,9 +34,9 @@ const usersId = [ this.timeout(timeoutEachTest); describe('standard', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -146,14 +149,14 @@ const usersId = [ describe('with notification', () => { let spyNotifier; - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -199,7 +202,9 @@ const usersId = [ assert.equal(user.email, user.email); assert.deepEqual(user.verifyChanges, { email: 'b@b' }); - assert.deepEqual(spyNotifier.result()[0].args, [ + const spy = spyNotifier.result()[0].args; + + assert.deepEqual(spy, [ 'identityChange', Object.assign( {}, @@ -212,7 +217,7 @@ const usersId = [ 'verifyChanges' ) ), - 'password', + { transport: "sms" }, ]); assert.strictEqual(user.isVerified, true, 'isVerified not false'); diff --git a/test/is-verified.test.js b/test/is-verified.test.ts old mode 100755 new mode 100644 similarity index 84% rename from test/is-verified.test.js rename to test/is-verified.test.ts index 7c92fcd..4e5566f --- a/test/is-verified.test.js +++ b/test/is-verified.test.ts @@ -1,62 +1,62 @@ - -const assert = require('chai').assert; -const { isVerified } = require('../src/index').hooks; -const { timeoutEachTest } = require('./helpers/config'); - -describe('is-verified.test.js', function () { - this.timeout(timeoutEachTest); - let context; - - beforeEach(() => { - context = { - type: 'before', - method: 'create', - params: { user: { email: 'a@a.com', password: '0000000000' } } - }; - }); - - it('throws if not before', () => { - context.type = 'after'; - assert.throws(() => { isVerified()(context); }, undefined, undefined, 'after'); - }); - - it('throws if not create, update or patch', () => { - context.method = 'find'; - assert.throws(() => isVerified()(context), undefined, undefined, 'find'); - - context.method = 'get'; - assert.throws(() => isVerified()(context), undefined, undefined, 'get'); - - context.method = 'remove'; - assert.throws(() => isVerified()(context), undefined, undefined, 'remove'); - }); - - it('works with verified used', () => { - context.params.user.isVerified = true; - assert.doesNotThrow(() => { isVerified()(context); }); - }); - - it('throws with unverified user', () => { - context.params.user.isVerified = false; - assert.throws(() => { isVerified()(context); }); - }); - - it('throws if addVerification not run', () => { - assert.throws(() => { isVerified()(context); }); - }); - - it('throws if populate not run', () => { - delete context.params.user; - assert.throws(() => { isVerified()(context); }); - }); - - it('throws with damaged hook', () => { - delete context.params; - assert.throws(() => { isVerified()(context); }); - }); - - it('throws if not before', () => { - context.type = 'after'; - assert.throws(() => { isVerified()(context); }); - }); -}); + +import { assert } from 'chai'; +import isVerified from '../src/hooks/is-verified'; +import { timeoutEachTest } from './helpers/config'; + +describe('is-verified.test.js', function () { + this.timeout(timeoutEachTest); + let context; + + beforeEach(() => { + context = { + type: 'before', + method: 'create', + params: { user: { email: 'a@a.com', password: '0000000000' } } + }; + }); + + it('throws if not before', () => { + context.type = 'after'; + assert.throws(() => { isVerified()(context); }, undefined, undefined); + }); + + it('throws if not create, update or patch', () => { + context.method = 'find'; + assert.throws(() => isVerified()(context), undefined, undefined); + + context.method = 'get'; + assert.throws(() => isVerified()(context), undefined, undefined); + + context.method = 'remove'; + assert.throws(() => isVerified()(context), undefined, undefined); + }); + + it('works with verified used', () => { + context.params.user.isVerified = true; + assert.doesNotThrow(() => { isVerified()(context); }); + }); + + it('throws with unverified user', () => { + context.params.user.isVerified = false; + assert.throws(() => { isVerified()(context); }); + }); + + it('throws if addVerification not run', () => { + assert.throws(() => { isVerified()(context); }); + }); + + it('throws if populate not run', () => { + delete context.params.user; + assert.throws(() => { isVerified()(context); }); + }); + + it('throws with damaged hook', () => { + delete context.params; + assert.throws(() => { isVerified()(context); }); + }); + + it('throws if not before', () => { + context.type = 'after'; + assert.throws(() => { isVerified()(context); }); + }); +}); diff --git a/test/password-change.test.js b/test/password-change.test.ts old mode 100755 new mode 100644 similarity index 88% rename from test/password-change.test.js rename to test/password-change.test.ts index b4278b3..70c49e5 --- a/test/password-change.test.js +++ b/test/password-change.test.ts @@ -1,15 +1,18 @@ -const assert = require('chai').assert; -const auth = require('@feathersjs/authentication-local').hooks; -const bcrypt = require('bcryptjs'); -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const authService = require('./helpers/authenticationService'); -const {authentication: authConfig} = require('./helpers/config'); - -const SpyOn = require('./helpers/basic-spy'); -const {hashPassword} = require('../src/helpers'); -const {timeoutEachTest, maxTimeAllTests} = require('./helpers/config'); +import { assert } from 'chai'; +import bcrypt from 'bcryptjs'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import { authentication as authConfig } from './helpers/config'; + +import { + SpyOn, + authenticationService as authService +} from './helpers'; +import hashPassword from '../src/helpers/hash-password'; +import { timeoutEachTest } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; const makeUsersService = options => function (app) { @@ -17,7 +20,7 @@ const makeUsersService = options => }; // users DB -const users_Id = [ +const users_Id: UserTestDB[] = [ { _id: 'a', email: 'a', @@ -34,7 +37,7 @@ const users_Id = [ } ]; -const usersId = [ +const usersId: UserTestLocal[] = [ { id: 'a', email: 'a', @@ -56,7 +59,7 @@ describe('password-change.js', function () { this.timeout(timeoutEachTest); describe('bcrypt', function () { - let app; + let app: Application; beforeEach(async () => { app = feathers(); @@ -90,9 +93,9 @@ describe('password-change.js', function () { ['paginated' /* 'non-paginated' */].forEach(pagination => { describe(`passwordChange ${pagination} ${idType}`, () => { describe('standard', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -192,14 +195,14 @@ describe('password-change.js', function () { describe('with notification', () => { let spyNotifier; - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); diff --git a/test/randoms.test.js b/test/randoms.test.ts old mode 100755 new mode 100644 similarity index 80% rename from test/randoms.test.js rename to test/randoms.test.ts index 39cd8ca..5c5351d --- a/test/randoms.test.js +++ b/test/randoms.test.ts @@ -1,40 +1,39 @@ - -const assert = require('chai').assert; -const randomDigits = require('../src/helpers').randomDigits; -const randomBytes = require('../src/helpers').randomBytes; - -describe('randoms.js', () => { - describe('randomDigits', () => { - it('correct length', () => { - const str = randomDigits(6); - assert.equal(str.length, 6); - }); - - it('returns different values', () => { - const str1 = randomDigits(6); - const str2 = randomDigits(6); - - assert.equal(str1.length, 6); - assert.equal(str2.length, 6); - - assert.notEqual(str1, str2); - }); - }); - - describe('randomBytes', () => { - it('correct length', async () => { - const str = await randomBytes(10); - - assert.equal(str.length, 20); - }); - - it('returns different values', async () => { - const str1 = await randomBytes(10); - const str2 = await randomBytes(10); - - assert.equal(str1.length, 20); - assert.equal(str2.length, 20); - assert.notEqual(str1, str2); - }); - }); -}); +import { assert } from 'chai'; +import randomDigits from '../src/helpers/random-digits'; +import randomBytes from '../src/helpers/random-bytes'; + +describe('randoms.js', () => { + describe('randomDigits', () => { + it('correct length', () => { + const str = randomDigits(6); + assert.equal(str.length, 6); + }); + + it('returns different values', () => { + const str1 = randomDigits(6); + const str2 = randomDigits(6); + + assert.equal(str1.length, 6); + assert.equal(str2.length, 6); + + assert.notEqual(str1, str2); + }); + }); + + describe('randomBytes', () => { + it('correct length', async () => { + const str = await randomBytes(10); + + assert.equal(str.length, 20); + }); + + it('returns different values', async () => { + const str1 = await randomBytes(10); + const str2 = await randomBytes(10); + + assert.equal(str1.length, 20); + assert.equal(str2.length, 20); + assert.notEqual(str1, str2); + }); + }); +}); diff --git a/test/remove-verification.test.js b/test/remove-verification.test.ts old mode 100755 new mode 100644 similarity index 78% rename from test/remove-verification.test.js rename to test/remove-verification.test.ts index 374ae5a..ce1b964 --- a/test/remove-verification.test.js +++ b/test/remove-verification.test.ts @@ -1,100 +1,102 @@ - -const assert = require('chai').assert; -const hooks = require('../src/index').hooks; - -let context; - -describe('remove-verification.test.js', () => { - beforeEach(() => { - context = { - type: 'after', - method: 'create', - params: { provider: 'socketio' }, - result: { - email: 'a@a.com', - password: '0000000000', - isVerified: true, - verifyToken: '000', - verifyExpires: Date.now(), - verifyChanges: {}, - resetToken: '000', - resetExpires: Date.now() - } - }; - }); - - it('works with verified user', () => { - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - - const user = context.result; - assert.property(user, 'isVerified'); - assert.equal(user.isVerified, true); - assert.notProperty(user, 'verifyToken'); - assert.notProperty(user, 'verifyExpires'); - assert.notProperty(user, 'resetToken'); - assert.notProperty(user, 'resetExpires'); - assert.notProperty(user, 'verifyChanges'); - }); - - it('works with unverified user', () => { - context.result.isVerified = false; - - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - - const user = context.result; - assert.property(user, 'isVerified'); - assert.equal(user.isVerified, false); - assert.notProperty(user, 'verifyToken'); - assert.notProperty(user, 'verifyExpires'); - assert.notProperty(user, 'resetToken'); - assert.notProperty(user, 'resetExpires'); - assert.notProperty(user, 'verifyChanges'); - }); - - it('works if addVerification not run', () => { - context.result = {}; - - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - }); - - it('noop if server initiated', () => { - context.params.provider = undefined; - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - - const user = context.result; - assert.property(user, 'isVerified'); - assert.equal(user.isVerified, true); - assert.property(user, 'verifyToken'); - assert.property(user, 'verifyExpires'); - assert.property(user, 'resetToken'); - assert.property(user, 'resetExpires'); - assert.property(user, 'verifyChanges'); - }); - - it('works with multiple verified user', () => { - context.result = [context.result, context.result]; - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - - context.result.forEach(user => { - assert.property(user, 'isVerified'); - assert.equal(user.isVerified, true); - assert.notProperty(user, 'verifyToken'); - assert.notProperty(user, 'verifyExpires'); - assert.notProperty(user, 'resetToken'); - assert.notProperty(user, 'resetExpires'); - assert.notProperty(user, 'verifyChanges'); - }); - }); - - it('does not throw with damaged hook', () => { - delete context.result; - - assert.doesNotThrow(() => { hooks.removeVerification()(context); }); - }); - - it('throws if not after', () => { - context.type = 'before'; - - assert.throws(() => { hooks.removeVerification()(context); }); - }); -}); + +import { assert } from 'chai'; +import { + removeVerification +} from '../src/hooks'; + +let context; + +describe('remove-verification.test.js', () => { + beforeEach(() => { + context = { + type: 'after', + method: 'create', + params: { provider: 'socketio' }, + result: { + email: 'a@a.com', + password: '0000000000', + isVerified: true, + verifyToken: '000', + verifyExpires: Date.now(), + verifyChanges: {}, + resetToken: '000', + resetExpires: Date.now() + } + }; + }); + + it('works with verified user', () => { + assert.doesNotThrow(() => { removeVerification()(context); }); + + const user = context.result; + assert.property(user, 'isVerified'); + assert.equal(user.isVerified, true); + assert.notProperty(user, 'verifyToken'); + assert.notProperty(user, 'verifyExpires'); + assert.notProperty(user, 'resetToken'); + assert.notProperty(user, 'resetExpires'); + assert.notProperty(user, 'verifyChanges'); + }); + + it('works with unverified user', () => { + context.result.isVerified = false; + + assert.doesNotThrow(() => { removeVerification()(context); }); + + const user = context.result; + assert.property(user, 'isVerified'); + assert.equal(user.isVerified, false); + assert.notProperty(user, 'verifyToken'); + assert.notProperty(user, 'verifyExpires'); + assert.notProperty(user, 'resetToken'); + assert.notProperty(user, 'resetExpires'); + assert.notProperty(user, 'verifyChanges'); + }); + + it('works if addVerification not run', () => { + context.result = {}; + + assert.doesNotThrow(() => { removeVerification()(context); }); + }); + + it('noop if server initiated', () => { + context.params.provider = undefined; + assert.doesNotThrow(() => { removeVerification()(context); }); + + const user = context.result; + assert.property(user, 'isVerified'); + assert.equal(user.isVerified, true); + assert.property(user, 'verifyToken'); + assert.property(user, 'verifyExpires'); + assert.property(user, 'resetToken'); + assert.property(user, 'resetExpires'); + assert.property(user, 'verifyChanges'); + }); + + it('works with multiple verified user', () => { + context.result = [context.result, context.result]; + assert.doesNotThrow(() => { removeVerification()(context); }); + + context.result.forEach(user => { + assert.property(user, 'isVerified'); + assert.equal(user.isVerified, true); + assert.notProperty(user, 'verifyToken'); + assert.notProperty(user, 'verifyExpires'); + assert.notProperty(user, 'resetToken'); + assert.notProperty(user, 'resetExpires'); + assert.notProperty(user, 'verifyChanges'); + }); + }); + + it('does not throw with damaged hook', () => { + delete context.result; + + assert.doesNotThrow(() => { removeVerification()(context); }); + }); + + it('throws if not after', () => { + context.type = 'before'; + + assert.throws(() => { removeVerification()(context); }); + }); +}); diff --git a/test/resend-verify-signup.test.js b/test/resend-verify-signup.test.ts old mode 100755 new mode 100644 similarity index 90% rename from test/resend-verify-signup.test.js rename to test/resend-verify-signup.test.ts index a5d5026..d2c838b --- a/test/resend-verify-signup.test.js +++ b/test/resend-verify-signup.test.ts @@ -1,643 +1,634 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const SpyOn = require('./helpers/basic-spy'); -const { - timeoutEachTest, - maxTimeAllTests, - defaultVerifyDelay -} = require('./helpers/config'); - -const now = Date.now(); - -const makeUsersService = options => - function (app) { - Object.assign(options, { multi: true }); - app.use('/users', feathersMemory(options)); - }; - -const usersId = [ - { - id: 'a', - email: 'a', - isVerified: false, - verifyToken: '000', - verifyShortToken: '00099', - verifyExpires: now + 500, - username: 'Doe' - }, - { - id: 'b', - email: 'b', - isVerified: true, - verifyToken: null, - verifyShortToken: null, - verifyExpires: null - }, - { - id: 'c', - email: 'c', - isVerified: true, - verifyToken: '999', - verifyShortToken: '99900', - verifyExpires: null - } // impossible -]; - -const users_Id = [ - { - _id: 'a', - email: 'a', - isVerified: false, - verifyToken: '000', - verifyShortToken: '00099', - verifyExpires: now + 500, - username: 'Doe' - }, - { - _id: 'b', - email: 'b', - isVerified: true, - verifyToken: null, - verifyShortToken: null, - verifyExpires: null - }, - { - _id: 'c', - email: 'c', - isVerified: true, - verifyToken: '999', - verifyShortToken: '99900', - verifyExpires: null - } // impossible -]; - -['_id', 'id'].forEach(idType => { - ['paginated', 'non-paginated'].forEach(pagination => { - describe(`resend-verify-signup.test.js ${pagination} ${idType}`, function () { - this.timeout(timeoutEachTest); - - function basicTest1 (desc, values) { - describe(desc, () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure(authLocalMgnt({})); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('authLocalMgnt::create exists', () => { - assert.isFunction(authLocalMgntService.create); - }); - - it('updates unverified user', async () => { - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: values[0] - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'result.isVerified not false' - ); - assert.strictEqual( - user.isVerified, - false, - 'isVerified not false' - ); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 30, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 6, - 'verify short token wrong length' - ); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - - it('sanitizes user', async () => { - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: values[1] - }); - - assert.strictEqual( - result.isVerified, - false, - 'isVerified not false' - ); - assert.strictEqual( - result.verifyToken, - undefined, - 'verifyToken not undefined' - ); - assert.strictEqual( - result.verifyShortToken, - undefined, - 'verifyShortToken not undefined' - ); - assert.strictEqual( - result.verifyExpires, - undefined, - 'verifyExpires not undefined' - ); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - - it('error on verified user', async () => { - try { - const result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: values[2] - }); - - assert(false, 'unexpectedly succeeded'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - - it('error on email not found', async () => { - try { - const result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: values[3] - }); - - assert(false, 'unexpectedly succeeded'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - }); - } - - basicTest1('emailOrToken is {email}', [ - { email: 'a' }, - { email: 'a' }, - { email: 'b' }, - { email: 'x' } - ]); - - basicTest1('emailOrToken is {verifyToken}', [ - { verifyToken: '000' }, - { verifyToken: '000' }, - { verifyToken: '999' }, - { verifyToken: 'xxx' } - ]); - - basicTest1('emailOrToken is {verifyShortToken}', [ - { verifyShortToken: '00099' }, - { verifyShortToken: '00099' }, - { verifyShortToken: '99900' }, - { verifyShortToken: 'xxx' } - ]); - - describe('emailOrToken is {verifyToken} can change len', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 10 - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('can change', async () => { - const verifyToken = '000'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { verifyToken } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'user.isVerified not false' - ); - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 20, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 6, - 'verify short token wrong length' - ); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - }); - - describe('short token (digit) can change length', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 15, // need to reset this - shortTokenLen: 8 - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('can change', async () => { - const verifyToken = '000'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { verifyToken } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'user.isVerified not false' - ); - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 30, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 8, - 'verify short token wrong length' - ); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - }); - - describe('short token (alpha) can change length', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 15, // need to reset this - shortTokenLen: 9, - shortTokenDigits: false - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('can change', async () => { - const verifyToken = '000'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { verifyToken } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'user.isVerified not false' - ); - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 30, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 9, - 'verify short token wrong length' - ); - assert.notMatch(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - }); - - describe('use affirming properties', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 15, // need to reset this - shortTokenLen: 6, - shortTokenDigits: false - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('verifies when correct', async () => { - const verifyToken = '000'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { - verifyToken, - email: 'a' - } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'user.isVerified not false' - ); - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 30, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 6, - 'verify short token wrong length' - ); - assert.notMatch(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - - it('fails when incorrect', async () => { - const verifyToken = '000'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { - verifyToken, - email: 'a', - username: 'Doexxxxxxx' - } - }); - - assert(false, 'unexpectedly succeeded'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - - it('fails when hacks attempted', async () => { - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { - username: 'Doe' - } - }); - - assert(false, 'unexpectedly succeeded'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - }); - - describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - let spyNotifier; - - beforeEach(async () => { - spyNotifier = new SpyOn(notifier); - - app = feathers(); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 15, // need to reset this - shortTokenLen: 6, // need to reset this - shortTokenDigits: true, // need to reset this - notifier: spyNotifier.callWith - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('is called', async () => { - const email = 'a'; - - try { - result = await authLocalMgntService.create({ - action: 'resendVerifySignup', - value: { email }, - notifierOptions: { transport: 'email' } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual( - result.isVerified, - false, - 'user.isVerified not false' - ); - - assert.strictEqual(user.isVerified, false, 'isVerified not false'); - assert.isString(user.verifyToken, 'verifyToken not String'); - assert.equal( - user.verifyToken.length, - 30, - 'verify token wrong length' - ); - assert.equal( - user.verifyShortToken.length, - 6, - 'verify short token wrong length' - ); - assert.match(user.verifyShortToken, /^[0-9]+$/); - aboutEqualDateTime(user.verifyExpires, makeDateTime()); - - assert.deepEqual(spyNotifier.result()[0].args, [ - 'resendVerifySignup', - sanitizeUserForEmail(user), - { transport: 'email' } - ]); - } catch (err) { - console.log(err); - assert.strictEqual(err, null, 'err code set'); - } - }); - }); - }); - }); -}); - -// Helpers - -async function notifier (action, user, notifierOptions, newEmail) { - return user; -} - -function makeDateTime (options1) { - options1 = options1 || {}; - return Date.now() + (options1.delay || defaultVerifyDelay); -} - -function aboutEqualDateTime (time1, time2, msg, delta) { - delta = delta || 500; - const diff = Math.abs(time1 - time2); - assert.isAtMost(diff, delta, msg || `times differ by ${diff}ms`); -} - -function sanitizeUserForEmail (user) { - const user1 = clone(user); - delete user1.password; - return user1; -} - -function clone (obj) { - return JSON.parse(JSON.stringify(obj)); -} +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import { + SpyOn, + aboutEqualDateTime, + makeDateTime +} from './helpers'; +import { timeoutEachTest, defaultVerifyDelay } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; + +const now = Date.now(); + +const makeUsersService = options => + function (app) { + Object.assign(options, { multi: true }); + app.use('/users', feathersMemory(options)); + }; + +const usersId: UserTestLocal[] = [ + { + id: 'a', + email: 'a', + isVerified: false, + verifyToken: '000', + verifyShortToken: '00099', + verifyExpires: now + 500, + username: 'Doe' + }, + { + id: 'b', + email: 'b', + isVerified: true, + verifyToken: null, + verifyShortToken: null, + verifyExpires: null + }, + { + id: 'c', + email: 'c', + isVerified: true, + verifyToken: '999', + verifyShortToken: '99900', + verifyExpires: null + } // impossible +]; + +const users_Id: UserTestDB[] = [ + { + _id: 'a', + email: 'a', + isVerified: false, + verifyToken: '000', + verifyShortToken: '00099', + verifyExpires: now + 500, + username: 'Doe' + }, + { + _id: 'b', + email: 'b', + isVerified: true, + verifyToken: null, + verifyShortToken: null, + verifyExpires: null + }, + { + _id: 'c', + email: 'c', + isVerified: true, + verifyToken: '999', + verifyShortToken: '99900', + verifyExpires: null + } // impossible +]; + +['_id', 'id'].forEach(idType => { + ['paginated', 'non-paginated'].forEach(pagination => { + describe(`resend-verify-signup.test.js ${pagination} ${idType}`, function () { + this.timeout(timeoutEachTest); + + function basicTest1 (desc, values) { + describe(desc, () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure(authLocalMgnt({})); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('authLocalMgnt::create exists', () => { + assert.isFunction(authLocalMgntService.create); + }); + + it('updates unverified user', async () => { + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: values[0] + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'result.isVerified not false' + ); + assert.strictEqual( + user.isVerified, + false, + 'isVerified not false' + ); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 30, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 6, + 'verify short token wrong length' + ); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + + it('sanitizes user', async () => { + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: values[1] + }); + + assert.strictEqual( + result.isVerified, + false, + 'isVerified not false' + ); + assert.strictEqual( + result.verifyToken, + undefined, + 'verifyToken not undefined' + ); + assert.strictEqual( + result.verifyShortToken, + undefined, + 'verifyShortToken not undefined' + ); + assert.strictEqual( + result.verifyExpires, + undefined, + 'verifyExpires not undefined' + ); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + + it('error on verified user', async () => { + try { + const result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: values[2] + }); + + assert(false, 'unexpectedly succeeded'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + + it('error on email not found', async () => { + try { + const result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: values[3] + }); + + assert(false, 'unexpectedly succeeded'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + }); + } + + basicTest1('emailOrToken is {email}', [ + { email: 'a' }, + { email: 'a' }, + { email: 'b' }, + { email: 'x' } + ]); + + basicTest1('emailOrToken is {verifyToken}', [ + { verifyToken: '000' }, + { verifyToken: '000' }, + { verifyToken: '999' }, + { verifyToken: 'xxx' } + ]); + + basicTest1('emailOrToken is {verifyShortToken}', [ + { verifyShortToken: '00099' }, + { verifyShortToken: '00099' }, + { verifyShortToken: '99900' }, + { verifyShortToken: 'xxx' } + ]); + + describe('emailOrToken is {verifyToken} can change len', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 10 + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('can change', async () => { + const verifyToken = '000'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { verifyToken } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'user.isVerified not false' + ); + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 20, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 6, + 'verify short token wrong length' + ); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + }); + + describe('short token (digit) can change length', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 15, // need to reset this + shortTokenLen: 8 + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('can change', async () => { + const verifyToken = '000'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { verifyToken } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'user.isVerified not false' + ); + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 30, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 8, + 'verify short token wrong length' + ); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + }); + + describe('short token (alpha) can change length', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 15, // need to reset this + shortTokenLen: 9, + shortTokenDigits: false + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('can change', async () => { + const verifyToken = '000'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { verifyToken } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'user.isVerified not false' + ); + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 30, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 9, + 'verify short token wrong length' + ); + assert.notMatch(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + }); + + describe('use affirming properties', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 15, // need to reset this + shortTokenLen: 6, + shortTokenDigits: false + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('verifies when correct', async () => { + const verifyToken = '000'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { + verifyToken, + email: 'a' + } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'user.isVerified not false' + ); + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 30, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 6, + 'verify short token wrong length' + ); + assert.notMatch(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + + it('fails when incorrect', async () => { + const verifyToken = '000'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { + verifyToken, + email: 'a', + username: 'Doexxxxxxx' + } + }); + + assert(false, 'unexpectedly succeeded'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + + it('fails when hacks attempted', async () => { + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { + username: 'Doe' + } + }); + + assert(false, 'unexpectedly succeeded'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + }); + + describe('with notification', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + let spyNotifier; + + beforeEach(async () => { + spyNotifier = SpyOn(notifier); + + app = feathers(); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 15, // need to reset this + shortTokenLen: 6, // need to reset this + shortTokenDigits: true, // need to reset this + notifier: spyNotifier.callWith + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('is called', async () => { + const email = 'a'; + + try { + result = await authLocalMgntService.create({ + action: 'resendVerifySignup', + value: { email }, + notifierOptions: { transport: 'email' } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual( + result.isVerified, + false, + 'user.isVerified not false' + ); + + assert.strictEqual(user.isVerified, false, 'isVerified not false'); + assert.isString(user.verifyToken, 'verifyToken not String'); + assert.equal( + user.verifyToken.length, + 30, + 'verify token wrong length' + ); + assert.equal( + user.verifyShortToken.length, + 6, + 'verify short token wrong length' + ); + assert.match(user.verifyShortToken, /^[0-9]+$/); + aboutEqualDateTime(user.verifyExpires, makeDateTime()); + + assert.deepEqual(spyNotifier.result()[0].args, [ + 'resendVerifySignup', + sanitizeUserForEmail(user), + { transport: 'email' } + ]); + } catch (err) { + console.log(err); + assert.strictEqual(err, null, 'err code set'); + } + }); + }); + }); + }); +}); + +// Helpers + +async function notifier (action, user, notifierOptions, newEmail) { + return user; +} + +function sanitizeUserForEmail (user) { + const user1 = clone(user); + delete user1.password; + return user1; +} + +function clone (obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/reset-pwd-long.test.js b/test/reset-pwd-long.test.ts old mode 100755 new mode 100644 similarity index 90% rename from test/reset-pwd-long.test.js rename to test/reset-pwd-long.test.ts index d955c58..09040b5 --- a/test/reset-pwd-long.test.js +++ b/test/reset-pwd-long.test.ts @@ -1,12 +1,13 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const authService = require('./helpers/authenticationService'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import authService from './helpers/authenticationService'; -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const SpyOn = require('./helpers/basic-spy'); -const { hashPassword } = require('../src/helpers'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import { SpyOn } from './helpers'; +import { hashPassword } from '../src/helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -87,9 +88,9 @@ const usersId = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -237,15 +238,15 @@ const usersId = [ }); describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; let spyNotifier; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -323,7 +324,7 @@ const usersId = [ value: { token: 'a___999', // invalid token password: '123456', - user: { email: db[i].email }, + //user: { email: db[i].email }, } }); } catch {} @@ -333,7 +334,7 @@ const usersId = [ value: { token: spyNotifier.result()[0].args[1].resetToken, password: '123456', - user: { email: db[i].email }, + //user: { email: db[i].email }, } }); assert(false, 'unexpected succeeded.'); @@ -342,15 +343,15 @@ const usersId = [ }); describe('with reusable token', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let spyNotifier; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -390,22 +391,22 @@ const usersId = [ value: { token: spyNotifier.result()[0].args[1].resetToken, password: '123456', - user: { email: db[i].email }, + //user: { email: db[i].email }, } }); }); }); describe('not expiring on token error', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let spyNotifier; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -440,7 +441,7 @@ const usersId = [ value: { token: 'a___999', // invalid token password: '123456', - user: { email: db[i].email }, + //user: { email: db[i].email }, } }); } catch {} @@ -449,7 +450,7 @@ const usersId = [ value: { token: spyNotifier.result()[0].args[1].resetToken, password: '123456', - user: { email: db[i].email }, + //user: { email: db[i].email }, } }); }); diff --git a/test/reset-pwd-short.test.js b/test/reset-pwd-short.test.ts old mode 100755 new mode 100644 similarity index 93% rename from test/reset-pwd-short.test.js rename to test/reset-pwd-short.test.ts index d0df96a..dd6969a --- a/test/reset-pwd-short.test.js +++ b/test/reset-pwd-short.test.ts @@ -1,11 +1,16 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const authService = require('./helpers/authenticationService'); -const SpyOn = require('./helpers/basic-spy'); -const { hashPassword } = require('../src/helpers'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; + +import { + SpyOn, + authenticationService as authService +} from './helpers'; +import { hashPassword } from '../src/helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -15,7 +20,7 @@ const makeUsersService = options => }; const fieldToHash = 'resetShortToken'; -const users_Id = [ +const users_Id: UserTestDB[] = [ // The added time interval must be longer than it takes to run ALL the tests { _id: 'a', @@ -55,7 +60,7 @@ const users_Id = [ } ]; -const usersId = [ +const usersId: UserTestLocal[] = [ // The added time interval must be longer than it takes to run ALL the tests { id: 'a', @@ -102,9 +107,9 @@ const usersId = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -386,15 +391,15 @@ const usersId = [ }); describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; let spyNotifier; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -408,8 +413,7 @@ const usersId = [ app.configure( authLocalMgnt({ // maybe reset identifyUserProps - notifier: spyNotifier.callWith, - testMode: true + notifier: spyNotifier.callWith }) ); app.setup(); diff --git a/test/scaffolding.test.js b/test/scaffolding.test.js deleted file mode 100755 index c610027..0000000 --- a/test/scaffolding.test.js +++ /dev/null @@ -1,167 +0,0 @@ - -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const authManagement = require('../src/index'); -const helpers = require('../src/helpers'); - -const optionsDefault = { - app: null, - service: '/users', // need exactly this for test suite - path: 'authManagement', - notifier: () => Promise.resolve(), - longTokenLen: 15, // token's length will be twice this - shortTokenLen: 6, - shortTokenDigits: true, - resetDelay: 1000 * 60 * 60 * 2, // 2 hours - delay: 1000 * 60 * 60 * 24 * 5, // 5 days - resetAttempts: 0, - reuseResetToken: false, - identifyUserProps: ['email'], - sanitizeUserForClient: helpers.sanitizeUserForClient -}; - -const userMgntOptions = { - service: '/users', - notifier: () => Promise.resolve(), - shortTokenLen: 8 -}; - -const orgMgntOptions = { - service: '/organizations', - path: 'authManagement/org', // *** specify path for this instance of service - notifier: () => Promise.resolve(), - shortTokenLen: 10 -}; - -function services () { - const app = this; - app.configure(user); - app.configure(organization); -} - -function user () { - const app = this; - - app.use('/users', { - async create (data) { return data; } - }); - - const service = app.service('/users'); - - service.hooks({ - before: { create: authManagement.hooks.addVerification() } - }); -} - -function organization () { - const app = this; - - app.use('/organizations', { - async create (data) { return data; } - }); - - const service = app.service('/organizations'); - - service.hooks({ - before: { create: authManagement.hooks.addVerification('authManagement/org') } // *** which one - }); -} - -describe('scaffolding.js', () => { - describe('can configure 1 service', () => { - let app; - - beforeEach(() => { - app = feathers(); - app.configure(authManagement(userMgntOptions)); - app.configure(services); - app.setup(); - }); - - it('can create an item', async () => { - const user = app.service('/users'); - - const result = await user.create({ username: 'John Doe' }); - assert.equal(result.username, 'John Doe'); - assert.equal(result.verifyShortToken.length, 8); - }); - - it('can call service', async () => { - const authLocalMgntService = app.service('authManagement'); - - const options = await authLocalMgntService.create({ action: 'options' }); - - assert.property(options, 'app'); - assert.property(options, 'notifier'); - delete options.app; - delete options.notifier; - - const expected = Object.assign({}, optionsDefault, userMgntOptions); - delete expected.app; - delete expected.notifier; - - assert.deepEqual(options, expected); - }); - }); - - describe('can configure 2 services', () => { - let app; - - beforeEach(() => { - app = feathers(); - app.configure(authManagement(userMgntOptions)); - app.configure(authManagement(orgMgntOptions)); - app.configure(services); - app.setup(); - }); - - it('can create items', async () => { - const user = app.service('/users'); - const organization = app.service('/organizations'); - - // create a user item - const result = await user.create({ username: 'John Doe' }); - - assert.equal(result.username, 'John Doe'); - assert.equal(result.verifyShortToken.length, 8); - - // create an organization item - const result1 = await organization.create({ organization: 'Black Ice' }); - - assert.equal(result1.organization, 'Black Ice'); - assert.equal(result1.verifyShortToken.length, 10); - }); - - it('can call services', async () => { - const authLocalMgntService = app.service('authManagement'); // *** the default - const authMgntOrgService = app.service('authManagement/org'); // *** which one - - // call the user instance - const options = await authLocalMgntService.create({ action: 'options' }); - - assert.property(options, 'app'); - assert.property(options, 'notifier'); - delete options.app; - delete options.notifier; - - const expected = Object.assign({}, optionsDefault, userMgntOptions); - delete expected.app; - delete expected.notifier; - - assert.deepEqual(options, expected); - - // call the organization instance - const options1 = await authMgntOrgService.create({ action: 'options' }); - assert.property(options1, 'app'); - assert.property(options1, 'notifier'); - delete options1.app; - delete options1.notifier; - - const expected1 = Object.assign({}, optionsDefault, orgMgntOptions); - delete expected1.app; - delete expected1.notifier; - - assert.deepEqual(options1, expected1); - }); - }); -}); diff --git a/test/scaffolding.test.ts b/test/scaffolding.test.ts new file mode 100644 index 0000000..504d936 --- /dev/null +++ b/test/scaffolding.test.ts @@ -0,0 +1,384 @@ + +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import socketio from "@feathersjs/socketio"; +import authManagement from '../src/index'; +import helpers from '../src/helpers'; + +import { + AuthenticationManagementService, + IdentityChangeService, + PasswordChangeService, + ResendVerifySignupService, + ResetPwdLongService, + ResetPwdShortService, + SendResetPwdService, + VerifySignupLongService, + VerifySignupSetPasswordLongService, + VerifySignupSetPasswordShortService, + VerifySignupShortService, + CheckUniqueService +} from '../src'; +import { + AuthenticationManagementConfigureOptions +} from '../src/types'; + +import "@feathersjs/transport-commons"; + +const optionsDefault: Omit = { + service: '/users', // need exactly this for test suite + path: "authManagement", + notifier: () => Promise.resolve(), + longTokenLen: 15, // token's length will be twice this + shortTokenLen: 6, + shortTokenDigits: true, + resetDelay: 1000 * 60 * 60 * 2, // 2 hours + delay: 1000 * 60 * 60 * 24 * 5, // 5 days + resetAttempts: 0, + reuseResetToken: false, + identifyUserProps: ['email'], + sanitizeUserForClient: helpers.sanitizeUserForClient, + skipIsVerifiedCheck: false, + passwordField: "password", + useSeparateServices: { + checkUnique: 'authManagement/check-unique', + identityChange: 'authManagement/identity-change', + passwordChange: 'authManagement/password-change', + resendVerifySignup: 'authManagement/resend-verify-signup', + resetPwdLong: 'authManagement/reset-password-long', + resetPwdShort: 'authManagement/reset-password-short', + sendResetPwd: 'authManagement/send-reset-pwd', + verifySignupLong: 'authManagement/verify-signup-long', + verifySignupSetPasswordLong: 'authManagement/verify-signup-set-password-long', + verifySignupSetPasswordShort: 'authManagement/verify-signup-set-password-short', + verifySignupShort: 'authManagement/verify-signup-short' + } +}; + +const userMgntOptions = { + service: '/users', + notifier: () => Promise.resolve(), + shortTokenLen: 8 +}; + +const orgMgntOptions = { + service: '/organizations', + path: 'authManagement/org', // *** specify path for this instance of service + notifier: () => Promise.resolve(), + shortTokenLen: 10 +}; + +function services () { + const app = this; + app.configure(user); + app.configure(organization); +} + +function user () { + const app = this; + + app.use('/users', { + async create (data) { return data; } + }); + + const service = app.service('/users'); + + service.hooks({ + // @ts-ignore + before: { create: authManagement.hooks.addVerification() } + }); +} + +function organization () { + const app = this; + + app.use('/organizations', { + async create (data) { return data; } + }); + + const service = app.service('/organizations'); + + service.hooks({ + // @ts-ignore + before: { create: authManagement.hooks.addVerification('authManagement/org') } // *** which one + }); +} + +describe('scaffolding.js', () => { + describe('can configure 1 service', () => { + let app: Application; + + beforeEach(() => { + app = feathers(); + app.configure(socketio()); + app.configure(authManagement(userMgntOptions)); + app.configure(services); + app.setup(); + }); + + it('can create an item', async () => { + const usersService = app.service('/users'); + + const user = await usersService.create({ username: 'John Doe' }); + assert.equal(user.username, 'John Doe'); + assert.equal(user.verifyShortToken.length, 8); + }); + + it('can call service', async () => { + const authLocalMgntService: AuthenticationManagementService = app.service('authManagement'); + + const { options } = authLocalMgntService; + + assert.property(options, 'app'); + assert.property(options, 'notifier'); + delete options.app; + delete options.notifier; + + const useSeparateServices = { + checkUnique: 'authManagement/check-unique', + identityChange: 'authManagement/identity-change', + passwordChange: 'authManagement/password-change', + resendVerifySignup: 'authManagement/resend-verify-signup', + resetPwdLong: 'authManagement/reset-password-long', + resetPwdShort: 'authManagement/reset-password-short', + sendResetPwd: 'authManagement/send-reset-pwd', + verifySignupLong: 'authManagement/verify-signup-long', + verifySignupSetPasswordLong: 'authManagement/verify-signup-set-password-long', + verifySignupSetPasswordShort: 'authManagement/verify-signup-set-password-short', + verifySignupShort: 'authManagement/verify-signup-short' + } + + const expected = Object.assign({}, optionsDefault, userMgntOptions); + delete expected.notifier; + + //@ts-expect-error thinks options has options + assert.deepEqual(options, expected); + + Object.values(useSeparateServices).forEach(path => { + const service = app.service(path); + assert.ok(service, `registered service at: '${path}'`); + }); + }); + + it("does not call publish on authManagement", async () => { + const usersService = app.service('/users'); + + const authManagementService = app.service("authManagement") + + assert.ok(authManagementService, "registered the service"); + + let calledUserEvent = false; + let calledAuthMgmtEvent = false; + + app.publish((data, context) => { + if (context.path === "users") { + calledUserEvent = true; + } + if (context.path === "authManagement") { + calledAuthMgmtEvent = true; + throw "it should not get here"; + } + }); + + await usersService.create({ username: 'John Doe' }); + await new Promise(resolve => setTimeout(resolve, 50)); + assert.strictEqual(calledUserEvent, true, "published user data"); + assert.strictEqual(calledAuthMgmtEvent, false, "not published authManagement data"); + }); + }); + + describe('can configure 2 services', () => { + let app: Application; + + beforeEach(() => { + app = feathers(); + app.configure(authManagement(userMgntOptions)); + app.configure(authManagement(orgMgntOptions)); + app.configure(services); + app.setup(); + }); + + it('can create items', async () => { + const usersService = app.service('/users'); + const organizationsService = app.service('/organizations'); + + // create a user item + const result = await usersService.create({ username: 'John Doe' }); + + assert.equal(result.username, 'John Doe'); + assert.equal(result.verifyShortToken.length, 8); + + // create an organization item + const result1 = await organizationsService.create({ organization: 'Black Ice' }); + + assert.equal(result1.organization, 'Black Ice'); + assert.equal(result1.verifyShortToken.length, 10); + }); + + it('can call services', async () => { + const authLocalMgntService: AuthenticationManagementService = app.service('authManagement'); // *** the default + const authMgntOrgService: AuthenticationManagementService = app.service('authManagement/org'); // *** which one + + // call the user instance + const { options } = authLocalMgntService; + + assert.property(options, 'app'); + assert.property(options, 'notifier'); + delete options.app; + delete options.notifier; + + const useSeparateServices = { + checkUnique: 'authManagement/check-unique', + identityChange: 'authManagement/identity-change', + passwordChange: 'authManagement/password-change', + resendVerifySignup: 'authManagement/resend-verify-signup', + resetPwdLong: 'authManagement/reset-password-long', + resetPwdShort: 'authManagement/reset-password-short', + sendResetPwd: 'authManagement/send-reset-pwd', + verifySignupLong: 'authManagement/verify-signup-long', + verifySignupSetPasswordLong: 'authManagement/verify-signup-set-password-long', + verifySignupSetPasswordShort: 'authManagement/verify-signup-set-password-short', + verifySignupShort: 'authManagement/verify-signup-short' + } + + const expected = Object.assign({}, optionsDefault, userMgntOptions); + delete expected.notifier; + + //@ts-expect-error thinks options has options + assert.deepEqual(options, expected); + + Object.values(useSeparateServices).forEach(path => { + const service = app.service(path); + assert.ok(service, `registered service at: '${path}'`); + }); + + // call the organization instance + const options1 = authMgntOrgService.options; + + assert.property(options1, 'app'); + assert.property(options1, 'notifier'); + delete options1.app; + delete options1.notifier; + + const useSeparateServicesOrg = { + checkUnique: 'authManagement/org/check-unique', + identityChange: 'authManagement/org/identity-change', + passwordChange: 'authManagement/org/password-change', + resendVerifySignup: 'authManagement/org/resend-verify-signup', + resetPwdLong: 'authManagement/org/reset-password-long', + resetPwdShort: 'authManagement/org/reset-password-short', + sendResetPwd: 'authManagement/org/send-reset-pwd', + verifySignupLong: 'authManagement/org/verify-signup-long', + verifySignupSetPasswordLong: 'authManagement/org/verify-signup-set-password-long', + verifySignupSetPasswordShort: 'authManagement/org/verify-signup-set-password-short', + verifySignupShort: 'authManagement/org/verify-signup-short' + } + + const expected1 = Object.assign({}, optionsDefault, orgMgntOptions, { useSeparateServices: useSeparateServicesOrg }); + delete expected1.notifier; + + //@ts-expect-error thinks options has options + assert.deepEqual(options1, expected1); + + Object.values(useSeparateServicesOrg).forEach(path => { + const service = app.service(path); + assert.ok(service, `registered service at: '${path}'`); + }); + }); + }); + + describe('useSeparateServices', () => { + const makeApp = (options: Partial) => { + const app = feathers(); + app.configure(authManagement(options)); + app.configure(services); + app.setup(); + return app; + } + + it('can disable all separate services with \'false\'', async () => { + const app = makeApp({ useSeparateServices: false }); + const authLocalMgntService: AuthenticationManagementService = app.service('authManagement'); + + const servicePaths = Object.keys(app.services); + assert.deepEqual(servicePaths.sort(), ["authManagement", "organizations", "users"].sort(), 'has no other services') + }); + + it('can disable certain services', async () => { + const app = makeApp({ useSeparateServices: { + checkUnique: false, + verifySignupShort: false + } }); + + assert.notOk(app.service("authManagement/check-unique"), "does not have 'checkUnique' service"); + assert.notOk(app.service("authManagement/verify-signup-short"), "does not have 'verifySignupShort' service"); + }); + + it('can set custom service paths', async () => { + const app = makeApp({ useSeparateServices: { + checkUnique: 'super-custom-service' + } }); + + assert.ok(app.service('super-custom-service'), 'registered on custom path'); + }); + }); + + describe('services independently', () => { + it("can register all services independently at custom routes", () => { + const app = feathers(); + app.configure(services); + app.use("am", new AuthenticationManagementService({ app })); + app.use("am/2", new IdentityChangeService({ app })); + app.use("am/3", new PasswordChangeService({ app })); + app.use("am/4", new ResendVerifySignupService({ app })); + app.use("am/5", new ResetPwdLongService({ app })); + app.use("am/6", new ResetPwdShortService({ app })); + app.use("am/7", new SendResetPwdService({ app })); + app.use("am/8", new VerifySignupLongService({ app })); + app.use("am/9", new VerifySignupSetPasswordLongService({ app })); + app.use("am/10", new VerifySignupSetPasswordShortService({ app })); + app.use("am/11", new VerifySignupShortService({ app })); + app.use("am/1", new CheckUniqueService({ app })); + app.setup(); + + const servicePaths = Object.keys(app.services); + + const expected = [ + "am", "am/1", "am/2", "am/3", "am/4", "am/5", "am/6", "am/7", "am/8", "am/9", "am/10", "am/11" + ] + + expected.forEach(path => { + assert.ok(servicePaths.includes(path), `registered '${path}' correctly`); + }) + }); + + it("fails without options: { app }", () => { + const app = feathers(); + app.configure(services); + const classes = [ + AuthenticationManagementService, + CheckUniqueService, + IdentityChangeService, + PasswordChangeService, + ResendVerifySignupService, + ResetPwdLongService, + ResetPwdShortService, + SendResetPwdService, + VerifySignupLongService, + VerifySignupSetPasswordLongService, + VerifySignupSetPasswordShortService, + VerifySignupShortService, + ]; + + classes.forEach(Service => { + //@ts-expect-error + assert.throws(() => new Service()); + }) + + classes.forEach(Service => { + //@ts-expect-error + assert.throws(() => new Service({})); + }) + }) + }); +}); diff --git a/test/send-reset-pwd.test.js b/test/send-reset-pwd.test.ts old mode 100755 new mode 100644 similarity index 89% rename from test/send-reset-pwd.test.js rename to test/send-reset-pwd.test.ts index 3ae3837..8515f52 --- a/test/send-reset-pwd.test.js +++ b/test/send-reset-pwd.test.ts @@ -1,438 +1,439 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const authService = require('./helpers/authenticationService'); - -const SpyOn = require('./helpers/basic-spy'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); - -const now = Date.now(); -const timeout = timeoutEachTest; - -const makeUsersService = options => - function (app) { - Object.assign(options, { multi: true }); - app.use('/users', feathersMemory(options)); - }; - -const usersId = [ - { - id: 'a', - email: 'a', - isVerified: false, - verifyToken: '000', - verifyExpires: now + maxTimeAllTests - }, - { - id: 'b', - email: 'b', - isVerified: true, - verifyToken: null, - verifyExpires: null - } -]; - -const users_Id = [ - { - _id: 'a', - email: 'a', - isVerified: false, - verifyToken: '000', - verifyExpires: now + maxTimeAllTests - }, - { - _id: 'b', - email: 'b', - isVerified: true, - verifyToken: null, - verifyExpires: null - } -]; - -['_id', 'id'].forEach(idType => { - ['paginated', 'non-paginated'].forEach(pagination => { - describe(`send-reset-pwd.js ${pagination} ${idType}`, function () { - this.timeout(timeoutEachTest); - - describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.use('/authentication', authService(app)); - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure(authLocalMgnt({})); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('updates verified user', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user = await usersService.get(result.id || result._id); - assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); - - assert.strictEqual(user.isVerified, true, 'isVerified not true'); - assert.isString(user.resetToken, 'resetToken not String'); - assert.equal(user.resetToken.length, 60, 'reset token wrong length'); - assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); - assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); - aboutEqualDateTime(user.resetExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - - it('error on unverified user', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'a' } - }); - - assert(false, 'unexpected succeeded.'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - - it('error on email not found', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'x' } - }); - - assert(false, 'unexpected succeeded.'); - } catch (err) { - assert.isString(err.message); - assert.isNotFalse(err.message); - } - }); - - it('user is sanitized', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - - assert.strictEqual(result.isVerified, true, 'isVerified not true'); - assert.strictEqual(result.resetToken, undefined, 'resetToken not undefined'); - assert.strictEqual(result.resetShortToken, undefined, 'resetToken not undefined'); - assert.strictEqual(result.resetExpires, undefined, 'resetExpires not undefined'); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - }); - - describe('length can change (digits)', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.use('/authentication', authService(app)); - - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - resetDelay: 200, - reuseResetToken: true, - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('token is reusable with options.reuseResetToken', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user1 = await usersService.get(result.id || result._id); - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user2 = await usersService.get(result.id || result._id); - - assert.equal(user1.resetToken, user2.resetToken, 'reset token has changed'); - assert.equal(user1.resetShortToken, user2.resetShortToken, 'reset short token has changed'); - assert.equal(user1.resetExpires, user2.resetExpires, 'reset expires wrong has changed'); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - - it('token is not reused after half reset time', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user1 = await usersService.get(result.id || result._id); - - await new Promise(resolve => setTimeout(resolve, 110)); - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user2 = await usersService.get(result.id || result._id); - - assert.notEqual(user1.resetToken, user2.resetToken, 'reset token has not changed'); - assert.notEqual(user1.resetShortToken, user2.resetShortToken, 'reset short token has not changed'); - assert.notEqual(user1.resetExpires, user2.resetExpires, 'reset expires wrong has not changed'); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - }); - - describe('length can change (digits)', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.use('/authentication', authService(app)); - - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 10, - shortTokenLen: 9, - shortTokenDigits: true - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('updates verified user', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); - - assert.strictEqual(user.isVerified, true, 'isVerified not true'); - assert.isString(user.resetToken, 'resetToken not String'); - assert.equal(user.resetToken.length, 60, 'reset token wrong length'); - assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); - assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); - aboutEqualDateTime(user.resetExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - }); - - describe('length can change (alpha)', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - - beforeEach(async () => { - app = feathers(); - app.use('/authentication', authService(app)); - - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 10, - shortTokenLen: 9, - shortTokenDigits: false - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('updates verified user', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); - - assert.strictEqual(user.isVerified, true, 'isVerified not true'); - assert.isString(user.resetToken, 'resetToken not String'); - assert.equal(user.resetToken.length, 60, 'reset token wrong length'); - assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); - assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); - aboutEqualDateTime(user.resetExpires, makeDateTime()); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - }); - - describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; - let db; - let result; - let spyNotifier; - - beforeEach(async () => { - spyNotifier = new SpyOn(notifier); - - app = feathers(); - app.use('/authentication', authService(app)); - - app.configure( - makeUsersService({ - id: idType, - paginate: pagination === 'paginated' - }) - ); - app.configure( - authLocalMgnt({ - longTokenLen: 15, - shortTokenLen: 6, - shortTokenDigits: true, - notifier: spyNotifier.callWith - }) - ); - app.setup(); - authLocalMgntService = app.service('authManagement'); - - usersService = app.service('users'); - await usersService.remove(null); - db = clone(idType === '_id' ? users_Id : usersId); - await usersService.create(db); - }); - - it('is called', async function () { - try { - result = await authLocalMgntService.create({ - action: 'sendResetPwd', - value: { email: 'b' }, - notifierOptions: { transport: 'sms' } - }); - const user = await usersService.get(result.id || result._id); - - assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); - - assert.strictEqual(user.isVerified, true, 'isVerified not true'); - assert.isString(user.resetToken, 'resetToken not String'); - assert.equal(user.resetToken.length, 60, 'reset token wrong length'); - assert.match(user.resetToken, /^\$2[ayb]\$.{56}$/); - aboutEqualDateTime(user.resetExpires, makeDateTime()); - - const expected = spyNotifier.result()[0].args; - expected[1] = Object.assign({}, expected[1], { - resetToken: user.resetToken, - resetShortToken: user.resetShortToken - }); - - assert.deepEqual(expected, ['sendResetPwd', sanitizeUserForEmail(user), { transport: 'sms' }]); - } catch (err) { - console.log(err); - assert(false, 'err code set'); - } - }); - }); - }); - }); -}); - -// Helpers - -async function notifier (action, user, notifierOptions, newEmail) { - return user; -} - -function makeDateTime (options1) { - options1 = options1 || {}; - return Date.now() + (options1.delay || maxTimeAllTests); -} - -function aboutEqualDateTime (time1, time2, msg, delta) { - delta = delta || maxTimeAllTests; - const diff = Math.abs(time1 - time2); - assert.isAtMost(diff, delta, msg || `times differ by ${diff}ms`); -} - -function sanitizeUserForEmail (user) { - const user1 = clone(user); - delete user1.password; - return user1; -} - -function clone (obj) { - return JSON.parse(JSON.stringify(obj)); -} +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import authService from './helpers/authenticationService'; + +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { + makeDateTime as helpersMakeDateTime, + SpyOn, + aboutEqualDateTime +} from './helpers'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; + +function makeDateTime(options1?) { + options1 = options1 || {}; + options1.delay = options1.delay || maxTimeAllTests; + return helpersMakeDateTime(options1); +} + +const now = Date.now(); +const timeout = timeoutEachTest; + +const makeUsersService = options => + function (app) { + Object.assign(options, { multi: true }); + app.use('/users', feathersMemory(options)); + }; + +const usersId: UserTestLocal[] = [ + { + id: 'a', + email: 'a', + isVerified: false, + verifyToken: '000', + verifyExpires: now + maxTimeAllTests + }, + { + id: 'b', + email: 'b', + isVerified: true, + verifyToken: null, + verifyExpires: null + } +]; + +const users_Id: UserTestDB[] = [ + { + _id: 'a', + email: 'a', + isVerified: false, + verifyToken: '000', + verifyExpires: now + maxTimeAllTests + }, + { + _id: 'b', + email: 'b', + isVerified: true, + verifyToken: null, + verifyExpires: null + } +]; + +['_id', 'id'].forEach(idType => { + ['paginated', 'non-paginated'].forEach(pagination => { + describe(`send-reset-pwd.js ${pagination} ${idType}`, function () { + this.timeout(timeoutEachTest); + + describe('basic', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.use('/authentication', authService(app)); + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure(authLocalMgnt({})); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('updates verified user', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user = await usersService.get(result.id || result._id); + assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); + + assert.strictEqual(user.isVerified, true, 'isVerified not true'); + assert.isString(user.resetToken, 'resetToken not String'); + assert.equal(user.resetToken.length, 60, 'reset token wrong length'); + assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); + assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); + aboutEqualDateTime(user.resetExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + + it('error on unverified user', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'a' } + }); + + assert(false, 'unexpected succeeded.'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + + it('error on email not found', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'x' } + }); + + assert(false, 'unexpected succeeded.'); + } catch (err) { + assert.isString(err.message); + assert.isNotFalse(err.message); + } + }); + + it('user is sanitized', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + + assert.strictEqual(result.isVerified, true, 'isVerified not true'); + assert.strictEqual(result.resetToken, undefined, 'resetToken not undefined'); + assert.strictEqual(result.resetShortToken, undefined, 'resetToken not undefined'); + assert.strictEqual(result.resetExpires, undefined, 'resetExpires not undefined'); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + }); + + describe('length can change (digits)', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.use('/authentication', authService(app)); + + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + resetDelay: 200, + reuseResetToken: true, + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('token is reusable with options.reuseResetToken', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user1 = await usersService.get(result.id || result._id); + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user2 = await usersService.get(result.id || result._id); + + assert.equal(user1.resetToken, user2.resetToken, 'reset token has changed'); + assert.equal(user1.resetShortToken, user2.resetShortToken, 'reset short token has changed'); + assert.equal(user1.resetExpires, user2.resetExpires, 'reset expires wrong has changed'); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + + it('token is not reused after half reset time', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user1 = await usersService.get(result.id || result._id); + + await new Promise(resolve => setTimeout(resolve, 110)); + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user2 = await usersService.get(result.id || result._id); + + assert.notEqual(user1.resetToken, user2.resetToken, 'reset token has not changed'); + assert.notEqual(user1.resetShortToken, user2.resetShortToken, 'reset short token has not changed'); + assert.notEqual(user1.resetExpires, user2.resetExpires, 'reset expires wrong has not changed'); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + }); + + describe('length can change (digits)', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.use('/authentication', authService(app)); + + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 10, + shortTokenLen: 9, + shortTokenDigits: true + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('updates verified user', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); + + assert.strictEqual(user.isVerified, true, 'isVerified not true'); + assert.isString(user.resetToken, 'resetToken not String'); + assert.equal(user.resetToken.length, 60, 'reset token wrong length'); + assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); + assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); + aboutEqualDateTime(user.resetExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + }); + + describe('length can change (alpha)', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + + beforeEach(async () => { + app = feathers(); + app.use('/authentication', authService(app)); + + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 10, + shortTokenLen: 9, + shortTokenDigits: false + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('updates verified user', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); + + assert.strictEqual(user.isVerified, true, 'isVerified not true'); + assert.isString(user.resetToken, 'resetToken not String'); + assert.equal(user.resetToken.length, 60, 'reset token wrong length'); + assert.equal(user.resetShortToken.length, 60, 'reset short token wrong length'); + assert.match(user.resetShortToken, /^\$2[ayb]\$.{56}$/); + aboutEqualDateTime(user.resetExpires, makeDateTime()); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + }); + + describe('with notification', () => { + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; + let db; + let result; + let spyNotifier; + + beforeEach(async () => { + spyNotifier = SpyOn(notifier); + + app = feathers(); + app.use('/authentication', authService(app)); + + app.configure( + makeUsersService({ + id: idType, + paginate: pagination === 'paginated' + }) + ); + app.configure( + authLocalMgnt({ + longTokenLen: 15, + shortTokenLen: 6, + shortTokenDigits: true, + notifier: spyNotifier.callWith + }) + ); + app.setup(); + authLocalMgntService = app.service('authManagement'); + + usersService = app.service('users'); + await usersService.remove(null); + db = clone(idType === '_id' ? users_Id : usersId); + await usersService.create(db); + }); + + it('is called', async function () { + try { + result = await authLocalMgntService.create({ + action: 'sendResetPwd', + value: { email: 'b' }, + notifierOptions: { transport: 'sms' } + }); + const user = await usersService.get(result.id || result._id); + + assert.strictEqual(result.isVerified, true, 'user.isVerified not true'); + + assert.strictEqual(user.isVerified, true, 'isVerified not true'); + assert.isString(user.resetToken, 'resetToken not String'); + assert.equal(user.resetToken.length, 60, 'reset token wrong length'); + assert.match(user.resetToken, /^\$2[ayb]\$.{56}$/); + aboutEqualDateTime(user.resetExpires, makeDateTime()); + + const expected = spyNotifier.result()[0].args; + expected[1] = Object.assign({}, expected[1], { + resetToken: user.resetToken, + resetShortToken: user.resetShortToken + }); + + assert.deepEqual(expected, ['sendResetPwd', sanitizeUserForEmail(user), { transport: 'sms' }]); + } catch (err) { + console.log(err); + assert(false, 'err code set'); + } + }); + }); + }); + }); +}); + +// Helpers + +async function notifier (action, user, notifierOptions, newEmail) { + return user; +} + +function sanitizeUserForEmail (user) { + const user1 = clone(user); + delete user1.password; + return user1; +} + +function clone (obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/spy-on.test.js b/test/spy-on.test.ts old mode 100755 new mode 100644 similarity index 84% rename from test/spy-on.test.js rename to test/spy-on.test.ts index 38f54bb..b3150fa --- a/test/spy-on.test.js +++ b/test/spy-on.test.ts @@ -1,43 +1,43 @@ - -const assert = require('chai').assert; -const SpyOn = require('./helpers/basic-spy'); - -describe('spy-on.test.js', () => { - it('works with functions without callbacks', () => { - const spy = new SpyOn(test); - spy.callWith(1, 2, 3); - spy.callWith(4, 5, 6); - - assert.deepEqual(spy.result(), [ - { args: [1, 2, 3], result: ['y', false, [1, 2, 3]] }, - { args: [4, 5, 6], result: ['y', false, [4, 5, 6]] } - ]); - - function test (a, b, c) { return ['y', false, [a, b, c]]; } - }); - - it('works with functions with a callback', (done) => { - const spy = new SpyOn(testCb); - spy.callWithCb(1, 2, 3, (x, y, z) => { - assert.strictEqual(x, 'a'); - assert.strictEqual(y, true); - assert.deepEqual(z, [1, 2, 3]); - - spy.callWithCb(8, 9, 0, (x, y, z) => { - assert.strictEqual(x, 'a'); - assert.strictEqual(y, true); - assert.deepEqual(z, [8, 9, 0]); - - assert.deepEqual(spy.result(), [ - { args: [1, 2, 3], result: ['a', true, [1, 2, 3]] }, - { args: [8, 9, 0], result: ['a', true, [8, 9, 0]] } - ]); - done(); - }); - }); - - function testCb (a, b, c, cb) { - setTimeout(() => (cb('a', true, [a, b, c])), 0); - } - }); -}); + +import { assert } from 'chai'; +import { SpyOn } from './helpers'; + +describe('spy-on.test.js', () => { + it('works with functions without callbacks', () => { + const spy = SpyOn(test); + spy.callWith(1, 2, 3); + spy.callWith(4, 5, 6); + + assert.deepEqual(spy.result(), [ + { args: [1, 2, 3], result: ['y', false, [1, 2, 3]] }, + { args: [4, 5, 6], result: ['y', false, [4, 5, 6]] } + ]); + + function test (a, b, c) { return ['y', false, [a, b, c]]; } + }); + + it('works with functions with a callback', (done) => { + const spy = SpyOn(testCb); + spy.callWithCb(1, 2, 3, (x, y, z) => { + assert.strictEqual(x, 'a'); + assert.strictEqual(y, true); + assert.deepEqual(z, [1, 2, 3]); + + spy.callWithCb(8, 9, 0, (x, y, z) => { + assert.strictEqual(x, 'a'); + assert.strictEqual(y, true); + assert.deepEqual(z, [8, 9, 0]); + + assert.deepEqual(spy.result(), [ + { args: [1, 2, 3], result: ['a', true, [1, 2, 3]] }, + { args: [8, 9, 0], result: ['a', true, [8, 9, 0]] } + ]); + done(); + }); + }); + + function testCb (a, b, c, cb) { + setTimeout(() => (cb('a', true, [a, b, c])), 0); + } + }); +}); diff --git a/test/verify-signup-long.test.js b/test/verify-signup-long.test.ts old mode 100755 new mode 100644 similarity index 89% rename from test/verify-signup-long.test.js rename to test/verify-signup-long.test.ts index 2fc9174..f3aa42b --- a/test/verify-signup-long.test.js +++ b/test/verify-signup-long.test.ts @@ -1,9 +1,11 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const SpyOn = require('./helpers/basic-spy'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import {SpyOn} from './helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -13,7 +15,7 @@ const makeUsersService = options => app.use('/users', feathersMemory(options)); }; -const usersId = [ +const usersId: UserTestLocal[] = [ { id: 'a', email: 'a', @@ -52,7 +54,7 @@ const usersId = [ } ]; -const users_Id = [ +const users_Id: UserTestDB[] = [ { _id: 'a', email: 'a', @@ -97,9 +99,9 @@ const users_Id = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -190,12 +192,10 @@ const users_Id = [ { action: 'verifySignupLong', value: '222' - }, - {}, - (err, user) => { } + } ); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -209,7 +209,7 @@ const users_Id = [ value: '111' }); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -223,7 +223,7 @@ const users_Id = [ value: '999' }); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -232,15 +232,15 @@ const users_Id = [ }); describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; let spyNotifier; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.configure( @@ -251,8 +251,7 @@ const users_Id = [ ); app.configure( authLocalMgnt({ - notifier: spyNotifier.callWith, - testMode: true + notifier: spyNotifier.callWith }) ); app.setup(); diff --git a/test/verify-signup-set-password-long.test.js b/test/verify-signup-set-password-long.test.ts old mode 100755 new mode 100644 similarity index 90% rename from test/verify-signup-set-password-long.test.js rename to test/verify-signup-set-password-long.test.ts index f9a339e..b50358b --- a/test/verify-signup-set-password-long.test.js +++ b/test/verify-signup-set-password-long.test.ts @@ -1,12 +1,15 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const bcrypt = require('bcryptjs'); -const authLocalMgnt = require('../src/index'); -const authService = require('./helpers/authenticationService'); -const SpyOn = require('./helpers/basic-spy'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import bcrypt from 'bcryptjs'; +import authLocalMgnt from '../src/index'; +import { + SpyOn, + authenticationService as authService +} from './helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -48,9 +51,9 @@ const users_Id = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -160,12 +163,9 @@ const users_Id = [ token: '222', password: '12456' } - }, - {}, - (err, user) => {} - ); + }); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -182,7 +182,7 @@ const users_Id = [ } }); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -199,7 +199,7 @@ const users_Id = [ } }); - assert(fail, 'unexpectedly succeeded'); + assert(false, 'unexpectedly succeeded'); } catch (err) { assert.isString(err.message); assert.isNotFalse(err.message); @@ -208,15 +208,15 @@ const users_Id = [ }); describe('with notification', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; let spyNotifier; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -229,8 +229,7 @@ const users_Id = [ ); app.configure( authLocalMgnt({ - notifier: spyNotifier.callWith, - testMode: true + notifier: spyNotifier.callWith }) ); app.setup(); diff --git a/test/verify-signup-set-password-short.test.js b/test/verify-signup-set-password-short.test.ts old mode 100755 new mode 100644 similarity index 93% rename from test/verify-signup-set-password-short.test.js rename to test/verify-signup-set-password-short.test.ts index f3bf403..cd8d70f --- a/test/verify-signup-set-password-short.test.js +++ b/test/verify-signup-set-password-short.test.ts @@ -1,12 +1,15 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const bcrypt = require('bcryptjs'); -const authLocalMgnt = require('../src/index'); -const authService = require('./helpers/authenticationService'); -const SpyOn = require('./helpers/basic-spy'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import bcrypt from 'bcryptjs'; +import authLocalMgnt from '../src/index'; +import { + SpyOn, + authenticationService as authService +} from './helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -52,9 +55,9 @@ const users_Id = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -202,7 +205,8 @@ const users_Id = [ action: 'verifySignupSetPasswordShort', value: { token: '00099', - user: { email: db[i].email, verifyShortToken: '00099' }, + //TODO: was this right? + user: { email: undefined, verifyShortToken: '00099' }, password } }); @@ -240,9 +244,9 @@ const users_Id = [ action: 'verifySignupSetPasswordShort', value: { token: '11199', + password, user: { username: db[2].username } - }, - password + } }); assert(false, 'unexpectedly succeeded.'); @@ -290,14 +294,14 @@ const users_Id = [ describe('with notification', () => { let spyNotifier; - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.use('/authentication', authService(app)); @@ -309,8 +313,7 @@ const users_Id = [ ); app.configure( authLocalMgnt({ - notifier: spyNotifier.callWith, - testMode: true + notifier: spyNotifier.callWith }) ); app.setup(); diff --git a/test/verify-signup-short.test.js b/test/verify-signup-short.test.ts old mode 100755 new mode 100644 similarity index 92% rename from test/verify-signup-short.test.js rename to test/verify-signup-short.test.ts index f7f0570..c837eef --- a/test/verify-signup-short.test.js +++ b/test/verify-signup-short.test.ts @@ -1,9 +1,11 @@ -const assert = require('chai').assert; -const feathers = require('@feathersjs/feathers'); -const feathersMemory = require('feathers-memory'); -const authLocalMgnt = require('../src/index'); -const SpyOn = require('./helpers/basic-spy'); -const { timeoutEachTest, maxTimeAllTests } = require('./helpers/config'); +import { assert } from 'chai'; +import feathers, { Application } from '@feathersjs/feathers'; +import feathersMemory, { Service } from 'feathers-memory'; +import authLocalMgnt from '../src/index'; +import {SpyOn} from './helpers'; +import { timeoutEachTest, maxTimeAllTests } from './helpers/config'; +import { UserTestDB, UserTestLocal } from './helpers/types'; +import { AuthenticationManagementService } from '../src/services'; const now = Date.now(); @@ -13,7 +15,7 @@ const makeUsersService = options => app.use('/users', feathersMemory(options)); }; -const usersId = [ +const usersId: UserTestLocal[] = [ { id: 'a', email: 'a', @@ -62,7 +64,7 @@ const usersId = [ } ]; -const users_Id = [ +const users_Id: UserTestDB[] = [ { _id: 'a', email: 'a', @@ -117,9 +119,9 @@ const users_Id = [ this.timeout(timeoutEachTest); describe('basic', () => { - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; @@ -259,7 +261,8 @@ const users_Id = [ action: 'verifySignupShort', value: { token: '00099', - user: { email: db[i].email, verifyShortToken: '00099' } + // was this right? + user: { email: undefined, verifyShortToken: '00099' } } }); @@ -339,14 +342,14 @@ const users_Id = [ describe('with notification', () => { let spyNotifier; - let app; - let usersService; - let authLocalMgntService; + let app: Application; + let usersService: Service; + let authLocalMgntService: AuthenticationManagementService; let db; let result; beforeEach(async () => { - spyNotifier = new SpyOn(notifier); + spyNotifier = SpyOn(notifier); app = feathers(); app.configure( @@ -358,8 +361,7 @@ const users_Id = [ app.configure( authLocalMgnt({ // maybe reset identifyUserProps - notifier: spyNotifier.callWith, - testMode: true + notifier: spyNotifier.callWith }) ); app.setup(); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..44947d7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "outDir": "dist", + "moduleResolution": "node", + "target": "es5", + "downlevelIteration": true, + "sourceMap": false, + "declaration": true, + "strictNullChecks": false, + }, + "include": ["src/**/*"], + "exclude": [ + "node_modules", + "**/*.test.*", + ".eslintrc.js", + "examples/**" + ] +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..30ce266 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "outDir": "dist", + "moduleResolution": "node", + "target": "es6", + "sourceMap": true, + "allowJs": true + }, + "include": ["src/**/*"], + "exclude": [ + "node_modules", + "**/*.test.ts", + "examples/**" + ] +}