Merge branch 'release-2.6.1' into feature/github-return-data

This commit is contained in:
denihs
2022-02-10 10:34:30 -04:00
68 changed files with 1789 additions and 492 deletions

View File

@@ -58,6 +58,7 @@ sidebar_categories:
Packages:
- packages/accounts-ui
- packages/accounts-passwordless
- packages/accounts-2fa
- packages/appcache
- packages/audit-argument-checks
- packages/autoupdate

View File

@@ -1,13 +1,60 @@
## vNEXT, UNRELEASED
## v2.6.1, UNRELEASED
#### Highlights
* TailwindCSS 3.x support
* Typescript `4.5.4` upgrade
* New core package: `accounts-2fa`
* Support for 2FA in `accounts-password` and `accounts-passwordless`
* Postcss configurations are now handled by `standard-minifier-css`
#### Breaking Changes
N/A
#### Migration Steps
Read our [Migration Guide](https://guide.meteor.com/2.6.1-migration.html) for this version.
#### Meteor Version Release
* `standard-minifier-css@1.8.0`
- Postcss configurations are now handled in this package
- TailwindCSS 3.x support
- Support postcss dependency messages. [PR](https://github.com/meteor/meteor/pull/11903)
* `accounts-2fa@1.0.0`
- New package to provide 2FA support
* `accounts-password@2.3.0`
- 2FA support
* `accounts-passwordless@2.1.0`
- 2FA support
* `@meteorjs/babel@7.16.0`
- Upgrade TypeScript to `4.5.4`
* `babel-compiler@7.9.0`
- Upgrade TypeScript to `4.5.4`
* `ecmascript@0.16.2`
- Upgrade TypeScript to `4.5.4`
* `typescript@4.5.4`
- Upgrade TypeScript to `4.5.4` [PR](https://github.com/meteor/meteor/pull/11846)
* `accounts-ui-unstyled@1.6.0`
- `Accounts.ui.config` can now be set via `Meteor.settings.public.packages.accounts-ui-unstyled`.
* `meteor-tool@2.6.1`
- Have build plugins handle caching for css minifiers. [PR](https://github.com/meteor/meteor/pull/11882).
* `standard-minifier-css@1.8.0`
- Cache minified stylesheets. [PR](https://github.com/meteor/meteor/pull/11882).
* `ejson@1.1.2`
- Fixing error were EJSON.equals fail to compare object and array if first param is object and second is array. [PR](https://github.com/meteor/meteor/pull/11866), [Issue](https://github.com/meteor/meteor/issues/11864).
#### Independent Releases
* `mongo@1.14.3` at 2022-02-08
@@ -17,6 +64,9 @@
* `mongo@1.14.1` at 2022-02-04
- Fix flatten object issue when the object is empty on oplog converter. [PR](https://github.com/meteor/meteor/pull/11885), [Issue](https://github.com/meteor/meteor/issues/11884).
* `email@2.2.1`
- Modernizes the code.
## v2.6, 2022-02-01
#### Highlights

View File

@@ -242,7 +242,7 @@ ServiceConfiguration.configurations.upsert(
);
```
Since Meteor 2.5 you no longer need to manually set the configuration and instead can use Meteor settings by setting your services under `Meteor.settings.packages.service-configuration.<service>`. All the properties can be set under the service and will be added to the database as is, so make sure that they are correct. For the example above, the settings would look like:
Since Meteor 2.6.1 you no longer need to manually set the configuration and instead can use Meteor settings by setting your services under `Meteor.settings.packages.service-configuration.<service>`. All the properties can be set under the service and will be added to the database as is, so make sure that they are correct. For the example above, the settings would look like:
```json
{
"packages": {
@@ -334,3 +334,6 @@ Accounts.ui.config({
passwordSignupFields: 'USERNAME_AND_OPTIONAL_EMAIL'
});
```
Since Meteor 2.6.1 you can configure these in your Meteor settings under `Meteor.settings.public.packages.accounts-ui-unstyled`.

View File

@@ -183,3 +183,7 @@ Accounts.emailTemplates.verifyEmail = {
}
};
```
<h3 id="enabling-2fa">Enable 2FA for this package</h3>
You can add 2FA to your login flow by using the package [accounts-2fa](https://docs.meteor.com/packages/accounts-2fa.html). You can find an example showing how this would look like [here](https://docs.meteor.com/packages/accounts-2fa.html#working-with-accounts-password).

View File

@@ -38,6 +38,16 @@ If you only use sudo because of a distribution default permission system, [check
In some cases you can get this error `npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules` because your Node.js installation was performed with wrong permissions. An easy way to fix this is to install Node.js using [nvm](https://github.com/nvm-sh/nvm) and forcing it to be used in your terminal. You can force it in the current session of your terminal by running `nvm use 14`.
<h2 id="path-management">PATH management</h2>
By default, the Meteor installer adds its install path (by default, `~/.meteor/`) to your PATH by updating either your `.bashrc`, `.bash_profile`, or `.zshrc` as appropriate. To disable this behavior, install Meteor by running:
```bash
npm install -g meteor --ignore-meteor-setup-exec-path
```
(or by setting the environment variable `npm_config_ignore_meteor_setup_exec_path=true`)
<h2 id="old-versions-m1">Old Versions on Apple M1</h2>
For Apple M1 computers, you can append Rosetta prefix as following, if you need to run older versions of Meteor (before 2.5.1):

View File

@@ -0,0 +1,241 @@
---
title: accounts-2fa
description: Documentation of Meteor's `accounts-2fa` package.
---
This package allows you to provide a way for your users to enable 2FA on their accounts, using an authenticator app such as Google Authenticator, or 1Password. When the user is logged in on your app, they will be able to generate a new QR code and read this code on the app they prefer. After that, they'll start receiving their codes. Then, they can finish enabling 2FA on your app, and every time they try to log in to your app, you can redirect them to a place where they can provide a code they received from the authenticator.
This package uses [node-2fa](https://www.npmjs.com/package/node-2fa) which works on top of [notp](https://github.com/guyht/notp), **that** implements TOTP ([RFC 6238](https://www.ietf.org/rfc/rfc6238.txt)) (the Authenticator standard), which is based on HOTP ([RFC 4226](https://www.ietf.org/rfc/rfc4226.txt)) to provide codes that are exactly compatible with all other Authenticator apps and services that use them.
> This package is meant to be used with [`accounts-password`](https://docs.meteor.com/api/passwords.html) or [`accounts-passwordless`](https://docs.meteor.com/packages/accounts-passwordless.html), so if you don't have either of those in your project, you'll need to add one of them. In the future, we want to enable the use of this package with other login methods, our oauth methods (Google, GitHub, etc...).
<h2 id="activating-2fa">Activating 2FA</h2>
The first step, in order to enable 2FA, is to generate a QR code so that the user can scan it in an authenticator app and start receiving codes.
{% apibox "Accounts.generate2faActivationQrCode" "module":"accounts-base" %}
Receives an `appName` which is the name of your app that will show up when the user scans the QR code. Also, a callback called with a QR code in SVG format on success or a single `Error` argument
on failure.
On success, this function will also add an object to the logged user's services object containing the QR secret:
```js
services: {
...
twoFactorAuthentication: {
secret: "***"
}
}
```
Here it's an example on how to call this function:
```js
import { Buffer } from "buffer";
import { Accounts } from 'meteor/accounts-base';
--
const [qrCode, setQrCode] = useState(null);
--
<button
onClick={() => {
Accounts.generate2faActivationQrCode("My app name", (err, svg) => {
if (err) {console.error("...", err);return;}
/*
the svg can be converted to base64, then be used like:
<img
width="200"
src={`data:image/svg+xml;base64,${qrCode}`}
/>
*/
setQrCode(Buffer.from(svg).toString('base64'));
})
}}
>
Generate a new code
</button>
```
At this point, the 2FA won't be activated just yet. Now that the user has access to the codes generated by their authenticator app, you can call the function `Accounts.enableUser2fa`:
{% apibox "Accounts.enableUser2fa" "module":"accounts-base" %}
It should be called with a code that the users will receive from the authenticator app once they read the QR code. The callback is called with a single `Error` argument on failure. If the code provided is correct, a `type` will be added to the user's `twoFactorAuthentication` object and now 2FA is considered enabled:
```js
services: {
...
twoFactorAuthentication: {
type: "otp",
secret: "***",
}
}
```
<h2 id="disabling-2fa">Disabling 2FA</h2>
To disable 2FA for a user use this method:
{% apibox "Accounts.disableUser2fa" "module":"accounts-base" %}
To call this function the user must be already logged in.
<h2 id="log-in-with-2fa">Log in with 2FA</h2>
Now that you have a way to allow your users to enable 2FA on their accounts, you can create a login flow based on that.
To verify whether or not a user has 2FA enabled, you can call the function `Accounts.has2faEnabled`:
{% apibox "Accounts.has2faEnabled" "module":"accounts-base" %}
As said at the beginning of this guide, this package is currently working with two other packages: `accounts-password` and `accounts-passwordless`. Below there is an explanation on how to use this package with them.
<h3 id="working-with-accounts-password">Working with accounts-password</h3>
With the function `Accounts.has2faEnabled`, you can check whether or not the user has 2FA enabled, and based on this information, you can directly call `Meteor.loginWithPassword` if the 2FA is not enabled, or redirect the user to a place where they can provide a code, in case they do have 2FA enabled.
A way of using it would be:
```js
<button
onClick={() => {
Accounts.has2faEnabled(username, (err, isEnabled) => {
if (err) {
console.error("Error verifying if user has 2fa enabled", err);
return;
}
if (isEnabled) {
// send user to a page or show a component
// where they can provide a 2FA code
setShouldAskCode(true);
return;
}
// Normal login when they don't have 2FA enabled.
Meteor.loginWithPassword(username, password, error => {
if (error) {
console.error("Error trying to log in (user without 2fa)", error);
}
});
});
}
}>
Login
</button>
```
If the user has 2FA enabled, and you try to use the function `Meteor.loginWithPassword`, the login will fail, as the user should provide a code to access the app.
The function you will need to call now to allow the user to login is `Meteor.loginWithPasswordAnd2faCode`:
{% apibox "Meteor.loginWithPasswordAnd2faCode" %}
Now you will be able to receive a code from the user and this function will verify if the code is valid. If it is, the user will be logged in.
So the call of this function should look something like this:
```js
<button onClick={() => {
Meteor.loginWithPasswordAnd2faCode(username, password, code,error => {
if (error) {
console.error("Error trying to log in (user with 2fa)", error);
}
})}
}>
Validate and log in
</button>
```
<h3 id="working-with-accounts-passwordless">Working with accounts-passwordless</h3>
Following the same strategy from the previous package, you can use the function `Accounts.has2faEnabled` to verify whether or not the user has 2FA enabled. If yes, you send them their token and on next step you receive their token and their 2FA code, otherwise, you still send them their token but on the next step you don't ask them for a 2FA code.
Here it's an example:
```js
Accounts.has2faEnabled(username, (err, isEnabled) => {
if (err) {console.error("...", err);return;}
Accounts.requestLoginTokenForUser({selector: "email@example.com"}, e => {
if (e) {console.error("...", e);return;}
if (isEnabled) {
setShouldAskTokenAndCode(true);
return;
}
setShouldAskToken(true);
});
});
```
Now you can either call the standard method [`Meteor.passwordlessLoginWithToken`](https://docs.meteor.com/packages/accounts-passwordless.html#Meteor-passwordlessLoginWithToken) if they don't have 2FA enabled, or in case they do, you call the method `Meteor.passwordlessLoginWithTokenAnd2faCode` that will allow you to provide a selector, token, and 2FA code:
{% apibox "Meteor.passwordlessLoginWithTokenAnd2faCode" %}
So, using this strategy your code should look something like this:
```js
<button
onClick={() => {
// logging in with token and code
if (shouldAskTokenAndCode) {
Meteor.passwordlessLoginWithTokenAnd2faCode(
email,
token,
code,
error => {
if (error) {console.error('...', error);}
}
);
return;
}
// logging in just with token
Meteor.passwordlessLoginWithToken(
email,
token,
error => {
if (error) {console.error('...', error);}
}
);
}}
>
Validate and Log in
</button>;
```
<h2 id="integrating-auth-package">How to integrate an Authentication Package with accounts-2fa</h2>
To integrate this package with any other existing Login method, it's necessary following two steps:
1 - For the client, create a new method from your current login method. So for example, from the method `Meteor.loginWithPassword` we created a new one called `Meteor.loginWithPasswordAnd2faCode`, and the only difference between them is that the latest one receives one additional parameter, the 2FA code, but we call the same function on the server side.
2 - For the server, inside the function that will log the user in, you verify if the function `Accounts._is2faEnabledForUser` exists, and if yes, you call it providing the user you want to check if the 2FA is enabled, and if either of these statements are false, you proceed with the login flow. This function exists only when the package `accounts-2fa` is added to the project.
If both statements are true, now you verify if a code was provided, if not throw an error, if it was provided, verify if the code is valid by calling the function `Accounts._isTokenValid`, if not, throw an error.
Here it's an example:
```js
if (
Accounts._is2faEnabledForUser &&
Accounts._is2faEnabledForUser(user)
) {
if (!code) {
Accounts._handleError('2FA code must be informed.');
}
if (
!Accounts._isTokenValid(user.services.twoFactorAuthentication.secret, code)
) {
Accounts._handleError('Invalid 2FA code.');
}
}
// continue the login flow
```

View File

@@ -25,3 +25,7 @@ sendLoginToken: {
text: (user, url, { sequence }) => { /* text template */ }
}
```
<h3 id="enabling-2fa">Enable 2FA for this package</h3>
You can add 2FA to your login flow by using the package [accounts-2fa](https://docs.meteor.com/packages/accounts-2fa.html). You can find an example showing how this would look like [here](https://docs.meteor.com/packages/accounts-2fa.html#working-with-accounts-passwordless).

View File

@@ -35,7 +35,7 @@ sidebar_categories:
- index
- code-style
- structure
- 2.6-migration
- 2.6.1-migration
Data:
- collections
- data-loading

View File

@@ -0,0 +1,55 @@
---
title: Migrating to Meteor 2.6.1
description: How to migrate your application to Meteor 2.6.1.
---
Meteor 2.6.1 introduce the new `accounts-2fa` package and also support to TailwindCSS 3.x incorporating `postcss` minifier code to core in the `standard-minifier-css`. For a complete breakdown of the changes, please refer to the [changelog](http://docs.meteor.com/changelog.html).
The above being said, there are a few items that you should do to have the latest CSS minifier in your project.
<h3 id="new-css-minifier">CSS Minifier with PostCSS</h3>
If you are using `juliancwirko:postcss` as your PostCSS CSS Minifier and you want to use the latest Minifier for PostCSS you should use the core package: `standard-minifier-css` instead. Starting from this version of Meteor (and 1.8.0 of `standard-minifier-css`) it supports the latest PostCSS features as well.
If you want to use TailwindCSS 3.x you must use the `standard-minifier-css` core package to insure Tailwind JIT working properly.
Steps to replace the package:
- `meteor remove juliancwirko:postcss`
- `meteor add standard-minifier-css`
After replacing the package with the commands above TailwindCSS 3.x should work fine with Meteor 2.6.1.
Please read the [Tailwind Official migration guide](https://tailwindcss.com/docs/upgrade-guide) to make sure you had applied the changes required by TailwindCSS itself.
> Note: In beta.1 of Meteor 2.6.1 we had added a new core package `minifier-css-postcss` but later in this discussion we decided to unify everything inside `standard-minifier-css`. So you shouldn't use `minifier-css-postcss`.
<h3 id="2fa">Accounts 2FA</h3>
`accounts-2fa` is a new package that enables two-factor authentication for `accounts-password` and `accounts-passwordless`.
There are no required changes to your application in any case, but if you want to provide 2FA for your users, and you are already using `accounts-password` or `accounts-passwordless` you can start using the new functions provided from 2FA package, read more in the [docs](https://docs.meteor.com/packages/accounts-2fa.html).
<h2 id="older-versions">Migrating from a version older than 2.6?</h2>
If you're migrating from a version of Meteor older than Meteor 2.6, there may be important considerations not listed in this guide (which specifically covers 2.6 to 2.6.1). Please review the older migration guides for details:
* [Migrating to Meteor 2.6](2.6-migration.html) (from 2.5)
* [Migrating to Meteor 2.5](2.5-migration.html) (from 2.4)
* [Migrating to Meteor 2.4](2.4-migration.html) (from 2.3)
* [Migrating to Meteor 2.3](2.3-migration.html) (from 2.2)
* [Migrating to Meteor 2.2](2.2-migration.html) (from 2.0)
* [Migrating to Meteor 2.0](2.0-migration.html) (from 1.12)
* [Migrating to Meteor 1.12](1.12-migration.html) (from 1.11)
* [Migrating to Meteor 1.11](1.11-migration.html) (from 1.10.2)
* [Migrating to Meteor 1.10.2](1.10.2-migration.html) (from 1.10)
* [Migrating to Meteor 1.10](1.10-migration.html) (from 1.9.3)
* [Migrating to Meteor 1.9.3](1.9.3-migration.html) (from 1.9)
* [Migrating to Meteor 1.9](1.9-migration.html) (from 1.8.3)
* [Migrating to Meteor 1.8.3](1.8.3-migration.html) (from 1.8.2)
* [Migrating to Meteor 1.8.2](1.8.2-migration.html) (from 1.8)
* [Migrating to Meteor 1.8](1.8-migration.html) (from 1.7)
* [Migrating to Meteor 1.7](1.7-migration.html) (from 1.6)
* [Migrating to Meteor 1.6](1.6-migration.html) (from 1.5)
* [Migrating to Meteor 1.5](1.5-migration.html) (from 1.4)
* [Migrating to Meteor 1.4](1.4-migration.html) (from 1.3)
* [Migrating to Meteor 1.3](1.3-migration.html) (from 1.2)

2
meteor
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
BUNDLE_VERSION=14.18.3.4
BUNDLE_VERSION=14.19.0.0
# OS Check. Put here because here is where we download the precompiled
# bundles that are arch specific.

View File

@@ -14,8 +14,8 @@ var packageJson = {
pacote: "https://github.com/meteor/pacote/tarball/a81b0324686e85d22c7688c47629d4009000e8b8",
"node-gyp": "8.0.0",
"node-pre-gyp": "0.15.0",
typescript: "4.3.5",
"@meteorjs/babel": "7.15.0",
typescript: "4.5.4",
"@meteorjs/babel": "7.16.0-beta.0",
// Keep the versions of these packages consistent with the versions
// found in dev-bundle-server-package.js.
"meteor-promise": "0.9.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@meteorjs/babel",
"version": "7.15.0",
"version": "7.16.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2438,9 +2438,9 @@
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
},
"typescript": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA=="
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
},
"unbox-primitive": {
"version": "1.0.1",

View File

@@ -1,7 +1,7 @@
{
"name": "@meteorjs/babel",
"author": "Meteor <dev@meteor.com>",
"version": "7.15.0",
"version": "7.16.0-beta.0",
"license": "MIT",
"description": "Babel wrapper package for use with Meteor",
"keywords": [
@@ -41,13 +41,13 @@
"@babel/template": "^7.14.5",
"@babel/traverse": "^7.15.0",
"@babel/types": "^7.15.0",
"@meteorjs/reify": "0.23.0",
"babel-preset-meteor": "^7.10.0",
"babel-preset-minify": "^0.5.1",
"convert-source-map": "^1.6.0",
"lodash": "^4.17.21",
"meteor-babel-helpers": "0.0.3",
"@meteorjs/reify": "0.23.0",
"typescript": "^4.3.5"
"typescript": "^4.5.4"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "7.14.5",

View File

@@ -34,3 +34,13 @@ npm install -g meteor
### Important note
This npm package is not Meteor itself, this npm package is just an installer. You should not include it as a dependency in your project. If you do your deploy is going to be broken.
### Path management
By default, the Meteor installer adds its install path (by default, `~/.meteor/`) to your PATH by updating either your `.bashrc`, `.bash_profile`, or `.zshrc` as appropriate. To disable this behavior, install Meteor by running:
```bash
npm install -g meteor --ignore-meteor-setup-exec-path
```
(or by setting the environment variable `npm_config_ignore_meteor_setup_exec_path=true`)

View File

@@ -31,6 +31,10 @@ if (isWindows() && !localAppData) {
throw new Error('LOCALAPPDATA env var is not set.');
}
const shouldSetupExecPath = () => {
return !process.env.npm_config_ignore_meteor_setup_exec_path;
}
const meteorLocalFolder = '.meteor';
const meteorPath = path.resolve(rootPath, meteorLocalFolder);
@@ -45,5 +49,6 @@ module.exports = {
isWindows,
isMac,
isRoot,
isSudo
isSudo,
shouldSetupExecPath,
};

View File

@@ -19,6 +19,7 @@ const {
isSudo,
isMac,
METEOR_LATEST_VERSION,
shouldSetupExecPath,
} = require('./config.js');
const { uninstall } = require('./uninstall');
const {
@@ -246,7 +247,10 @@ async function extract() {
}
async function setup() {
fs.unlinkSync(startedPath);
await setupExecPath();
if (shouldSetupExecPath()) {
await setupExecPath();
}
await fixOwnership();
showGettingStarted();
}
async function setupExecPath() {
@@ -267,8 +271,9 @@ async function setupExecPath() {
await appendPathToFile('.bashrc');
await appendPathToFile('.bash_profile');
}
if (isSudo()) {
}
async function fixOwnership() {
if (!isWindows() && isSudo()) {
// if we identified sudo is being used, we need to change the ownership of the meteorpath folder
child_process.execSync(`chown -R ${sudoUser} "${meteorPath}"`);
}

2
packages/accounts-2fa/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.build*
.versions

View File

@@ -0,0 +1,76 @@
import { Accounts } from 'meteor/accounts-base';
// Used in the various functions below to handle errors consistently
const reportError = (error, callback) => {
if (callback) {
callback(error);
} else {
throw error;
}
};
/**
* @summary Verify if the user has 2FA enabled
* @locus Client
* @param {Object|String} selector Username, email or custom selector to identify the user.
* @param {Function} [callback] Called with a boolean on success that indicates whether the user has
* or not 2FA enabled, or with a single `Error` argument on failure.
*/
Accounts.has2faEnabled = (selector, callback) => {
Accounts.connection.call('has2faEnabled', selector, callback);
};
/**
* @summary Generates a svg QR code and save secret on user
* @locus Client
* @param {String} appName It's the name of your app that will show up when the user scans the QR code.
* @param {Function} callback
* Called with a QR code in SVG format on success, or with a single `Error` argument
* on failure.
*/
Accounts.generate2faActivationQrCode = (appName, callback) => {
if (!appName) {
throw new Meteor.Error(
500,
'An app name is necessary when calling the function generate2faActivationQrCode'
);
}
if (!callback) {
throw new Meteor.Error(
500,
'A callback is necessary when calling the function generate2faActivationQrCode so a QR code can be provided'
);
}
Accounts.connection.call('generate2faActivationQrCode', appName, callback);
};
/**
* @summary Enable the user 2FA
* @locus Client
* @param {String} code Code received from the authenticator app.
* @param {Function} [callback] Optional callback.
* Called with no arguments on success, or with a single `Error` argument
* on failure.
*/
Accounts.enableUser2fa = (code, callback) => {
if (!code) {
return reportError(
new Meteor.Error(400, 'Must provide a code to validate'),
callback
);
}
Accounts.connection.call('enableUser2fa', code, callback);
};
/**
* @summary Disable user 2FA
* @locus Client
* @param {Function} [callback] Optional callback.
* Called with no arguments on success, or with a single `Error` argument
* on failure.
*/
Accounts.disableUser2fa = callback => {
Accounts.connection.call('disableUser2fa', callback);
};

View File

@@ -0,0 +1,129 @@
import { Accounts } from 'meteor/accounts-base';
import twofactor from 'node-2fa';
import QRCode from 'qrcode-svg';
import { Meteor } from 'meteor/meteor';
Accounts._is2faEnabledForUser = selector => {
if (!Meteor.isServer) {
throw new Meteor.Error(
400,
'The function _is2faEnabledForUser can only be called on the server'
);
}
if (typeof selector === 'string') {
if (!selector.includes('@')) {
selector = { username: selector };
} else {
selector = { email: selector };
}
}
const user = Meteor.users.findOne(selector) || {};
const { services: { twoFactorAuthentication } = {} } = user;
return (
twoFactorAuthentication &&
twoFactorAuthentication.secret &&
twoFactorAuthentication.type === 'otp'
);
};
Accounts._generate2faToken = secret => twofactor.generateToken(secret);
Accounts._isTokenValid = (secret, code) => {
if (!Meteor.isServer) {
throw new Meteor.Error(
400,
'The function _isTokenValid can only be called on the server'
);
}
const { delta } = twofactor.verifyToken(secret, code, 10) || {};
return delta != null && delta >= 0;
};
Meteor.methods({
generate2faActivationQrCode(appName) {
const user = Meteor.user();
if (!user) {
throw new Meteor.Error(
400,
'There must be a user logged in to generate the QR code.'
);
}
const { username } = user;
const { secret, uri } = twofactor.generateSecret({
name: appName.trim(),
account: username,
});
const svg = new QRCode(uri).svg();
Meteor.users.update(
{ username },
{
$set: {
'services.twoFactorAuthentication': {
secret,
},
},
}
);
return svg;
},
enableUser2fa(code) {
const user = Meteor.user();
if (!user) {
throw new Meteor.Error(400, 'No user logged in.');
}
const {
services: { twoFactorAuthentication },
username,
} = user;
if (!twoFactorAuthentication || !twoFactorAuthentication.secret) {
throw new Meteor.Error(
500,
'The user does not have a secret generated. You may have to call the function generateSvgCode first.'
);
}
if (!Accounts._isTokenValid(twoFactorAuthentication.secret, code)) {
throw new Meteor.Error(400, 'Invalid code.');
}
Meteor.users.update(
{ username },
{
$set: {
'services.twoFactorAuthentication': {
...twoFactorAuthentication,
type: 'otp',
},
},
}
);
},
disableUser2fa() {
const user = Meteor.user();
if (!user) {
throw new Meteor.Error(400, 'No user logged in.');
}
Meteor.users.update(
{ username: user.username },
{
$unset: {
'services.twoFactorAuthentication': 1,
},
}
);
},
has2faEnabled(selector) {
return Accounts._is2faEnabledForUser(selector);
},
});

View File

@@ -0,0 +1,7 @@
# accounts-2fa
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/accounts-2fa)
| [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/accounts-2fa)
***
A package that provides a simple way to integrate 2FA in login services. Check the [docs](https://docs.meteor.com/packages/accounts-2fa.html) to see which packages are compatible with 2FA already.

View File

@@ -0,0 +1,22 @@
Package.describe({
version: '1.0.0-beta261.3',
summary:
'Package used to enable two factor authentication through OTP protocol',
});
Npm.depends({
'node-2fa': '2.0.3',
'qrcode-svg': '1.1.0',
});
Package.onUse(function(api) {
api.use(['accounts-base'], ['client', 'server']);
// Export Accounts (etc) to packages using this one.
api.imply('accounts-base', ['client', 'server']);
api.use('ecmascript');
api.addFiles(['2fa-client.js'], 'client');
api.addFiles(['2fa-server.js'], 'server');
});

View File

@@ -1,8 +1,11 @@
import {Accounts} from "meteor/accounts-base";
const username = 'jsmith';
const password = 'password';
const excludeField = 'excludeField';
const defaultExcludeField = 'defaultExcludeField';
const excludeValue = 'foo';
const secret2fa = 'shhhh';
const profile = {
name: username,
[excludeField]: excludeValue,
@@ -22,12 +25,49 @@ const logoutAndCreateUser = (test, done, nextTests) => {
});
};
const removeTestUser = (done) => {
const createUserAndLogout = (test, done, nextTests) => {
// Setup a new test user
Accounts.createUser(
{
username,
password,
profile: {
name: username,
},
},
() => {
Meteor.logout(() => {
// Make sure we're logged out
test.isFalse(Meteor.user());
// Handle next tests
nextTests(test, done);
});
}
);
};
const removeTestUser = done => {
Meteor.call('removeAccountsTestUser', username, () => {
done();
});
};
const forceEnableUser2fa = done => {
Meteor.call('forceEnableUser2fa', username, secret2fa, (err, token) => {
done(token);
});
};
const getTokenFromSecret = done => {
Meteor.call(
'getTokenFromSecret',
{ username },
(err, token) => {
done(token);
}
);
};
Tinytest.addAsync(
'accounts - Meteor.loggingIn() is true right after a login call',
(test, done) => {
@@ -137,3 +177,84 @@ Tinytest.addAsync(
});
}
);
Tinytest.addAsync(
'accounts-2fa - Meteor.loginWithPasswordAnd2faCode() fails when token is not provided',
(test, done) => {
createUserAndLogout(test, done, () => {
try {
Meteor.loginWithPasswordAnd2faCode(username, password);
} catch (e) {
test.equal(
e.reason,
'token is required to use loginWithPasswordAnd2faCode and must be a string'
);
} finally {
test.isFalse(Meteor.user());
removeTestUser(done);
}
});
}
);
Tinytest.addAsync(
'accounts-2fa - Meteor.loginWithPasswordAnd2faCode() fails with invalid code',
(test, done) => {
createUserAndLogout(test, done, () => {
forceEnableUser2fa(() => {
Meteor.loginWithPasswordAnd2faCode(username, password, 'ABC', e => {
test.isFalse(Meteor.user());
test.equal(e.reason, 'Invalid 2FA code.');
removeTestUser(done);
});
});
});
}
);
Tinytest.addAsync(
'accounts-2fa - Meteor.loginWithPasswordAnd2faCode() succeeds when token is correct',
(test, done) => {
createUserAndLogout(test, done, () => {
forceEnableUser2fa((token) => {
Meteor.loginWithPasswordAnd2faCode(username, password, token, e => {
test.equal(e, undefined);
test.isTrue(Meteor.user());
removeTestUser(done);
});
});
});
}
);
Tinytest.addAsync(
'accounts-2fa - Generates secret, enable 2fa, verifies if 2fa is enabled, disable 2fa, verifies if 2fa is disabled',
(test, done) => {
logoutAndCreateUser(test, done, () => {
// Generates secret
Accounts.generate2faActivationQrCode('test', (err, svg) => {
test.isTrue(svg != null);
getTokenFromSecret(token => {
// enable 2fa
Accounts.enableUser2fa(token, () => {
// verifies if 2fa is enabled
Accounts.has2faEnabled(username, (err, isEnabled) => {
test.isTrue(isEnabled);
// disable 2fa
Accounts.disableUser2fa(() => {
// verifies if 2fa is disabled
Accounts.has2faEnabled(username, (err, isEnabled) => {
test.isFalse(!!isEnabled);
removeTestUser(done);
});
});
});
});
});
});
});
}
);

View File

@@ -1,5 +1,36 @@
const getTokenFromSecret = ({ username, secret: secretParam }) => {
let secret = secretParam;
if (!secret) {
const { services: { twoFactorAuthentication } = {} } =
Meteor.users.findOne({ username }) || {};
if (!twoFactorAuthentication) {
throw new Meteor.Error(500, 'twoFactorAuthentication not set.');
}
secret = twoFactorAuthentication.secret;
}
const { token } = Accounts._generate2faToken(secret);
return token;
};
Meteor.methods({
removeAccountsTestUser(username) {
Meteor.users.remove({ username });
},
forceEnableUser2fa(username, secret) {
Meteor.users.update(
{ username },
{
$set: {
'services.twoFactorAuthentication': {
secret,
type: 'otp',
},
},
}
);
return getTokenFromSecret({ username, secret });
},
getTokenFromSecret,
});

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'A user account system',
version: '2.2.1',
version: '2.2.2-beta261.3',
});
Package.onUse(api => {
@@ -60,6 +60,7 @@ Package.onTest(api => {
'oauth-encryption',
'ddp',
'accounts-password',
'accounts-2fa',
]);
api.addFiles('accounts_tests_setup.js', 'server');

View File

@@ -5,7 +5,7 @@ Package.describe({
// 2.2.x in the future. The version was also bumped to 2.0.0 temporarily
// during the Meteor 1.5.1 release process, so versions 2.0.0-beta.2
// through -beta.5 and -rc.0 have already been published.
version: '2.2.0',
version: '2.3.0-beta261.3',
});
Npm.depends({

View File

@@ -7,6 +7,31 @@ const reportError = (error, callback) => {
}
};
const internalLoginWithPassword = ({ selector, password, code, callback }) => {
if (typeof selector === 'string')
if (!selector.includes('@')) selector = { username: selector };
else selector = { email: selector };
Accounts.callLoginMethod({
methodArguments: [
{
user: selector,
password: Accounts._hashPassword(password),
code,
},
],
userCallback: (error, result) => {
if (error) {
reportError(error, callback);
} else {
callback && callback();
}
},
});
return selector;
};
// Attempt to log in with a password.
//
// @param selector {String|Object} One of the following:
@@ -31,25 +56,7 @@ const reportError = (error, callback) => {
* @importFromPackage meteor
*/
Meteor.loginWithPassword = (selector, password, callback) => {
if (typeof selector === 'string')
if (!selector.includes('@'))
selector = {username: selector};
else
selector = {email: selector};
Accounts.callLoginMethod({
methodArguments: [{
user: selector,
password: Accounts._hashPassword(password)
}],
userCallback: (error, result) => {
if (error) {
reportError(error, callback);
} else {
callback && callback();
}
}
});
return internalLoginWithPassword({ selector, password, callback });
};
Accounts._hashPassword = password => ({
@@ -57,6 +64,33 @@ Accounts._hashPassword = password => ({
algorithm: "sha-256"
});
/**
* @summary Log the user in with a password and token.
* @locus Client
* @param {Object | String} selector
* Either a string interpreted as a username or an email; or an object with a
* single key: `email`, `username` or `id`. Username or email match in a case
* insensitive manner.
* @param {String} password The user's password.
* @param {String} token Token provide by the user's authenticator app.
* @param {Function} [callback] Optional callback.
* Called with no arguments on success, or with a single `Error` argument
* on failure.
* @importFromPackage meteor
*/
Meteor.loginWithPasswordAnd2faCode = (selector, password, code, callback) => {
if (code == null || typeof code !== 'string' || !code) {
throw new Meteor.Error(
400,
'token is required to use loginWithPasswordAnd2faCode and must be a string'
);
}
return internalLoginWithPassword({ selector, password, code, callback });
};
// Attempt to log in as a new user.
/**

View File

@@ -169,7 +169,8 @@ Accounts.registerLoginHandler("password", options => {
check(options, {
user: Accounts._userQueryValidator,
password: passwordValidator
password: passwordValidator,
code: Match.Optional(NonEmptyString),
});
@@ -181,6 +182,21 @@ Accounts.registerLoginHandler("password", options => {
Accounts._handleError("User not found");
}
// This method is added by the package accounts-2fa
if (
Accounts._is2faEnabledForUser &&
Accounts._is2faEnabledForUser(options.user)
) {
if (!options.code) {
Accounts._handleError('2FA code must be informed.');
}
if (
!Accounts._isTokenValid(user.services.twoFactorAuthentication.secret, options.code)
) {
Accounts._handleError('Invalid 2FA code.');
}
}
if (!user.services || !user.services.password ||
!user.services.password.bcrypt) {
Accounts._handleError("User has no password set");

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'No-password login/sign-up support for accounts',
version: '2.0.0',
version: '2.1.0-beta261.3',
});
Package.onUse(api => {

View File

@@ -21,6 +21,31 @@ const transformSelector = selector => {
return { username: selector };
};
const internalPasswordlessLoginWithToken = ({
selector,
token,
code,
callback,
}) => {
Accounts.callLoginMethod({
methodArguments: [
{
selector: transformSelector(selector),
token,
code,
},
],
userCallback: error => {
if (error) {
reportError(error, callback);
} else {
callback && callback();
}
},
});
};
// Attempt to log in with a token.
//
// @param selector {String|Object} One of the following:
@@ -31,6 +56,7 @@ const transformSelector = selector => {
// @param password {String}
// @param callback {Function(error|undefined)}
/**
* @summary Log the user in with a one time token.
* @locus Client
@@ -42,21 +68,22 @@ const transformSelector = selector => {
* @importFromPackage meteor
*/
Meteor.passwordlessLoginWithToken = (selector, token, callback) => {
Accounts.callLoginMethod({
methodArguments: [
{
selector: transformSelector(selector),
token,
},
],
userCallback: error => {
if (error) {
reportError(error, callback);
} else {
callback && callback();
}
},
});
internalPasswordlessLoginWithToken({ selector, token, callback });
};
/**
* @summary Log the user in with a one time token.
* @locus Client
* @param {Object|String} selector Username, email or custom selector to identify the user.
* @param {String} token one time token generated by the server
* @param {String} code generated by the user's authenticator app
* @param {Function} [callback] Optional callback.
* Called with no arguments on success, or with a single `Error` argument
* on failure.
* @importFromPackage meteor
*/
Meteor.passwordlessLoginWithTokenAnd2faCode = (selector, token, code, callback) => {
internalPasswordlessLoginWithToken({ selector, token, code, callback });
};
/**

View File

@@ -1,5 +1,5 @@
import { Accounts } from 'meteor/accounts-base';
import { getUserById, tokenValidator } from './server_utils';
import {getUserById, NonEmptyString, tokenValidator} from './server_utils';
import { Random } from 'meteor/random';
const ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000;
@@ -63,6 +63,7 @@ Accounts.registerLoginHandler('passwordless', options => {
check(options, {
token: tokenValidator(),
code: Match.Optional(NonEmptyString),
selector: Accounts._userQueryValidator,
});
@@ -79,6 +80,21 @@ Accounts.registerLoginHandler('passwordless', options => {
Accounts._handleError('User has no token set');
}
// This method is added by the package accounts-2fa
if (
Accounts._is2faEnabledForUser &&
Accounts._is2faEnabledForUser(user)
) {
if (!options.code) {
Accounts._handleError('2FA code must be informed.');
}
if (
!Accounts._isTokenValid(user.services.twoFactorAuthentication.secret, options.code)
) {
Accounts._handleError('Invalid 2FA code.');
}
}
const result = checkToken({
user,
selector,

View File

@@ -9,3 +9,8 @@ export const tokenValidator = () => {
str => Match.test(str, String) && str.length <= tokenLength
);
};
export const NonEmptyString = Match.Where(x => {
check(x, String);
return x.length > 0;
});

View File

@@ -20,18 +20,18 @@ const VALID_OPTIONS = new Set()
.add('passwordlessSignupFields');
const VALID_PASSWORD_SIGNUP_FIELDS = new Set()
.add("USERNAME_AND_EMAIL")
.add("USERNAME_AND_OPTIONAL_EMAIL")
.add("USERNAME_ONLY")
.add("EMAIL_ONLY");
.add('USERNAME_AND_EMAIL')
.add('USERNAME_AND_OPTIONAL_EMAIL')
.add('USERNAME_ONLY')
.add('EMAIL_ONLY');
function isValidPasswordSignupField(field) {
return VALID_PASSWORD_SIGNUP_FIELDS.has(field);
}
const VALID_PASSWORDLESS_SIGNUP_FIELDS = new Set()
.add("USERNAME_AND_EMAIL")
.add("EMAIL_ONLY")
.add('USERNAME_AND_EMAIL')
.add('EMAIL_ONLY');
function isValidPasswordlessSignupField(field) {
return VALID_PASSWORDLESS_SIGNUP_FIELDS.has(field);
@@ -62,15 +62,25 @@ Accounts.ui.config = options => {
handleForceApprovalPrompt(options);
};
Meteor.startup(function() {
const settings = Meteor.settings.public?.packages?.['accounts-ui-unstyled'];
if (settings) {
Accounts.ui.config(settings);
}
});
function handlePasswordlessSignupFields(options) {
let { passwordlessSignupFields } = options;
if (passwordlessSignupFields) {
const reportInvalid = () => {
throw new Error(`Accounts.ui.config: Invalid option for \`passwordlessSignupFields\`: ${passwordlessSignupFields}`);
throw new Error(
`Accounts.ui.config: Invalid option for \`passwordlessSignupFields\`: ${passwordlessSignupFields}`
);
};
if (typeof passwordlessSignupFields === "string") {
if (typeof passwordlessSignupFields === 'string') {
passwordlessSignupFields = [passwordlessSignupFields];
} else if (!Array.isArray(passwordlessSignupFields)) {
reportInvalid();
@@ -78,7 +88,9 @@ function handlePasswordlessSignupFields(options) {
if (passwordlessSignupFields.every(isValidPasswordlessSignupField)) {
if (Accounts.ui._options.passwordlessSignupFields) {
throw new Error("Accounts.ui.config: Can't set `passwordlessSignupFields` more than once");
throw new Error(
"Accounts.ui.config: Can't set `passwordlessSignupFields` more than once"
);
}
Object.assign(Accounts.ui._options, { passwordlessSignupFields });
return;
@@ -93,10 +105,12 @@ function handlePasswordSignupFields(options) {
if (passwordSignupFields) {
const reportInvalid = () => {
throw new Error(`Accounts.ui.config: Invalid option for \`passwordSignupFields\`: ${passwordSignupFields}`);
throw new Error(
`Accounts.ui.config: Invalid option for \`passwordSignupFields\`: ${passwordSignupFields}`
);
};
if (typeof passwordSignupFields === "string") {
if (typeof passwordSignupFields === 'string') {
passwordSignupFields = [passwordSignupFields];
} else if (!Array.isArray(passwordSignupFields)) {
reportInvalid();
@@ -104,7 +118,9 @@ function handlePasswordSignupFields(options) {
if (passwordSignupFields.every(isValidPasswordSignupField)) {
if (Accounts.ui._options.passwordSignupFields) {
throw new Error("Accounts.ui.config: Can't set `passwordSignupFields` more than once");
throw new Error(
"Accounts.ui.config: Can't set `passwordSignupFields` more than once"
);
}
Object.assign(Accounts.ui._options, { passwordSignupFields });
return;
@@ -125,7 +141,7 @@ export function passwordSignupFields() {
return [passwordSignupFields];
}
return ["EMAIL_ONLY"];
return ['EMAIL_ONLY'];
}
export function passwordlessSignupFields() {
@@ -139,21 +155,24 @@ export function passwordlessSignupFields() {
return [passwordlessSignupFields];
}
return ["EMAIL_ONLY"];
return ['EMAIL_ONLY'];
}
function handleRequestPermissions({ requestPermissions }) {
if (requestPermissions) {
Object.keys(requestPermissions).forEach(service => {
if (Accounts.ui._options.requestPermissions[service]) {
throw new Error(`Accounts.ui.config: Can't set \`requestPermissions\` more than once for ${service}`);
throw new Error(
`Accounts.ui.config: Can't set \`requestPermissions\` more than once for ${service}`
);
}
const scope = requestPermissions[service];
if (!Array.isArray(scope)) {
throw new Error("Accounts.ui.config: Value for `requestPermissions` must be an array");
throw new Error(
'Accounts.ui.config: Value for `requestPermissions` must be an array'
);
}
Accounts.ui._options.requestPermissions[service] = scope;
@@ -165,11 +184,15 @@ function handleRequestOfflineToken({ requestOfflineToken }) {
if (requestOfflineToken) {
Object.keys(requestOfflineToken).forEach(service => {
if (service !== 'google') {
throw new Error("Accounts.ui.config: `requestOfflineToken` only supported for Google login at the moment.");
throw new Error(
'Accounts.ui.config: `requestOfflineToken` only supported for Google login at the moment.'
);
}
if (Accounts.ui._options.requestOfflineToken[service]) {
throw new Error(`Accounts.ui.config: Can't set \`requestOfflineToken\` more than once for ${service}`);
throw new Error(
`Accounts.ui.config: Can't set \`requestOfflineToken\` more than once for ${service}`
);
}
Accounts.ui._options.requestOfflineToken[service] =
@@ -182,11 +205,15 @@ function handleForceApprovalPrompt({ forceApprovalPrompt }) {
if (forceApprovalPrompt) {
Object.keys(forceApprovalPrompt).forEach(service => {
if (service !== 'google') {
throw new Error("Accounts.ui.config: `forceApprovalPrompt` only supported for Google login at the moment.");
throw new Error(
'Accounts.ui.config: `forceApprovalPrompt` only supported for Google login at the moment.'
);
}
if (Accounts.ui._options.forceApprovalPrompt[service]) {
throw new Error(`Accounts.ui.config: Can't set \`forceApprovalPrompt\` more than once for ${service}`);
throw new Error(
`Accounts.ui.config: Can't set \`forceApprovalPrompt\` more than once for ${service}`
);
}
Accounts.ui._options.forceApprovalPrompt[service] =

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Unstyled version of login widgets',
version: '1.6.0',
version: '1.7.0-beta261.3',
});
Package.onUse(function(api) {

View File

@@ -1,20 +1,25 @@
{
"lockfileVersion": 1,
"dependencies": {
"@ampproject/remapping": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.0.3.tgz",
"integrity": "sha512-DmIAguV77yFP0MGVFWknCMgSLAtsLR3VlRTteR6xgMpIfYtwaZuMvjGv5YlpiqN7S/5q87DHyuIx8oa15kiyag=="
},
"@babel/code-frame": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz",
"integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
"integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="
},
"@babel/compat-data": {
"version": "7.16.4",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz",
"integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz",
"integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng=="
},
"@babel/core": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz",
"integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.0.tgz",
"integrity": "sha512-x/5Ea+RO5MvF9ize5DeVICJoVrNv0Mi2RnIABrZEKYvPEpldXwauPkgvYA17cKa6WpU3LoYvYbuEMFtSNFsarA==",
"dependencies": {
"json5": {
"version": "2.2.0",
@@ -24,104 +29,104 @@
}
},
"@babel/generator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz",
"integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz",
"integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw=="
},
"@babel/helper-annotate-as-pure": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz",
"integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
"integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw=="
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz",
"integrity": "sha512-3JEA9G5dmmnIWdzaT9d0NmFRgYnWUThLsDaL7982H0XqqWr56lRrsmwheXFMjR+TMl7QMBb6mzy9kvgr1lRLUA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz",
"integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA=="
},
"@babel/helper-compilation-targets": {
"version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz",
"integrity": "sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
"integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA=="
},
"@babel/helper-create-class-features-plugin": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz",
"integrity": "sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg=="
"version": "7.17.1",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz",
"integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ=="
},
"@babel/helper-create-regexp-features-plugin": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz",
"integrity": "sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz",
"integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA=="
},
"@babel/helper-define-polyfill-provider": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz",
"integrity": "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz",
"integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA=="
},
"@babel/helper-environment-visitor": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz",
"integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
"integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag=="
},
"@babel/helper-explode-assignable-expression": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz",
"integrity": "sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz",
"integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ=="
},
"@babel/helper-function-name": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz",
"integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
"integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA=="
},
"@babel/helper-get-function-arity": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz",
"integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
"integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw=="
},
"@babel/helper-hoist-variables": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz",
"integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
"integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg=="
},
"@babel/helper-member-expression-to-functions": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz",
"integrity": "sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz",
"integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q=="
},
"@babel/helper-module-imports": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz",
"integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg=="
},
"@babel/helper-module-transforms": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz",
"integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng=="
},
"@babel/helper-optimise-call-expression": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz",
"integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz",
"integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w=="
},
"@babel/helper-plugin-utils": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz",
"integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
"integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA=="
},
"@babel/helper-remap-async-to-generator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz",
"integrity": "sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw=="
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz",
"integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw=="
},
"@babel/helper-replace-supers": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz",
"integrity": "sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
"integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw=="
},
"@babel/helper-simple-access": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz",
"integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
"integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g=="
},
"@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.16.0",
@@ -129,74 +134,74 @@
"integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw=="
},
"@babel/helper-split-export-declaration": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz",
"integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
"integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw=="
},
"@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
},
"@babel/helper-validator-option": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz",
"integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
},
"@babel/helper-wrap-function": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz",
"integrity": "sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA=="
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz",
"integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw=="
},
"@babel/helpers": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz",
"integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.0.tgz",
"integrity": "sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ=="
},
"@babel/highlight": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
"integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g=="
"version": "7.16.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
"integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw=="
},
"@babel/parser": {
"version": "7.16.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz",
"integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz",
"integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw=="
},
"@babel/plugin-proposal-async-generator-functions": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz",
"integrity": "sha512-C/FX+3HNLV6sz7AqbTQqEo1L9/kfrKjxcVtgyBCmvIgOjvuBVUWooDoi7trsLxOzCEo5FccjRvKHkfDsJFZlfA=="
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz",
"integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ=="
},
"@babel/plugin-proposal-class-properties": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.5.tgz",
"integrity": "sha512-pJD3HjgRv83s5dv1sTnDbZOaTjghKEz8KUn1Kbh2eAIRhGuyQ1XSeI4xVXU3UlIEVA3DAyIdxqT1eRn7Wcn55A=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz",
"integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww=="
},
"@babel/plugin-proposal-logical-assignment-operators": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz",
"integrity": "sha512-xqibl7ISO2vjuQM+MzR3rkd0zfNWltk7n9QhaD8ghMmMceVguYrNDt7MikRyj4J4v3QehpnrU8RYLnC7z/gZLA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz",
"integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg=="
},
"@babel/plugin-proposal-nullish-coalescing-operator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.5.tgz",
"integrity": "sha512-YwMsTp/oOviSBhrjwi0vzCUycseCYwoXnLiXIL3YNjHSMBHicGTz7GjVU/IGgz4DtOEXBdCNG72pvCX22ehfqg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz",
"integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ=="
},
"@babel/plugin-proposal-object-rest-spread": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.5.tgz",
"integrity": "sha512-UEd6KpChoyPhCoE840KRHOlGhEZFutdPDMGj+0I56yuTTOaT51GzmnEl/0uT41fB/vD2nT+Pci2KjezyE3HmUw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz",
"integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA=="
},
"@babel/plugin-proposal-optional-catch-binding": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz",
"integrity": "sha512-ihCMxY1Iljmx4bWy/PIMJGXN4NS4oUj1MKynwO07kiKms23pNvIn1DMB92DNB2R0EA882sw0VXIelYGdtF7xEQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz",
"integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA=="
},
"@babel/plugin-proposal-optional-chaining": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz",
"integrity": "sha512-kzdHgnaXRonttiTfKYnSVafbWngPPr2qKw9BWYBESl91W54e+9R5pP70LtWxV56g0f05f/SQrwHYkfvbwcdQ/A=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz",
"integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA=="
},
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
@@ -214,9 +219,9 @@
"integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="
},
"@babel/plugin-syntax-jsx": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz",
"integrity": "sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz",
"integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q=="
},
"@babel/plugin-syntax-logical-assignment-operators": {
"version": "7.10.4",
@@ -244,164 +249,179 @@
"integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg=="
},
"@babel/plugin-transform-arrow-functions": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz",
"integrity": "sha512-8bTHiiZyMOyfZFULjsCnYOWG059FVMes0iljEHSfARhNgFfpsqE92OrCffv3veSw9rwMkYcFe9bj0ZoXU2IGtQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz",
"integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ=="
},
"@babel/plugin-transform-async-to-generator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz",
"integrity": "sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w=="
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz",
"integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg=="
},
"@babel/plugin-transform-block-scoped-functions": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz",
"integrity": "sha512-BxmIyKLjUGksJ99+hJyL/HIxLIGnLKtw772zYDER7UuycDZ+Xvzs98ZQw6NGgM2ss4/hlFAaGiZmMNKvValEjw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz",
"integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg=="
},
"@babel/plugin-transform-block-scoping": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz",
"integrity": "sha512-JxjSPNZSiOtmxjX7PBRBeRJTUKTyJ607YUYeT0QJCNdsedOe+/rXITjP08eG8xUpsLfPirgzdCFN+h0w6RI+pQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz",
"integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ=="
},
"@babel/plugin-transform-classes": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz",
"integrity": "sha512-DzJ1vYf/7TaCYy57J3SJ9rV+JEuvmlnvvyvYKFbk5u46oQbBvuB9/0w+YsVsxkOv8zVWKpDmUoj4T5ILHoXevA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz",
"integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ=="
},
"@babel/plugin-transform-computed-properties": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz",
"integrity": "sha512-n1+O7xtU5lSLraRzX88CNcpl7vtGdPakKzww74bVwpAIRgz9JVLJJpOLb0uYqcOaXVM0TL6X0RVeIJGD2CnCkg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz",
"integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw=="
},
"@babel/plugin-transform-destructuring": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz",
"integrity": "sha512-GuRVAsjq+c9YPK6NeTkRLWyQskDC099XkBSVO+6QzbnOnH2d/4mBVXYStaPrZD3dFRfg00I6BFJ9Atsjfs8mlg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz",
"integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A=="
},
"@babel/plugin-transform-exponentiation-operator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz",
"integrity": "sha512-12rba2HwemQPa7BLIKCzm1pT2/RuQHtSFHdNl41cFiC6oi4tcrp7gjB07pxQvFpcADojQywSjblQth6gJyE6CA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz",
"integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA=="
},
"@babel/plugin-transform-for-of": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz",
"integrity": "sha512-+DpCAJFPAvViR17PIMi9x2AE34dll5wNlXO43wagAX2YcRGgEVHCNFC4azG85b4YyyFarvkc/iD5NPrz4Oneqw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz",
"integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg=="
},
"@babel/plugin-transform-literals": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz",
"integrity": "sha512-B1j9C/IfvshnPcklsc93AVLTrNVa69iSqztylZH6qnmiAsDDOmmjEYqOm3Ts2lGSgTSywnBNiqC949VdD0/gfw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz",
"integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ=="
},
"@babel/plugin-transform-modules-commonjs": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz",
"integrity": "sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ=="
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
"integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA=="
},
"@babel/plugin-transform-object-super": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz",
"integrity": "sha512-tded+yZEXuxt9Jdtkc1RraW1zMF/GalVxaVVxh41IYwirdRgyAxxxCKZ9XB7LxZqmsjfjALxupNE1MIz9KH+Zg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz",
"integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw=="
},
"@babel/plugin-transform-parameters": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz",
"integrity": "sha512-B3O6AL5oPop1jAVg8CV+haeUte9oFuY85zu0jwnRNZZi3tVAbJriu5tag/oaO2kGaQM/7q7aGPBlTI5/sr9enA=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz",
"integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw=="
},
"@babel/plugin-transform-property-literals": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz",
"integrity": "sha512-+IRcVW71VdF9pEH/2R/Apab4a19LVvdVsr/gEeotH00vSDVlKD+XgfSIw+cgGWsjDB/ziqGv/pGoQZBIiQVXHg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz",
"integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw=="
},
"@babel/plugin-transform-react-display-name": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.5.tgz",
"integrity": "sha512-dHYCOnzSsXFz8UcdNQIHGvg94qPL/teF7CCiCEMRxmA1G2p5Mq4JnKVowCDxYfiQ9D7RstaAp9kwaSI+sXbnhw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz",
"integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg=="
},
"@babel/plugin-transform-react-jsx": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.5.tgz",
"integrity": "sha512-+arLIz1d7kmwX0fKxTxbnoeG85ONSnLpvdODa4P3pc1sS7CV1hfmtYWufkW/oYsPnkDrEeQFxhUWcFnrXW7jQQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz",
"integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag=="
},
"@babel/plugin-transform-react-jsx-development": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.5.tgz",
"integrity": "sha512-uQSLacMZSGLCxOw20dzo1dmLlKkd+DsayoV54q3MHXhbqgPzoiGerZQgNPl/Ro8/OcXV2ugfnkx+rxdS0sN5Uw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz",
"integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A=="
},
"@babel/plugin-transform-react-pure-annotations": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.5.tgz",
"integrity": "sha512-0nYU30hCxnCVCbRjSy9ahlhWZ2Sn6khbY4FqR91W+2RbSqkWEbVu2gXh45EqNy4Bq7sRU+H4i0/6YKwOSzh16A=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz",
"integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA=="
},
"@babel/plugin-transform-regenerator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz",
"integrity": "sha512-2z+it2eVWU8TtQQRauvGUqZwLy4+7rTfo6wO4npr+fvvN1SW30ZF3O/ZRCNmTuu4F5MIP8OJhXAhRV5QMJOuYg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz",
"integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q=="
},
"@babel/plugin-transform-runtime": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.5.tgz",
"integrity": "sha512-gxpfS8XQWDbQ8oP5NcmpXxtEgCJkbO+W9VhZlOhr0xPyVaRjAQPOv7ZDj9fg0d5s9+NiVvMCE6gbkEkcsxwGRw=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz",
"integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A=="
},
"@babel/plugin-transform-shorthand-properties": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz",
"integrity": "sha512-ZbuWVcY+MAXJuuW7qDoCwoxDUNClfZxoo7/4swVbOW1s/qYLOMHlm9YRWMsxMFuLs44eXsv4op1vAaBaBaDMVg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz",
"integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg=="
},
"@babel/plugin-transform-spread": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz",
"integrity": "sha512-5d6l/cnG7Lw4tGHEoga4xSkYp1euP7LAtrah1h1PgJ3JY7yNsjybsxQAnVK4JbtReZ/8z6ASVmd3QhYYKLaKZw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz",
"integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg=="
},
"@babel/plugin-transform-sticky-regex": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz",
"integrity": "sha512-usYsuO1ID2LXxzuUxifgWtJemP7wL2uZtyrTVM4PKqsmJycdS4U4mGovL5xXkfUheds10Dd2PjoQLXw6zCsCbg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz",
"integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw=="
},
"@babel/plugin-transform-template-literals": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz",
"integrity": "sha512-gnyKy9RyFhkovex4BjKWL3BVYzUDG6zC0gba7VMLbQoDuqMfJ1SDXs8k/XK41Mmt1Hyp4qNAvGFb9hKzdCqBRQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz",
"integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA=="
},
"@babel/plugin-transform-typeof-symbol": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz",
"integrity": "sha512-ldxCkW180qbrvyCVDzAUZqB0TAeF8W/vGJoRcaf75awm6By+PxfJKvuqVAnq8N9wz5Xa6mSpM19OfVKKVmGHSQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz",
"integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ=="
},
"@babel/plugin-transform-unicode-regex": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz",
"integrity": "sha512-GTJ4IW012tiPEMMubd7sD07iU9O/LOo8Q/oU4xNhcaq0Xn8+6TcUQaHtC8YxySo1T+ErQ8RaWogIEeFhKGNPzw=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz",
"integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q=="
},
"@babel/preset-react": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.5.tgz",
"integrity": "sha512-3kzUOQeaxY/2vhPDS7CX/KGEGu/1bOYGvdRDJ2U5yjEz5o5jmIeTPLoiQBPGjfhPascLuW5OlMiPzwOOuB6txg=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz",
"integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA=="
},
"@babel/runtime": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz",
"integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ=="
},
"@babel/template": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz",
"integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
"integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w=="
},
"@babel/traverse": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz",
"integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz",
"integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg=="
},
"@babel/types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz",
"integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg=="
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
"integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw=="
},
"@jridgewell/resolve-uri": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz",
"integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg=="
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz",
"integrity": "sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg=="
},
"@jridgewell/trace-mapping": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.2.7.tgz",
"integrity": "sha512-ZKfRhw6eK2vvdWqpU7DQq49+BZESqh5rmkYpNhuzkz01tapssl2sNNy6uMUIgrTtUWQDijomWJzJRCoevVrfgw=="
},
"@meteorjs/babel": {
"version": "7.15.0",
"resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.15.0.tgz",
"integrity": "sha512-XHyjZ1z3glbyGvSVT06re9HK25X2FOrsDE1X/Ph6c/66Pwxf+a2t1TiyxR/WvkHFxBMwDm09xcAZ2WMdl2GfAw=="
"version": "7.16.0-beta.0",
"resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.16.0-beta.0.tgz",
"integrity": "sha512-XRjYHxFOYlWj/j4aVVM/RYd9Vi/Pgq2etJmb1F+pZIUuUS95Ak166yes1T2X2aRukWdAuyl8nyhZL6EWjoTuYQ=="
},
"@meteorjs/reify": {
"version": "0.23.0",
@@ -531,19 +551,19 @@
"integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA="
},
"babel-plugin-polyfill-corejs2": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz",
"integrity": "sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz",
"integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w=="
},
"babel-plugin-polyfill-corejs3": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz",
"integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw=="
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz",
"integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ=="
},
"babel-plugin-polyfill-regenerator": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz",
"integrity": "sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz",
"integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A=="
},
"babel-plugin-transform-inline-consecutive-adds": {
"version": "0.4.3",
@@ -621,9 +641,9 @@
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="
},
"caniuse-lite": {
"version": "1.0.30001291",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001291.tgz",
"integrity": "sha512-roMV5V0HNGgJ88s42eE70sstqGW/gwFndosYrikHthw98N5tLnOTxFqMLQjZVRxTWFlJ4rn+MsgXrR7MDPY4jA=="
"version": "1.0.30001307",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001307.tgz",
"integrity": "sha512-+MXEMczJ4FuxJAUp0jvAl6Df0NI/OfW1RWEE61eSmzS7hw6lz4IKutbhbXendwq8BljfFuHtu26VWsg4afQ7Ng=="
},
"chalk": {
"version": "2.4.2",
@@ -646,9 +666,9 @@
"integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA=="
},
"core-js-compat": {
"version": "3.20.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.0.tgz",
"integrity": "sha512-relrah5h+sslXssTTOkvqcC/6RURifB0W5yhYBdBkaPYa5/2KBMiog3XiD+s3TwEHWxInWVv4Jx2/Lw0vng+IQ==",
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz",
"integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==",
"dependencies": {
"semver": {
"version": "7.0.0",
@@ -668,9 +688,9 @@
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ=="
},
"electron-to-chromium": {
"version": "1.4.25",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.25.tgz",
"integrity": "sha512-bTwub9Y/76EiNmfaiJih+hAy6xn7Ns95S4KvI2NuKNOz8TEEKKQUu44xuy0PYMudjM9zdjKRS1bitsUvHTfuUg=="
"version": "1.4.65",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz",
"integrity": "sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw=="
},
"escalade": {
"version": "3.1.1",
@@ -728,9 +748,9 @@
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
},
"is-core-module": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
"integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw=="
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
"integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA=="
},
"is-reference": {
"version": "1.2.1",
@@ -818,9 +838,9 @@
"integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="
},
"regenerate-unicode-properties": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz",
"integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA=="
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz",
"integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw=="
},
"regenerator-runtime": {
"version": "0.13.9",
@@ -833,19 +853,19 @@
"integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw=="
},
"regexpu-core": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz",
"integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg=="
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz",
"integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw=="
},
"regjsgen": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
"integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A=="
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz",
"integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA=="
},
"regjsparser": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz",
"integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==",
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz",
"integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==",
"dependencies": {
"jsesc": {
"version": "0.5.0",
@@ -855,9 +875,9 @@
}
},
"resolve": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A=="
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw=="
},
"safe-buffer": {
"version": "5.1.2",
@@ -884,15 +904,20 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"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="
},
"typescript": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA=="
},
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",

View File

@@ -1,11 +1,11 @@
Package.describe({
name: "babel-compiler",
summary: "Parser/transpiler for ECMAScript 2015+ syntax",
version: '7.8.0'
version: '7.9.0-beta261.3'
});
Npm.depends({
'@meteorjs/babel': '7.15.0',
'@meteorjs/babel': '7.16.0-beta.0',
'json5': '2.1.1'
});

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'ecmascript',
version: '0.16.1',
version: '0.16.2-beta261.3',
summary: 'Compiler plugin that supports ES2015+ in all .js files',
documentation: 'README.md',
});

View File

@@ -486,10 +486,16 @@ EJSON.equals = (a, b, options) => {
return b.equals(a, options);
}
if (a instanceof Array) {
if (!(b instanceof Array)) {
return false;
}
// Array.isArray works across iframes while instanceof won't
const aIsArray = Array.isArray(a);
const bIsArray = Array.isArray(b);
// if not both or none are array they are not equal
if (aIsArray !== bIsArray) {
return false;
}
if (aIsArray && bIsArray) {
if (a.length !== b.length) {
return false;
}

View File

@@ -44,6 +44,14 @@ Tinytest.add('ejson - some equality tests', test => {
test.isFalse(EJSON.equals({a: 1, b: 2, c: 3}, {a: 1, c: 3, b: 4}));
test.isFalse(EJSON.equals({a: {}}, {a: {b: 2}}));
test.isFalse(EJSON.equals({a: {b: 2}}, {a: {}}));
// XXX: Object and Array were previously mistaken, which is why
// we add some extra tests for them here
test.isTrue(EJSON.equals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]));
test.isFalse(EJSON.equals([1, 2, 3, 4, 5], [1, 2, 3, 4]));
test.isFalse(EJSON.equals([1,2,3,4], {0: 1, 1: 2, 2: 3, 3: 4}));
test.isFalse(EJSON.equals({0: 1, 1: 2, 2: 3, 3: 4}, [1,2,3,4]));
test.isFalse(EJSON.equals({}, []));
test.isFalse(EJSON.equals([], {}));
});
Tinytest.add('ejson - equality and falsiness', test => {

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Extended and Extensible JSON library',
version: '1.1.1'
version: '1.1.2-beta261.3'
});
Package.onUse(function onUse(api) {

View File

@@ -14,29 +14,34 @@ export const EmailInternals = {
NpmModules: {
mailcomposer: {
version: Npm.require('nodemailer/package.json').version,
module: Npm.require('nodemailer/lib/mail-composer')
module: Npm.require('nodemailer/lib/mail-composer'),
},
nodemailer: {
version: Npm.require('nodemailer/package.json').version,
module: Npm.require('nodemailer')
}
}
module: Npm.require('nodemailer'),
},
},
};
const MailComposer = EmailInternals.NpmModules.mailcomposer.module;
const makeTransport = function (mailUrlString) {
const makeTransport = function(mailUrlString) {
const mailUrl = new URL(mailUrlString);
if (mailUrl.protocol !== 'smtp:' && mailUrl.protocol !== 'smtps:') {
throw new Error("Email protocol in $MAIL_URL (" +
mailUrlString + ") must be 'smtp' or 'smtps'");
throw new Error(
'Email protocol in $MAIL_URL (' +
mailUrlString +
") must be 'smtp' or 'smtps'"
);
}
if (mailUrl.protocol === 'smtp:' && mailUrl.port === '465') {
Log.debug("The $MAIL_URL is 'smtp://...:465'. " +
"You probably want 'smtps://' (The 's' enables TLS/SSL) " +
"since '465' is typically a secure port.");
Log.debug(
"The $MAIL_URL is 'smtp://...:465'. " +
"You probably want 'smtps://' (The 's' enables TLS/SSL) " +
"since '465' is typically a secure port."
);
}
// Allow overriding pool setting, but default to true.
@@ -84,15 +89,17 @@ const knownHostsTransport = function(settings = undefined, url = undefined) {
}
if (!wellKnow(settings?.service || service)) {
throw new Error('Could not recognize e-mail service. See list at https://nodemailer.com/smtp/well-known/ for services that we can configure for you.');
throw new Error(
'Could not recognize e-mail service. See list at https://nodemailer.com/smtp/well-known/ for services that we can configure for you.'
);
}
const transport = nodemailer.createTransport({
service: settings?.service || service,
auth: {
user: settings?.user || user,
pass: settings?.password || password
}
pass: settings?.password || password,
},
});
transport._syncSendMail = Meteor.wrapAsync(transport.sendMail, transport);
@@ -106,8 +113,17 @@ const getTransport = function() {
// set process.env.MAIL_URL in startup code. Then we store in a cache until
// process.env.MAIL_URL changes.
const url = process.env.MAIL_URL;
if (this.cacheKey === undefined || (this.cacheKey !== url || this.cacheKey !== packageSettings?.service || 'settings')) {
if ((packageSettings?.service && wellKnow(packageSettings.service)) || (url && wellKnow(new URL(url).hostname) || wellKnow(url?.split(':')[0] || ''))) {
if (
this.cacheKey === undefined ||
this.cacheKey !== url ||
this.cacheKey !== packageSettings?.service ||
this.cacheKey !== 'settings'
) {
if (
(packageSettings?.service && wellKnow(packageSettings.service)) ||
(url && wellKnow(new URL(url).hostname)) ||
wellKnow(url?.split(':')[0] || '')
) {
this.cacheKey = packageSettings.service || 'settings';
this.cache = knownHostsTransport(packageSettings, url);
} else {
@@ -122,35 +138,37 @@ let nextDevModeMailId = 0;
let output_stream = process.stdout;
// Testing hooks
EmailTest.overrideOutputStream = function (stream) {
EmailTest.overrideOutputStream = function(stream) {
nextDevModeMailId = 0;
output_stream = stream;
};
EmailTest.restoreOutputStream = function () {
EmailTest.restoreOutputStream = function() {
output_stream = process.stdout;
};
const devModeSend = function (mail) {
const devModeSend = function(mail) {
let devModeMailId = nextDevModeMailId++;
const stream = output_stream;
// This approach does not prevent other writers to stdout from interleaving.
stream.write("====== BEGIN MAIL #" + devModeMailId + " ======\n");
stream.write("(Mail not sent; to enable sending, set the MAIL_URL " +
"environment variable.)\n");
stream.write('====== BEGIN MAIL #' + devModeMailId + ' ======\n');
stream.write(
'(Mail not sent; to enable sending, set the MAIL_URL ' +
'environment variable.)\n'
);
const readStream = new MailComposer(mail).compile().createReadStream();
readStream.pipe(stream, {end: false});
const future = new Future;
readStream.on('end', function () {
stream.write("====== END MAIL #" + devModeMailId + " ======\n");
readStream.pipe(stream, { end: false });
const future = new Future();
readStream.on('end', function() {
stream.write('====== END MAIL #' + devModeMailId + ' ======\n');
future.return();
});
future.wait();
};
const smtpSend = function (transport, mail) {
const smtpSend = function(transport, mail) {
transport._syncSendMail(mail);
};
@@ -165,7 +183,7 @@ const sendHooks = new Hook();
* false to skip sending.
* @returns {{ stop: function, callback: function }}
*/
Email.hookSend = function (f) {
Email.hookSend = function(f) {
return sendHooks.register(f);
};
@@ -210,13 +228,13 @@ Email.customTransport = undefined;
* You can create a `MailComposer` object via
* `new EmailInternals.NpmModules.mailcomposer.module`.
*/
Email.send = function (options) {
Email.send = function(options) {
if (options.mailComposer) {
options = options.mailComposer.mail;
}
let send = true;
sendHooks.each(hook => {
sendHooks.forEach(hook => {
send = hook(options);
return send;
});
@@ -228,7 +246,11 @@ Email.send = function (options) {
customTransport({ packageSettings, ...options });
return;
}
if (Meteor.isProduction || process.env.MAIL_URL || Meteor.settings.packages?.email) {
if (
Meteor.isProduction ||
process.env.MAIL_URL ||
Meteor.settings.packages?.email
) {
const transport = getTransport();
smtpSend(transport, options);
return;

View File

@@ -1,21 +1,21 @@
Package.describe({
summary: "Send email messages",
version: "2.2.0"
summary: 'Send email messages',
version: '2.2.1-beta261.3',
});
Npm.depends({
nodemailer: "6.6.3",
"stream-buffers": "3.0.2"
nodemailer: '6.6.3',
'stream-buffers': '3.0.2',
});
Package.onUse(function (api) {
Package.onUse(function(api) {
api.use(['ecmascript', 'logging', 'callback-hook'], 'server');
api.mainModule('email.js', 'server');
api.export(['Email', 'EmailInternals'], 'server');
api.export('EmailTest', 'server', {testOnly: true});
api.export('EmailTest', 'server', { testOnly: true });
});
Package.onTest(function (api) {
Package.onTest(function(api) {
api.use('email', 'server');
api.use(['tinytest', 'ecmascript']);
api.addFiles('email_tests.js', 'server');

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'The Meteor command-line tool',
version: '2.6.0',
version: '2.6.1-beta.3',
});
Package.includeTool();

View File

@@ -6,11 +6,36 @@
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz",
"integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA=="
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="
},
"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=="
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"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=="
},
"micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg=="
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
@@ -21,6 +46,11 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
},
"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=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@@ -7,5 +7,46 @@ Standard Minifier for CSS
This package provides a minifier plugin used for Meteor apps by default.
The CSS minifier mostly reduces amount of white-space parsing CSS with
ParseCSS.
## Post CSS
This package can optionally run [PostCSS](https://postcss.org/) plugins on the css files in your app. To enable:
1. Install npm peer dependencies:
```sh
meteor npm install -D postcss postcss-load-config
```
2. Add PostCSS Config. Create a `postcss.config.js` file and add a config:
```js
module.exports = {
plugins: {
autoprefixer: {},
}
};
```
> The example config enables the `autoprefixer` postcss plugin. You can install the plugin by running `meteor npm install -D autoprefixer`.
Learn more about [configuring postcss](https://github.com/postcss/postcss-load-config#packagejson) or find a list of [available plugins](https://www.postcss.parts/).
### Exclude Meteor Packages
In addition to the css files in your app, PostCSS will also process the css files added from Meteor packages. In case you do not want these files to be processed, or they are not compatible with your PostCSS config, you can have PostCSS ignore them by using the `excludedMeteorPackages` option:
```js
module.exports = {
plugins: {
autoprefixer: {},
},
excludedMeteorPackages: [
'github-config-ui',
'constellation:console'
]
};
```
### Tailwind CSS
Tailwind CSS is fully supported. Since HMR applies updates to js files earlier than the css is updated, there can be a delay when using a Tailwind CSS class the first time before the styles are applied.

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'standard-minifier-css',
version: '1.7.4',
version: '1.8.0-beta261.3',
summary: 'Standard css minifier used with Meteor apps by default.',
documentation: 'README.md'
});
@@ -14,7 +14,8 @@ Package.registerBuildPlugin({
npmDependencies: {
"@babel/runtime": "7.15.3",
"source-map": "0.7.3",
"lru-cache": "6.0.0"
"lru-cache": "6.0.0",
"micromatch": "4.0.4"
},
sources: [
'plugin/minify-css.js'

View File

@@ -1,6 +1,7 @@
import sourcemap from "source-map";
import { createHash } from "crypto";
import LRU from "lru-cache";
import { loadPostCss, watchAndHashDeps, usePostCss } from './postcss.js';
Plugin.registerMinifier({
extensions: ["css"],
@@ -11,43 +12,90 @@ Plugin.registerMinifier({
});
class CssToolsMinifier {
constructor() {
this.cache = new LRU({
max: 100
});
async processFilesForBundle (files, options) {
const mode = options.minifyMode;
if (! files.length) return;
const merged = await mergeCss(files);
if (mode === 'development') {
files[0].addStylesheet({
data: merged.code,
sourceMap: merged.sourceMap,
path: 'merged-stylesheets.css'
});
return;
}
const minifiedFiles = CssTools.minifyCss(merged.code);
if (files.length) {
minifiedFiles.forEach(function (minified) {
files[0].addStylesheet({
data: minified
});
});
}
this.depsHashCache = Object.create(null);
}
beforeMinify() {
this.depsHashCache = Object.create(null);
}
watchAndHashDeps(deps, file) {
const cacheKey = JSON.stringify(deps);
if (cacheKey in this.depsHashCache) {
return this.depsHashCache[cacheKey];
}
let hash = watchAndHashDeps(deps, (filePath) => {
return file.readAndWatchFileWithHash(filePath).hash;
});
this.depsHashCache[cacheKey] = hash;
return hash;
}
async minifyFiles (files, mode, postcssConfig) {
const cacheKey = createCacheKey(files, mode);
const cachedResult = this.cache.get(cacheKey);
if (
cachedResult &&
cachedResult.depsCacheKey === this.watchAndHashDeps(cachedResult.deps, files[0])
) {
return cachedResult.stylesheets;
}
let result = [];
const merged = await mergeCss(files, postcssConfig);
if (mode === 'development') {
result = [{
data: merged.code,
sourceMap: merged.sourceMap,
path: 'merged-stylesheets.css'
}];
} else {
const minifiedFiles = CssTools.minifyCss(merged.code);
result = minifiedFiles.map(minified => ({
data: minified
}));
}
this.cache.set(cacheKey, {
stylesheets: result,
deps: merged.deps,
depsCacheKey: this.watchAndHashDeps(merged.deps, files[0])
});
return result;
}
async processFilesForBundle(files, { minifyMode }) {
if (! files.length) return;
const { error, postcssConfig } = await loadPostCss();
if (error) {
files[0].error(postcssInfo.error);
return;
}
const stylesheets = await this.minifyFiles(files, minifyMode, postcssConfig);
stylesheets.forEach(stylesheet => {
files[0].addStylesheet(stylesheet);
});
}
}
const mergeCache = new LRU({
max: 100
});
const hashFiles = Profile("hashFiles", function (files) {
const createCacheKey = Profile("createCacheKey", function (files, minifyMode) {
const hash = createHash("sha1");
hash.update(minifyMode).update("\0");
files.forEach(f => {
hash.update(f.getSourceHash()).update("\0");
});
@@ -62,24 +110,41 @@ function disableSourceMappingURLs(css) {
// Lints CSS files and merges them into one file, fixing up source maps and
// pulling any @import directives up to the top since the CSS spec does not
// allow them to appear in the middle of a file.
const mergeCss = Profile("mergeCss", async function (css) {
const hashOfFiles = hashFiles(css);
let merged = mergeCache.get(hashOfFiles);
if (merged) {
return merged;
}
const mergeCss = Profile("mergeCss", async function (css, postcssConfig) {
// Filenames passed to AST manipulator mapped to their original files
const originals = {};
const deps = [];
const cssAsts = css.map(function (file) {
const astPromises = css.map(async function (file) {
const filename = file.getPathInBundle();
originals[filename] = file;
let ast;
try {
let content = disableSourceMappingURLs(file.getContentsAsString());
if (usePostCss(file, postcssConfig)) {
const result = await postcssConfig.postcss(
postcssConfig.plugins
).process(content, {
// TODO: provide a better way to get the file's path
from: process.cwd() + file._source.url?.replace('/__cordova', ''),
parser: postcssConfig.options.parser
});
result.warnings().forEach(warning => {
warnCb(filename, warning.toString());
});
result.messages.forEach(message => {
if (['dependency', 'dir-dependency'].includes(message.type)) {
deps.push(message);
}
});
content = result.css;
}
const parseOptions = { source: filename, position: true };
const css = disableSourceMappingURLs(file.getContentsAsString());
ast = CssTools.parseCss(css, parseOptions);
ast = CssTools.parseCss(content, parseOptions);
ast.filename = filename;
} catch (e) {
if (e.reason) {
@@ -90,7 +155,7 @@ const mergeCss = Profile("mergeCss", async function (css) {
});
} else {
// Just in case it's not the normal error the library makes.
file.error({message: e.message});
file.error({message: e.stack});
}
return { type: "stylesheet", stylesheet: { rules: [] }, filename };
@@ -99,12 +164,7 @@ const mergeCss = Profile("mergeCss", async function (css) {
return ast;
});
const warnCb = (filename, msg) => {
// XXX make this a buildmessage.warning call rather than a random log.
// this API would be like buildmessage.error, but wouldn't cause
// the build to fail.
console.log(`${filename}: warn: ${msg}`);
};
const cssAsts = await Promise.all(astPromises);
const mergedCssAst = CssTools.mergeCssAsts(cssAsts, warnCb);
@@ -116,8 +176,7 @@ const mergeCss = Profile("mergeCss", async function (css) {
});
if (! stringifiedCss.code) {
mergeCache.set(hashOfFiles, merged = { code: '' });
return merged;
return { code: '', deps };
}
// Add the contents of the input files to the source map of the new file
@@ -220,10 +279,16 @@ const mergeCss = Profile("mergeCss", async function (css) {
return newMap;
});
mergeCache.set(hashOfFiles, merged = {
return {
code: stringifiedCss.code,
sourceMap: newMap.toString()
});
return merged;
sourceMap: newMap.toString(),
deps
};
});
function warnCb (filename, msg) {
// XXX make this a buildmessage.warning call rather than a random log.
// this API would be like buildmessage.error, but wouldn't cause
// the build to fail.
console.log(`${filename}: warn: ${msg}`);
};

View File

@@ -0,0 +1,168 @@
import { createHash } from "crypto";
import micromatch from 'micromatch';
import { performance } from 'perf_hooks';
var fs = Plugin.fs;
var path = Plugin.path;
const DEBUG_CACHE = process.env.DEBUG_METEOR_POSTCSS_DEP_CACHE === 'true';
let postcssConfig;
let loaded = false;
const missingPostCssError = new Error([
'',
`The postcss npm package could not be found in your node_modules`,
'directory. Please run the following command to install it:',
' meteor npm install postcss@8',
'or disable postcss by removing the postcss config.',
''
].join('\n'));
export async function loadPostCss() {
if (loaded) {
return { postcssConfig };
}
let loadConfig;
try {
loadConfig = require('postcss-load-config');
} catch (e) {
console.log('no postcss-load-config');
// The app doesn't have this package installed
// Assuming the app doesn't use PostCSS
loaded = true;
return {};
}
let config;
try {
config = await loadConfig({ meteor: true });
} catch (e) {
if (e.message.includes('No PostCSS Config found in')) {
// PostCSS is not used by this app
loaded = true;
return {};
}
if (e.message.includes('Cannot find module \'postcss\'')) {
return { error: missingPostCssError };
}
e.message = `While loading postcss config: ${e.message}`;
return {
error: e
};
}
let postcss;
try {
postcss = require('postcss');
} catch (e) {
return { error: missingPostCssError };
}
const postcssVersion = require('postcss/package.json').version;
const major = parseInt(postcssVersion.split('.')[0], 10);
if (major !== 8) {
// TODO: should this just be a warning instead?
const error = new Error([
'',
`Found version ${postcssVersion} of postcss in your node_modules`,
'directory. standard-minifier-css is only compatible with',
'version 8 of PostCSS. Please restart Meteor after installing',
'a supported version of PostCSS',
''
].join('\n'));
return { error };
}
loaded = true;
config.postcss = postcss;
postcssConfig = config;
return { postcssConfig };
}
export function usePostCss(file, postcssConfig) {
if (!postcssConfig) {
return false;
}
const excludedPackages = postcssConfig.options.excludedMeteorPackages || [];
const path = file.getPathInBundle();
const excluded = excludedPackages.some(name => {
return path.includes(`packages/${name.replace(':', '_')}`)
});
return !excluded;
}
export const watchAndHashDeps = Profile(
'watchAndHashDeps',
function (deps, hashAndWatchFile) {
const hash = createHash('sha1');
const globsByDir = Object.create(null);
let fileCount = 0;
let folderCount = 0;
let start = performance.now();
deps.forEach(dep => {
if (dep.type === 'dependency') {
fileCount += 1;
const fileHash = hashAndWatchFile(dep.file);
hash.update(fileHash).update('\0');
} else if (dep.type === 'dir-dependency') {
if (dep.dir in globsByDir) {
globsByDir[dep.dir].push(dep.glob || '**');
} else {
globsByDir[dep.dir] = [dep.glob || '**'];
}
}
});
Object.entries(globsByDir).forEach(([parentDir, globs]) => {
const matchers = globs.map(glob => micromatch.matcher(glob));
function walk(relDir) {
const absDir = path.join(parentDir, relDir);
hash.update(absDir).update('\0');
folderCount += 1;
const entries = fs.readdirWithTypesSync(absDir);
for (const entry of entries) {
const relPath = path.join(relDir, entry.name);
if (entry.isFile() && matchers.some(isMatch => isMatch(relPath))) {
const absPath = path.join(absDir, entry.name);
fileCount += 1;
hash.update(hashAndWatchFile(absPath)).update('\0');
} else if (
entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.meteor'
) {
walk(relPath);
}
}
}
walk('./');
});
let digest = hash.digest('hex');
if (DEBUG_CACHE) {
console.log('--- PostCSS Cache Info ---');
console.log('Glob deps', JSON.stringify(globsByDir, null, 2));
console.log('File dep count', fileCount);
console.log('Walked folders', folderCount);
console.log('Created dep cache key in', performance.now() - start, 'ms');
console.log('--------------------------');
}
return digest;
});

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'typescript',
version: '4.4.1',
version: '4.5.4-beta261.3',
summary:
'Compiler plugin that compiles TypeScript and ECMAScript in .ts and .tsx files',
documentation: 'README.md',

View File

@@ -1,6 +1,6 @@
{
"track": "METEOR",
"version": "2.6-rc.2",
"version": "2.6.1-beta.3",
"recommended": false,
"official": false,
"description": "Meteor experimental release"

View File

@@ -5,7 +5,7 @@ set -u
UNAME=$(uname)
ARCH=$(uname -m)
NODE_VERSION=14.18.3
NODE_VERSION=14.19.0
MONGO_VERSION_64BIT=5.0.5
MONGO_VERSION_32BIT=3.2.22
NPM_VERSION=6.14.15

0
scripts/ci/run-selftest-ci.sh Normal file → Executable file
View File

View File

@@ -14,8 +14,8 @@ var packageJson = {
pacote: "https://github.com/meteor/pacote/tarball/a81b0324686e85d22c7688c47629d4009000e8b8",
"node-gyp": "8.0.0",
"node-pre-gyp": "0.15.0",
typescript: "4.3.5",
"@meteorjs/babel": "7.15.0",
typescript: "4.5.4",
"@meteorjs/babel": "7.16.0-beta.0",
// Keep the versions of these packages consistent with the versions
// found in dev-bundle-server-package.js.
"meteor-promise": "0.9.0",

View File

@@ -318,7 +318,7 @@ function statOrNullHelper(path: string, preserveSymlinks = false) {
return preserveSymlinks
? lstat(path)
: stat(path);
} catch (e) {
} catch (e: any) {
if (e.code === "ENOENT") {
return null;
}
@@ -329,7 +329,7 @@ function statOrNullHelper(path: string, preserveSymlinks = false) {
export function realpathOrNull(path: string) {
try {
return realpath(path);
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
return null;
}
@@ -347,7 +347,7 @@ export function rm_recursive_async(path: string) {
export const rm_recursive = Profile("files.rm_recursive", (path: string) => {
try {
rimraf.sync(convertToOSPath(path));
} catch (e) {
} catch (e: any) {
if ((e.code === "ENOTEMPTY" ||
e.code === "EPERM") &&
canYield()) {
@@ -452,7 +452,7 @@ export function mkdir_p(dir: string, mode: number | null = null) {
try {
mkdir(p, mode);
} catch (err) {
} catch (err: any) {
if (err.code === "EEXIST") {
if (pathIsDirectory(p)) {
// all good, someone else created this directory for us while we were
@@ -575,7 +575,7 @@ Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite(
try {
symlink(...args);
} catch (e) {
} catch (e: any) {
if (e.code === "EEXIST") {
function normalizePath(path: string) {
return convertToOSPath(path).replace(/[\/\\]$/, "")
@@ -908,7 +908,7 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => {
try {
rename(toDir, garbageDir);
cleanupGarbage = true;
} catch (e) {
} catch (e: any) {
if (e.code === 'EXDEV') {
// Some (notably Docker) file systems will fail to do a seemingly
// harmless operation, such as renaming, on what is apparently the same
@@ -926,7 +926,7 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => {
if (! forceCopy) {
try {
rename(fromDir, toDir);
} catch (e) {
} catch (e: any) {
// It's possible that there may not have been a `toDir` to have
// advanced warning about this, so we're prepared to handle it again.
if (e.code === 'EXDEV') {
@@ -1072,7 +1072,7 @@ export function runJavaScript(code: string, {
// Pass 'true' as third argument if we want the parse error on
// stderr (which we don't).
var script = require('vm').createScript(wrapped, stackFilename);
} catch (nodeParseError) {
} catch (nodeParseError: any) {
if (!(nodeParseError instanceof SyntaxError)) {
throw nodeParseError;
}
@@ -1090,7 +1090,7 @@ export function runJavaScript(code: string, {
const { parse } = require('@meteorjs/babel');
try {
parse(wrapped, { strictMode: false });
} catch (parseError) {
} catch (parseError: any) {
if (typeof parseError.loc !== "object") {
throw parseError;
}
@@ -1158,7 +1158,7 @@ export class OfflineError {
export function readdirNoDots(path: string) {
try {
var entries = readdir(path);
} catch (e) {
} catch (e: any) {
if (e.code === 'ENOENT') {
return [];
}
@@ -1196,7 +1196,7 @@ export function splitBufferToLines(buffer: Buffer) {
export function getLinesOrEmpty(file: string) {
try {
return getLines(file);
} catch (e) {
} catch (e: any) {
if (e && e.code === 'ENOENT') {
return [];
}
@@ -1209,7 +1209,7 @@ export function getLinesOrEmpty(file: string) {
export function readJSONOrNull(file: string) {
try {
var raw = readFile(file, 'utf8');
} catch (e) {
} catch (e: any) {
if (e && e.code === 'ENOENT') {
return null;
}
@@ -1577,7 +1577,7 @@ export const rename = isWindowsLikeFilesystem() ? function (from: string, to: st
rimraf.sync(osTo);
wrappedRename(from, to);
resolve();
} catch (err) {
} catch (err: any) {
if (err.code !== 'EPERM' && err.code !== 'EACCES') {
reject(err);
} else if (Date.now() - startTimeMs < timeLimitMs) {
@@ -1588,7 +1588,7 @@ export const rename = isWindowsLikeFilesystem() ? function (from: string, to: st
}
}
attempt();
}).catch(error => {
}).catch((error: any) => {
if (error.code === 'EPERM' ||
error.code === 'EACCESS') {
cp_r(from, to, { preserveSymlinks: true });

View File

@@ -14,6 +14,7 @@ export {
read, read as readSync,
readFile, readFile as readFileSync,
readdir, readdir as readdirSync,
readdirWithTypes as readdirWithTypesSync,
readlink, readlink as readlinkSync,
realpath, realpath as realpathSync,
rename, rename as renameSync,

View File

@@ -265,7 +265,7 @@ export const optimisticLStatOrNull = makeCheapPathFunction(
(path: string) => {
try {
return optimisticLStat(path);
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
dependOnParentDirectory(path);
return null;
@@ -282,7 +282,7 @@ export const optimisticHashOrNull = makeOptimistic("hashOrNull", (
try {
return sha1(optimisticReadFile(path, options)) as string;
} catch (e) {
} catch (e: any) {
if (e.code !== "EISDIR" &&
e.code !== "ENOENT") {
throw e;
@@ -309,7 +309,7 @@ makeOptimistic("readJsonOrNull", (
let contents: string | Buffer;
try {
contents = optimisticReadFile(path, options);
} catch (e) {
} catch (e: any) {
if (e.code === "ENOENT") {
dependOnParentDirectory(path);
return null;
@@ -399,7 +399,7 @@ wrap((absRootDir: string, relDir: string) => {
const optimisticIsSymbolicLink = wrap((path: string) => {
try {
return lstat(path)?.isSymbolicLink();
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
dependOnParentDirectory(path);
return false;

View File

@@ -38,7 +38,7 @@ const WATCHER_CLEANUP_DELAY_MS = 30000;
// watched folder and create a separate watcher for each subfolder. Until it has a
// way for us to filter which folders it walks we will continue to use
// pathwatcher to avoid having too many watchers.
let watcherLibrary = process.env.METEOR_WATCHER_LIBRARY ||
let watcherLibrary = process.env.METEOR_WATCHER_LIBRARY ||
(process.platform === 'linux' ? 'pathwatcher' : 'nsfw');
// Pathwatcher complains (using console.error, ugh) if you try to watch
@@ -360,7 +360,7 @@ function watchLibraryWatch(absPath: string, callback: EntryCallback) {
if (watcherEnabled && watcherLibrary === 'pathwatcher') {
try {
return pathwatcher.watch(convertToOSPath(absPath), callback);
} catch (e) {
} catch (e: any) {
maybeSuggestRaisingWatchLimit(e);
// ... ignore the error. We'll still have watchFile, which is good
// enough.
@@ -430,7 +430,7 @@ export function addWatchRoot(absPath: string) {
}
watchRoots.add(absPath);
// If there already is a watcher for a parent directory, there is no need
// to create this watcher.
for (const path of watchRoots) {

View File

@@ -314,7 +314,7 @@ export class WatchSet {
export function readFile(absPath: string) {
try {
return files.readFile(absPath);
} catch (e) {
} catch (e: any) {
// Rethrow most errors.
if (! e || (e.code !== 'ENOENT' && e.code !== 'EISDIR')) {
throw e;
@@ -340,7 +340,7 @@ function readAndStatDirectory(absPath: string) {
// Read the directory.
try {
var contents = files.readdirWithTypes(absPath);
} catch (e) {
} catch (e: any) {
// If the path is not a directory, return null; let other errors through.
if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) {
return null;
@@ -618,7 +618,7 @@ export class Watcher {
} else if (stat.isDirectory()) {
try {
var dirFiles = files.readdir(absPath);
} catch (err) {
} catch (err: any) {
if (err.code === "ENOENT" ||
err.code === "ENOTDIR") {
// The directory was removed or changed type since we called
@@ -834,8 +834,8 @@ export function readAndWatchDirectory(
) {
const contents = readDirectory(options);
watchSet.addDirectory({
contents,
...options,
contents,
});
return contents;
}
@@ -858,7 +858,7 @@ export function readAndWatchFileWithHash(watchSet: WatchSet, absPath: string) {
try {
result.contents = files.readFile(absPath);
} catch (e) {
} catch (e: any) {
if (e && e.code === "EISDIR") {
// Avoid adding directories to the watchSet as files.
return result;

View File

@@ -1119,10 +1119,8 @@ class Target {
// Takes a CssOutputResource and returns a string of minified CSS,
// or null to indicate no minification occurred.
// TODO Cache result by resource hash?
minifyCssResource(resource) {
if (! minifiersByExt.css ||
minifyMode === "development") {
minifyCssResource: (resource) => {
if (! minifiersByExt.css) {
// Indicates the caller should use the original resource.data
// without minification.
return null;
@@ -1142,6 +1140,7 @@ class Target {
arch: target.arch,
minifier: minifiersByExt.css,
minifyMode,
watchSet: this.watchSet
}).map(file => file.contents("utf8")).join("\n");
}
});
@@ -1691,6 +1690,7 @@ class ClientTarget extends Target {
arch: this.arch,
minifier: minifierDef,
minifyMode,
watchSet: this.watchSet
});
}
@@ -1896,15 +1896,15 @@ class ClientTarget extends Target {
}
}
const { wrap, defaultMakeCacheKey } = require("optimism");
const minifyCssFiles = Profile("minifyCssFiles", wrap(function (files, {
function minifyCssFiles (files, {
arch,
minifier,
minifyMode,
watchSet
}) {
const inputHashesByCssFile = new Map;
const sources = files.map(file => {
const cssFile = new CssFile(file, { arch });
const cssFile = new CssFile(file, { arch, watchSet });
inputHashesByCssFile.set(cssFile, file.hash());
return cssFile;
});
@@ -1943,16 +1943,7 @@ const minifyCssFiles = Profile("minifyCssFiles", wrap(function (files, {
return newFile;
});
}));
}, {
makeCacheKey(files, { arch, minifier, minifyMode }) {
return defaultMakeCacheKey(
minifier,
arch,
minifyMode,
hashOfFiles(files),
);
}
}));
}
const { createHash } = require("crypto");
function hashOfFiles(files) {
@@ -3340,6 +3331,13 @@ function bundle({
return mergeAppWatchSets();
}
// Call any beforeMinify callbacks defined by minifier plugins
minifiers.forEach(minifier => {
if (typeof minifier.userPlugin.beforeMinify === 'function') {
minifier.userPlugin.beforeMinify();
}
});
const targets = Object.create(null);
const hasOwn = Object.prototype.hasOwnProperty;

View File

@@ -80,7 +80,7 @@ const reifyCompileWithCache = Profile("reifyCompileWithCache", wrap(function (
if (cacheFilePath) {
try {
return readFile(cacheFilePath, "utf8");
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
}
}
@@ -1090,7 +1090,7 @@ export default class ImportScanner {
try {
file.deps = file.deps || this.findImportedModuleIdentifiers(file);
} catch (e) {
} catch (e: any) {
if (e.$ParseError) {
(buildmessage as any).error(e.message, {
file: file.sourcePath,
@@ -1214,7 +1214,7 @@ export default class ImportScanner {
private readPackageJson(absPath: string) {
try {
var info = this.readFile(absPath);
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
return null;
}
@@ -1257,7 +1257,7 @@ export default class ImportScanner {
try {
var info = this.readFile(absPath);
} catch (e) {
} catch (e: any) {
if (e.code !== "ENOENT") throw e;
return null;
}

View File

@@ -1,4 +1,14 @@
import buildmessage from '../utils/buildmessage.js';
import {
readAndWatchFileWithHash,
} from '../fs/watch';
import {
optimisticReadFile,
optimisticHashOrNull,
} from "../fs/optimistic";
import {
convertToPosixPath
} from '../fs/files';
const buildPluginModule = require('./build-plugin.js');
class InputFile extends buildPluginModule.InputFile {
@@ -7,6 +17,7 @@ class InputFile extends buildPluginModule.InputFile {
this._source = source;
this._arch = options.arch;
this._watchSet = options.watchSet;
this._minifiedFiles = [];
}
@@ -75,5 +86,17 @@ export class CssFile extends InputFile {
addStylesheet(options) {
this._minifiedFiles.push({ ...options });
}
}
readAndWatchFileWithHash(path) {
const filePath = convertToPosixPath(path);
const hash = optimisticHashOrNull(filePath);
const contents = optimisticReadFile(filePath);
this._watchSet.addFile(filePath, hash);
return {
hash,
contents
}
}
}

View File

@@ -18,7 +18,7 @@
"@types/mocha": "^8.2.3",
"@types/react": "^17.0.30",
"@types/react-dom": "^17.0.9",
"typescript": "^4.4.4"
"typescript": "^4.5.4"
},
"meteor": {
"mainModule": {

View File

@@ -1,4 +1,5 @@
<body>
<div class="production_css">Text for prod</div>
<div class="development_css">Text for devel</div>
<div class="minified_lazy">Text for imported</div>
</body>

View File

@@ -1,6 +1,8 @@
if (Meteor.isClient) {
require('./imports/imported.css');
Meteor.startup(function () {
['production_css', 'development_css'].forEach(cls => {
['production_css', 'development_css', 'minified_lazy'].forEach(cls => {
var color = getComputedStyle(document.querySelectorAll('.' + cls)[0]).color;
Meteor.call('print', cls + ': ' + color);
});

View File

@@ -0,0 +1,3 @@
.lazy-resource {
color: rgb(0, 256, 0);
}

View File

@@ -29,6 +29,7 @@ CustomMinifier.prototype.processFilesForBundle = function (files, options) {
data: contents
});
} else {
contents = contents.replace(/lazy-resource/g, 'minified_lazy');
file.addStylesheet({
data: contents
});
@@ -37,5 +38,3 @@ CustomMinifier.prototype.processFilesForBundle = function (files, options) {
Plugin.nudge();
});
};

View File

@@ -22,6 +22,7 @@ selftest.define('custom minifier - devel vs prod', function (options) {
run.match('production_css: rgb(255, 0, 0)');
run.match('development_css: rgb(0, 0, 0)');
run.match('minified_lazy: rgb(0, 255, 0)');
run.match('Message (client): production_js');
run.stop();
@@ -43,6 +44,7 @@ selftest.define('custom minifier - devel vs prod', function (options) {
run.match('production_css: rgb(0, 0, 0)');
run.match('development_css: rgb(255, 0, 0)');
run.match('minified_lazy: rgb(0, 255, 0)');
run.match('Message (client): development_js');
run.stop();

View File

@@ -3,7 +3,7 @@ import { enterJob } from '../../../utils/buildmessage.js';
import { ensureDependencies } from '../../../cli/dev-bundle-helpers.js';
const NPM_DEPENDENCIES = {
puppeteer: '8.0.0'
puppeteer: '13.2.0'
};
export default class PuppeteerClient extends Client {

View File

@@ -20,7 +20,7 @@ export function transform(callback: LineTransformer) {
let line = chunk.toString("utf8");
try {
line = await callback(line);
} catch (error) {
} catch (error: any) {
done(error);
return;
}