mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'devel' of github.com:meteor/meteor into mongo-no-fiber-option
This commit is contained in:
1
.github/workflows/guide.yml
vendored
1
.github/workflows/guide.yml
vendored
@@ -30,4 +30,3 @@ jobs:
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GUIDE_SITE_ID }}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ Current Core Committers:
|
||||
|
||||
### Tracking project work
|
||||
|
||||
Right now, the best place to track the work being done on Meteor is to take a look at the latest release milestone [here](https://github.com/meteor/meteor/milestones). Also, the [Meteor Roadmap](Roadmap.md) contains high-level information on the current priorities of the project.
|
||||
Right now, the best place to track the work being done on Meteor is to take a look at the latest release milestone [here](https://github.com/meteor/meteor/milestones). Also, the [Meteor Roadmap](https://docs.meteor.com/roadmap.html) contains high-level information on the current priorities of the project.
|
||||
|
||||
## Reporting a bug in Meteor
|
||||
<a name="reporting-bug"></a>
|
||||
@@ -126,7 +126,7 @@ for more details on proposing changes to core code.
|
||||
Feature requests are tracked in the [Discussions](https://github.com/meteor/meteor/discussions).
|
||||
|
||||
Meteor is a big project with [many sub-projects](https://github.com/meteor/meteor/tree/devel/packages).
|
||||
Community is welcome to help in all the sub-projects. We use our [roadmap](Roadmap.md) to communicate the high-level features we're currently prioritizing.
|
||||
Community is welcome to help in all the sub-projects. We use our [roadmap](https://docs.meteor.com/roadmap.html) to communicate the high-level features we're currently prioritizing.
|
||||
|
||||
Every additional feature adds a maintenance cost in addition to its value. This
|
||||
cost starts with the work of writing the feature or reviewing a community pull
|
||||
@@ -199,7 +199,7 @@ For more information about how to work with Meteor core, take a look at the [Dev
|
||||
|
||||
### Proposing your change
|
||||
|
||||
You'll have the best chance of getting a change into core if you can build consensus in the community for it or if it is listed in the [roadmap](https://github.com/meteor/meteor/blob/devel/Roadmap.md). Start by creating a well specified Discussion [here](https://github.com/meteor/meteor/discussions).
|
||||
You'll have the best chance of getting a change into core if you can build consensus in the community for it or if it is listed in the [roadmap](https://docs.meteor.com/roadmap.html). Start by creating a well specified Discussion [here](https://github.com/meteor/meteor/discussions).
|
||||
|
||||
Help drive discussion and advocate for your feature on the Github ticket (and perhaps the forums). The higher the demand for the feature and the greater the clarity of it's specification will determine the likelihood of a core contributor prioritizing your feature by flagging it with the `ready` label.
|
||||
|
||||
|
||||
8873
History.md
8873
History.md
File diff suppressed because it is too large
Load Diff
171
Roadmap.md
171
Roadmap.md
@@ -1,171 +0,0 @@
|
||||
# Meteor Roadmap
|
||||
|
||||
**Up to date as of Jan 20, 2021**
|
||||
|
||||
This document describes the high-level features and actions for the Meteor project in the near- to medium-term future. This roadmap was built based on community feedback and to improve areas where Meteor is already strong. The description of many items include sentences and ideas from Meteor community members.
|
||||
|
||||
As with any roadmap, this is a living document that will evolve as priorities and dependencies shift; we aim to update the roadmap with any changes or status updates every quarter.
|
||||
|
||||
Contributors are encouraged to focus their efforts on work that aligns with the roadmap then we can work together in these areas.
|
||||
|
||||
PRs to the roadmap are welcome. If you are willing to contribute please open a PR explaining your ideas and what you would be able to do yourself.
|
||||
|
||||
## Priorities for V2
|
||||
|
||||
Updated at: 2021/01/20
|
||||
|
||||
V2 initial release (2.0) was delivered today (2021/01/20) with Hot Module Replacement (HMR), React Fast Refresh, and Free deploy including MongoDB on [Cloud](https://www.meteor.com/cloud) and some other features. See all the changes [here](./History.md).
|
||||
|
||||
We expect to have HMR also working for Blaze in Meteor 2.1 in the following weeks (it's currently on [beta](https://github.com/meteor/blaze/pull/313)).
|
||||
|
||||
Other important updates that you should expect to see in Meteor 2.2, 2.3 and so on:
|
||||
- Node.js 14; [PR](https://github.com/meteor/meteor/pull/11197)
|
||||
- Cordova 10; [PR](https://github.com/meteor/meteor/pull/11208)
|
||||
- Remove deprecated code pre v1; [PR](https://github.com/meteor/meteor/pull/11226)
|
||||
- Tree-shaking; [PR](https://github.com/meteor/meteor/pull/11164)
|
||||
- Blaze HMR; [PR](https://github.com/meteor/blaze/pull/313)
|
||||
- Tutorials migration (help needed, understand [here](https://forums.meteor.com/t/new-meteor-react-tutorial-and-new-format-for-tutorials/54074));
|
||||
|
||||
Do you want to get involved in the items above? Talk to [Filipe Névola](https://twitter.com/filipenevola) in the [community Slack](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc)
|
||||
|
||||
V2 minor releases are not limited by the items above, these are the ones already in progress, some of them are going to be ready in the next weeks.
|
||||
|
||||
## Priorities for V3
|
||||
|
||||
Updated at: 2021/01/20
|
||||
|
||||
Meteor is accelerating! We are going release more often this year.
|
||||
|
||||
We expect to have new features focusing in ease app development in V3 or probably in V2 as well.
|
||||
|
||||
See feature requests and other discussions [here](https://github.com/meteor/meteor/discussions)
|
||||
|
||||
## Recently completed
|
||||
|
||||
### MongoDB shared hosting on Cloud
|
||||
- Leaders: Meteor Software
|
||||
- Status: shipped in January 2021
|
||||
|
||||
You can host your app on Galaxy and use our shared MongoDB for non-commercial/non-production apps. We don't recommend a shared MongoDB instance for production apps.
|
||||
|
||||
### Free deploy on Cloud
|
||||
- Leaders: Meteor Software
|
||||
- Status: shipped in January 2021
|
||||
|
||||
Meteor free deploy is back.
|
||||
|
||||
### Hot Module Replacement
|
||||
- Leaders: [zodern](https://github.com/zodern)
|
||||
- Status: shipped in January 2021
|
||||
- PRs: https://github.com/meteor/meteor/pull/11117
|
||||
|
||||
HMR is available since Meteor 2.0
|
||||
|
||||
### Vue.js
|
||||
- Leaders: [Brian Mulhall](https://github.com/BrianMulhall)
|
||||
- Status: shipped in August 2020
|
||||
- PRs: https://github.com/meteor/simple-todos-vue
|
||||
|
||||
Tutorial is ready and create command meteor create --vue
|
||||
|
||||
### Apollo
|
||||
- Leaders: [Jan Dvorak](https://github.com/StorytellerCZ)
|
||||
- Status: shipped in August 2020
|
||||
- PRs: https://github.com/meteor/meteor/pull/11119
|
||||
|
||||
Apollo skeleton, meteor create --apollo
|
||||
|
||||
### Performance improvements on Windows
|
||||
- Leaders: [zodern](https://github.com/zodern)
|
||||
- Status: shipped in August 2020
|
||||
- PRs: https://github.com/meteor/meteor/pull/10838 https://github.com/meteor/meteor/pull/11114 https://github.com/meteor/meteor/pull/11115 https://github.com/meteor/meteor/pull/11102
|
||||
|
||||
Explore ideas to improve performance on Windows such as build in place.
|
||||
|
||||
### Update React Tutorial
|
||||
- Leaders: [Leonardo Venturini](https://github.com/leonardoventurini) / [Brian Mulhall](https://github.com/BrianMulhall)
|
||||
- Status: shipped in July 2020
|
||||
- PRs: https://github.com/meteor/simple-todos-react
|
||||
|
||||
### React Native
|
||||
- Leaders: [Nathaniel Dsouza](https://github.com/TheRealNate)
|
||||
- Status: shipped in June 2020
|
||||
- PRs: https://github.com/meteor/guide/pull/1041 https://github.com/meteor/guide/pull/1039 https://github.com/meteor/guide/pull/1035
|
||||
|
||||
Guide is ready ([check here](https://guide.meteor.com/react-native.html)).
|
||||
|
||||
### Update Blaze Tutorial
|
||||
- Leaders: [Jan Küster](https://github.com/jankapunkt), [Harry Adel](https://github.com/harryadelb), [Brian Mulhall](https://github.com/BrianMulhall)
|
||||
- Status: shipped in April 2020
|
||||
- PRs: https://github.com/meteor/tutorials/pull/200 https://github.com/meteor/tutorials/pull/199
|
||||
|
||||
Blaze tutorial should reflect latest best practices.
|
||||
|
||||
### Update MongoDB driver
|
||||
- Leaders: [Christian Klaussner](https://github.com/klaussner)
|
||||
- Status: shipped in Meteor 1.10.1
|
||||
- PRs: https://github.com/meteor/meteor/pull/10861 / https://github.com/meteor/meteor/pull/10723
|
||||
|
||||
Update to Mongodb driver from 3.2.7 to 3.5.4, this version is compatible with MongoDB 4.2.
|
||||
|
||||
### Update Cordova to 9
|
||||
- Leaders: [Filipe Névola](https://github.com/filipenevola) / [Renan Castro](https://github.com/renanccastro)
|
||||
- Status: shipped in Meteor 1.10.1
|
||||
- PRs: https://github.com/meteor/meteor/pull/10861 / https://github.com/meteor/meteor/pull/10810 / https://github.com/meteor/meteor/pull/10861
|
||||
|
||||
Update Cordoba lib and its dependencies to latest (version 9)
|
||||
|
||||
### Update to Node.js 12
|
||||
- Leaders: [Ben Newman](https://github.com/benjamn)
|
||||
- Status: shipped in Meteor 1.9.
|
||||
- PRs: https://github.com/meteor/meteor/pull/10527
|
||||
|
||||
Since Node.js 12 is scheduled to become the LTS version on October 1st, 2019, Meteor 1.9 will update the Node.js version used by Meteor from 8.16.1 (in Meteor 1.8.2) to 12.10.0 (the most recent current version).
|
||||
|
||||
### Different JS bundles for modern versus legacy browsers
|
||||
|
||||
- Status: shipped in Meteor 1.6.2.
|
||||
- PRs: https://github.com/meteor/meteor/pull/9439
|
||||
|
||||
### Eliminate the need for an `imports` directory
|
||||
|
||||
- Status: shipped in Meteor 1.6.2.
|
||||
- PRs: https://github.com/meteor/meteor/pull/9690, https://github.com/meteor/meteor/pull/9714, https://github.com/meteor/meteor/pull/9715
|
||||
|
||||
### Make Mongo more optional
|
||||
|
||||
- Status: shipped in Meteor 1.6.2.
|
||||
- PRs: https://github.com/meteor/meteor/pull/8999
|
||||
|
||||
### Upgrade to Node 8
|
||||
|
||||
- Status: shipped in Meteor 1.6.
|
||||
- PRs: https://github.com/meteor/meteor/pull/8728
|
||||
|
||||
### Upgrade to npm 5
|
||||
|
||||
- Status: shipped in Meteor 1.6
|
||||
|
||||
### Dynamic `import(...)`
|
||||
|
||||
- Status: shipped in Meteor 1.5
|
||||
|
||||
### Rebuild performance improvements
|
||||
|
||||
- Status: shipped in Meteor 1.4.2
|
||||
|
||||
### MongoDB updates
|
||||
|
||||
- Status: shipped in Meteor 1.4
|
||||
|
||||
### Support for Node 4 and beyond
|
||||
|
||||
- Status: shipped in Meteor 1.4
|
||||
|
||||
### View Layer
|
||||
|
||||
- Status: Blaze split into new repository and can be published independently as of 1.4.2
|
||||
|
||||
### Other
|
||||
|
||||
For more completed items, refer to the project history here: https://github.com/meteor/meteor/blob/devel/History.md
|
||||
@@ -1,6 +1,8 @@
|
||||
title: Meteor API Docs
|
||||
subtitle: API Docs
|
||||
versions:
|
||||
- '2.7'
|
||||
- '2.6'
|
||||
- '2.5'
|
||||
- '2.4'
|
||||
- '2.3'
|
||||
@@ -29,6 +31,7 @@ sidebar_categories:
|
||||
- index
|
||||
- changelog
|
||||
- install
|
||||
- roadmap
|
||||
API:
|
||||
- api/core
|
||||
- api/pubsub
|
||||
@@ -56,6 +59,7 @@ sidebar_categories:
|
||||
Packages:
|
||||
- packages/accounts-ui
|
||||
- packages/accounts-passwordless
|
||||
- packages/accounts-2fa
|
||||
- packages/appcache
|
||||
- packages/audit-argument-checks
|
||||
- packages/autoupdate
|
||||
@@ -74,6 +78,7 @@ sidebar_categories:
|
||||
- packages/random
|
||||
- packages/server-render
|
||||
- packages/spacebars
|
||||
- packages/standard-minifier-css
|
||||
- packages/underscore
|
||||
- packages/url
|
||||
- packages/webapp
|
||||
|
||||
9167
docs/history.md
Normal file
9167
docs/history.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -95,7 +95,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Callback descriptions are going to be embeded into Function descriptions
|
||||
// Callback descriptions are going to be embedded into Function descriptions
|
||||
// when they are used as arguments, so we always attach them to reference
|
||||
// them later.
|
||||
var callbacks = helper.find(data, {kind: "typedef"});
|
||||
|
||||
@@ -227,9 +227,10 @@ First, add the service configuration package:
|
||||
meteor add service-configuration
|
||||
```
|
||||
|
||||
Then, in your app (this example is for the Weebo service):
|
||||
Then, inside the server of your app (this example is for the Weebo service), import `ServiceConfiguration`:
|
||||
|
||||
```js
|
||||
import { ServiceConfiguration } from 'meteor/service-configuration';
|
||||
ServiceConfiguration.configurations.upsert(
|
||||
{ service: 'weibo' },
|
||||
{
|
||||
@@ -242,7 +243,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.7 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 +335,6 @@ Accounts.ui.config({
|
||||
passwordSignupFields: 'USERNAME_AND_OPTIONAL_EMAIL'
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
Since Meteor 2.7 you can configure these in your Meteor settings under `Meteor.settings.public.packages.accounts-ui-unstyled`.
|
||||
|
||||
@@ -117,7 +117,7 @@ Email.customTransport = (data) => {
|
||||
// The rest of the options are from Email.send options
|
||||
const mailgun = Mailgun({ apiKey: data.packageSettings.mailgun.privateKey, domain: 'mg.mygreatapp.com' })
|
||||
|
||||
// Since the data object that we recieve already includes the correct key names for sending
|
||||
// Since the data object that we receive already includes the correct key names for sending
|
||||
// we can just pass it to the mailgun sending message.
|
||||
mailgun.messages().send(data, (error, body) => {
|
||||
if (error) Log.error(error)
|
||||
|
||||
@@ -30,10 +30,40 @@ App.icons({
|
||||
// More screen sizes and platforms...
|
||||
});
|
||||
|
||||
// Before Meteor 2.6 we had to pass device specific splash screens for iOS, but this behavior was dropped in favor of story board images.
|
||||
App.launchScreens({
|
||||
'iphone_2x': 'splash/Default@2x~iphone.png',
|
||||
'iphone5': 'splash/Default~iphone5.png',
|
||||
// More screen sizes and platforms...
|
||||
// iOS
|
||||
// For most cases you will only need to use the 'ios_universal' and 'ios_universal_3x'.
|
||||
'ios_universal': { src: 'splash/Default@2x.png', srcDarkMode: 'splash/Default@2x~dark.png' }, // (2732x2732) - All @2x devices, if device/mode specific is not declared
|
||||
'ios_universal_3x': 'splash/Default@3x.png', // (2208x2208) - All @3x devices, if device/mode specific is not declared
|
||||
|
||||
// If you still want to use a universal splash, but want to fine-tune for the device mode (landscape, portrait), then use the following keys:
|
||||
'Default@2x~universal~comany': 'splash/Default@2x~universal~comany.png', // (1278x2732) - All @2x devices in portrait mode.
|
||||
'Default@2x~universal~comcom': 'splash/Default@2x~universal~comcom.png', // (1334x750) - All @2x devices in landscape (narrow) mode.
|
||||
'Default@3x~universal~anycom': 'splash/Default@3x~universal~anycom.png', // (2208x1242) - All @3x devices in landscape (wide) mode.
|
||||
'Default@3x~universal~comany': 'splash/Default@3x~universal~comany.png', // (1242x2208) - All @3x devices in portrait mode.
|
||||
|
||||
// However, if you need to fine tune the splash screens for the device idiom (iPhone, iPad, etc).
|
||||
'Default@2x~iphone~anyany': 'splash/Default@2xiphoneanyany.png', // (1334x1334) - iPhone SE/6s/7/8/XR
|
||||
'Default@2x~iphone~comany': 'splash/Default@2xiphonecomany.png', // (750x1334) - iPhone SE/6s/7/8/XR - portrait mode
|
||||
'Default@2x~iphone~comcom': 'splash/Default@2xiphonecomcom.png', // (1334x750) - iPhone SE/6s/7/8/XR - landscape (narrow) mode
|
||||
'Default@3x~iphone~anyany': 'Default@3xiphoneanyany.png', // (2208x2208) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max
|
||||
'Default@3x~iphone~anycom': { src: 'splash/Default@3xiphoneanycom.png', srcDarkMode: 'splash/Default@3xiphoneanycom~dark.png' }, // (2208x1242) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - landscape (wide) mode
|
||||
'Default@3x~iphone~comany': 'Default@3xiphonecomany.png', // (1242x2208) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - portrait mode
|
||||
'Default@2x~ipad~anyany': 'Default@2xipadanyany.png', // (2732x2732) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9"
|
||||
'Default@2x~ipad~comany': 'Default@2xipadcomany.png', // (1278x2732) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9" - portrait mode
|
||||
|
||||
// Android
|
||||
'android_mdpi_portrait': 'splash/android_mdpi_portrait.png', // (320x480)
|
||||
'android_mdpi_landscape': { src: 'splash/android_mdpi_landscape.png', srcDarkMode: 'splash/android_mdpi_landscape-night.png' }, // (480x320)
|
||||
'android_hdpi_portrait': 'splash/android_hdpi_portrait.png', // (480x800)
|
||||
'android_hdpi_landscape': 'splash/android_hdpi_landscape.png', // (800x480)
|
||||
'android_xhdpi_portrait': 'splash/android_xhdpi_portrait.png', // (720x1280)
|
||||
'android_xhdpi_landscape': 'splash/android_xhdpi_landscape.png', // (1280x720)
|
||||
'android_xxhdpi_portrait': { src: 'splash/android_xxhdpi_portrait.png', srcDarkMode: 'splash/android_xxhdpi_portrait-night.png'}, // (960x1600)
|
||||
'android_xxhdpi_landscape': 'splash/android_xxhdpi_landscape.png', // (1600x960)
|
||||
'android_xxxhdpi_portrait': 'splash/android_xxxhdpi_portrait.png', // (1280x1920)
|
||||
'android_xxxhdpi_landscape': 'splash/android_xxxhdpi_landscape.png', // (1920x1280)
|
||||
});
|
||||
|
||||
// Set PhoneGap/Cordova preferences.
|
||||
@@ -84,4 +114,4 @@ App.accessRule('https://example.com', { type: 'navigation' });
|
||||
{% apibox "App.appendToConfig" %}
|
||||
{% apibox "App.addResourceFile" %}
|
||||
|
||||
> Note: The resource file is copied in two steps : from the **src** of your meteor project to the root of the cordova project, then to the **target**
|
||||
> Note: The resource file is copied in two steps : from the **src** of your meteor project to the root of the cordova project, then to the **target**
|
||||
|
||||
@@ -313,6 +313,8 @@ methods are available:
|
||||
uses the `hot-module-replacement` package. There are rare situations where `hmrAvailable`
|
||||
returns true, but when more information is available later in the build process Meteor
|
||||
decides the file can not be updated with HMR.
|
||||
- `readAndWatchFileWithHash` - Accepts an absolute path, and returns { contents, hash }
|
||||
Makes sure Meteor watches the file so any changes to it will trigger a rebuild
|
||||
|
||||
Meteor implements a couple of compilers as Core packages, good examples would be
|
||||
the
|
||||
@@ -385,9 +387,11 @@ unnecessary work and then we minify the files in production mode.
|
||||
|
||||
Besides the common input files' methods, these methods are available:
|
||||
- `getPathInBundle` - returns a path of the processed file in the bundle.
|
||||
- `getSourcePath` - returns absolute path of the input file if available, or null.
|
||||
- `getSourceMap` - returns the source-map for the processed file if there is such.
|
||||
- `addJavaScript` - same as compilers
|
||||
- `addStylesheet` - same as compilers
|
||||
- `readAndWatchFileWithHash` - only available for css minifiers. Same as compilers.
|
||||
|
||||
Right now, Meteor Core ships with the `standard-minifiers` package that can be
|
||||
replaced with a custom one. The
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Meteor Changelog
|
||||
title: Changelog
|
||||
---
|
||||
|
||||
{%- changelog '../History.md' %}
|
||||
{%- changelog 'history.md' %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Meteor API Docs
|
||||
title: Docs
|
||||
---
|
||||
|
||||
<!-- XXX: note that this content is somewhat duplicated on the guide, and should be updated in parallel -->
|
||||
@@ -34,4 +34,4 @@ Meteor is a full-stack JavaScript platform for developing modern web and mobile
|
||||
|
||||
{% oldRedirects %}
|
||||
|
||||
<!-- hidden comment to trigger a change 2 -->
|
||||
<!-- hidden comment to trigger a change -->
|
||||
|
||||
@@ -7,7 +7,7 @@ Apple M1 is natively supported from Meteor 2.5.1 onward (for older versions, you
|
||||
<h2 id="prereqs">Prerequisites and useful information</h2>
|
||||
|
||||
- If you are on a Mac M1 (Arm64 version) you need to have Rosetta 2 installed, as Meteor uses it for running MongoDB. Check how to install it [here](https://osxdaily.com/2020/12/04/how-install-rosetta-2-apple-silicon-mac/)
|
||||
- Meteor requires Node.js version >= 10 and <= 14 installed for running the npm installer (tip: you can use [nvm](https://github.com/nvm-sh/nvm) for managing node versions).
|
||||
- Meteor works with Node.js version >= 10 and <= 14, for Windows you need to have Node.js installed for running the npm installer (tip: you can use [nvm](https://github.com/nvm-sh/nvm) for managing node versions).
|
||||
- Meteor supports Windows 7/Windows Server 2008 R2 and up.
|
||||
- Disabling antivirus (Windows Defender, etc.) will improve performance.
|
||||
- For compatibility, Linux binaries are built with CentOS 6.4 i386/amd64.
|
||||
@@ -16,7 +16,15 @@ Apple M1 is natively supported from Meteor 2.5.1 onward (for older versions, you
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
|
||||
Install the latest official Meteor release from your terminal:
|
||||
Install the latest official Meteor release from your terminal running one of the commands below.
|
||||
|
||||
For Linux and OS X:
|
||||
|
||||
```bash
|
||||
curl https://install.meteor.com/ | sh
|
||||
```
|
||||
|
||||
For Windows (Node.js is required):
|
||||
|
||||
```bash
|
||||
npm install -g meteor
|
||||
@@ -38,6 +46,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):
|
||||
@@ -48,16 +66,6 @@ arch -x86_64 npm install -g meteor
|
||||
|
||||
or select Terminal in the Applications folder, press CMD(⌘)+I and check the "Open using Rosetta" option.
|
||||
|
||||
<h2 id="legacy-install">Alternative Installation Method</h2>
|
||||
|
||||
For Linux and OS X, we still provide an alternative installation method which uses a bash script and doesn't depend on Node.js.
|
||||
|
||||
```bash
|
||||
curl https://install.meteor.com/ | sh
|
||||
```
|
||||
|
||||
We recommend everybody to use the npm installer but we are still going to maintain this script as well.
|
||||
|
||||
<h2 id="meteor-docker">Run Meteor inside Docker</h2>
|
||||
|
||||
You can also use a Docker container for running Meteor inside your CI, or even in your local development toolchain.
|
||||
|
||||
225
docs/source/packages/accounts-2fa.md
Normal file
225
docs/source/packages/accounts-2fa.md
Normal file
@@ -0,0 +1,225 @@
|
||||
---
|
||||
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.
|
||||
|
||||
To provide codes that are exactly compatible with all other Authenticator apps and services that implements TOTP, 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)).
|
||||
|
||||
> 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, on success, with a QR code in SVG format, a QR secret, and the URI that can be used to activate the 2FA in an authenticator app,
|
||||
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, result) => {
|
||||
if (err) {console.error("...", err);return;}
|
||||
const { svg, secret, uri } = result;
|
||||
/*
|
||||
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>
|
||||
```
|
||||
|
||||
This method can fail throwing the following error:
|
||||
* "The 2FA is activated. You need to disable the 2FA first before trying to generate a new activation code [2fa-activated]" if trying to generate an activation when the user already have 2FA enabled.
|
||||
|
||||
|
||||
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: "***",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To verify whether or not a user has 2FA enabled, you can call the function `Accounts.has2faEnabled`:
|
||||
|
||||
{% apibox "Accounts.has2faEnabled" "module":"accounts-base" %}
|
||||
|
||||
This function must be called when the user is logged in.
|
||||
|
||||
<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.
|
||||
|
||||
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>
|
||||
|
||||
When calling the function `Meteor.loginWithPassword`, if the 2FA is enabled for the user, an error will be returned to the callback, so you can redirect the user to a place where they can provide a code.
|
||||
|
||||
As an example:
|
||||
|
||||
```js
|
||||
<button
|
||||
onClick={() => {
|
||||
Meteor.loginWithPassword(username, password, error => {
|
||||
if (error) {
|
||||
if (error.error === 'no-2fa-code') {
|
||||
// send user to a page or show a component
|
||||
// where they can provide a 2FA code
|
||||
setShouldAskCode(true);
|
||||
return;
|
||||
}
|
||||
console.error("Error trying to log in (user without 2fa)", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}>
|
||||
Login
|
||||
</button>
|
||||
```
|
||||
|
||||
If the 2FA is not enabled, the user will be logged in normally.
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
This method can fail throwing one of the following errors:
|
||||
* "2FA code must be informed [no-2fa-code]" if a 2FA code was not provided.
|
||||
* "Invalid 2FA code [invalid-2fa-code]" if the provided 2FA code is invalid.
|
||||
|
||||
<h3 id="working-with-accounts-passwordless">Working with accounts-passwordless</h3>
|
||||
|
||||
Following the same logic from the previous package, if the 2FA is enabled, an error will be returned to the callback of the function [`Meteor.passwordlessLoginWithToken`](https://docs.meteor.com/packages/accounts-passwordless.html#Meteor-passwordlessLoginWithToken), then you can redirect the user to a place where they can provide a code.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```js
|
||||
<button
|
||||
onClick={() => {
|
||||
// logging in just with token
|
||||
Meteor.passwordlessLoginWithToken(
|
||||
email,
|
||||
token,
|
||||
error => {
|
||||
if (error) {
|
||||
if (error.error === 'no-2fa-code') {
|
||||
// send user to a page or show a component
|
||||
// where they can provide a 2FA code
|
||||
setShouldAskCode(true);
|
||||
return;
|
||||
}
|
||||
console.error('Error verifying token', error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Validate token
|
||||
</button>;
|
||||
```
|
||||
|
||||
Now you can call the function `Meteor.passwordlessLoginWithTokenAnd2faCode` that will allow you to provide a selector, token, and 2FA code:
|
||||
|
||||
{% apibox "Meteor.passwordlessLoginWithTokenAnd2faCode" %}
|
||||
|
||||
This method can fail throwing one of the following errors:
|
||||
* "2FA code must be informed [no-2fa-code]" if a 2FA code was not provided.
|
||||
* "Invalid 2FA code [invalid-2fa-code]" if the provided 2FA code is invalid.
|
||||
|
||||
<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._check2faEnabled` exists, and if yes, you call it providing the user object 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, and the login validation succeeds, 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 `Accounts._isTokenValid` returns false, throw an error.
|
||||
|
||||
Here it's an example:
|
||||
|
||||
```js
|
||||
const result = validateLogin();
|
||||
if (
|
||||
!result.error &&
|
||||
Accounts._check2faEnabled?.(user)
|
||||
) {
|
||||
if (!code) {
|
||||
Accounts._handleError('2FA code must be informed.');
|
||||
}
|
||||
if (
|
||||
!Accounts._isTokenValid(user.services.twoFactorAuthentication.secret, code)
|
||||
) {
|
||||
Accounts._handleError('Invalid 2FA code.');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
```
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -13,7 +13,7 @@ To add this package to an existing app, run the following command from
|
||||
your app directory:
|
||||
|
||||
```bash
|
||||
meteor add ecmascript
|
||||
meteor add fetch
|
||||
```
|
||||
|
||||
To add the `fetch` package to an existing package, include the
|
||||
@@ -59,4 +59,4 @@ async function postData (url, data) {
|
||||
const postDataCall = Meteor.wrapAsync(postData);
|
||||
const results = postDataCall('https://www.example.org/statsSubmission', { totalUsers: 55 }));
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -62,7 +62,8 @@ architecture of the pending HTTP response (e.g. "web.browser").
|
||||
Here is a basic example of `onPageLoad` usage on the server:
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
import
|
||||
from "react";
|
||||
import { renderToString } from "react-dom/server";
|
||||
import { onPageLoad } from "meteor/server-render";
|
||||
|
||||
@@ -160,11 +161,7 @@ In some cases you want to customize meta tags or something else in your response
|
||||
You can extract information from the request using the `sink` object.
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
import { onPageLoad } from "meteor/server-render";
|
||||
import { renderToNodeStream } from "react-dom/server";
|
||||
import { ServerStyleSheet } from "styled-components"
|
||||
import App from "/imports/Server";
|
||||
|
||||
const getBaseUrlFromHeaders = headers => {
|
||||
const protocol = headers['x-forwarded-proto'];
|
||||
|
||||
52
docs/source/packages/standard-minifier-css.md
Normal file
52
docs/source/packages/standard-minifier-css.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: standard-minifier-css
|
||||
description: Documentation of Meteor's `standard-minifier-css` package.
|
||||
---
|
||||
|
||||
This package is the default css minifier in Meteor apps. In addition to minifying the css code in production builds, it also runs any PostCSS plugins configured for the app.
|
||||
|
||||
## 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/).
|
||||
|
||||
After making changes to the PostCSS Config, `meteor` must be restarted for it to use the new config.
|
||||
|
||||
### 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.
|
||||
79
docs/source/roadmap.md
Normal file
79
docs/source/roadmap.md
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Roadmap
|
||||
description: Describes the high-level features and actions for the Meteor project in the near-to-medium term future.
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
**Up to date as of Jan 26, 2022**
|
||||
|
||||
This document describes the high-level features and actions for the Meteor project in the near-to-medium term future. The description of many items include sentences and ideas from Meteor community members.
|
||||
|
||||
As with any roadmap, this is a living document that will evolve as priorities and dependencies shift.
|
||||
|
||||
Contributors are encouraged to focus their efforts on work that aligns with the roadmap then we can work together in these areas.
|
||||
|
||||
If you have new feature requests or ideas you should open a new [discussion](https://github.com/meteor/meteor/discussions/new).
|
||||
|
||||
## Core team
|
||||
|
||||
The items in this section are the core team's priorities.
|
||||
|
||||
### Next minor releases
|
||||
|
||||
- New Core Packages
|
||||
- Accounts 2FA package; [PR](https://github.com/meteor/meteor/pull/11818)
|
||||
- Better file upload support;
|
||||
- TailwindCSS 3.0 JIT Support; [Discussion](https://github.com/meteor/meteor/discussions/11804)
|
||||
- Tree-shaking; [PR](https://github.com/meteor/meteor/pull/11164)
|
||||
- Guide review;
|
||||
- Provide new async APIs where Fibers is required;
|
||||
- Mongo package with Async API; [PR](https://github.com/meteor/meteor/pull/11605)
|
||||
- Finish Blaze 2.6;
|
||||
- ES Modules Support;
|
||||
- node: Protocol Import Support;
|
||||
- Explore new ways to expose Meteor type definitions;
|
||||
|
||||
### Next major releases
|
||||
|
||||
- Support building mobile apps using CapacitorJS;
|
||||
- Explore bringing Redis-oplog to core;
|
||||
- Support Top-level await;
|
||||
- Remove Fibers dependency from Meteor Public APIs;
|
||||
- Make Fibers optional on runtime, or remove it entirely;
|
||||
- Improve Dev Tools
|
||||
- Better way to define Meteor public API types;
|
||||
- Better support for mainstream IDEs;
|
||||
- Launch new sections for [Meteor University](https://university.meteor.com/);
|
||||
- ARM Support;
|
||||
- HTTP/3 Support;
|
||||
- MongoDB Change Streams Support;
|
||||
- Explore Flutter as a front-end for Meteor apps;
|
||||
|
||||
## Community
|
||||
|
||||
The items in this section are not the priorities of the core team but the core team can support community members working on it.
|
||||
|
||||
- Finish Vue3 integration; [Basic usage](https://github.com/meteor-vue/meteor-vue3/tree/main/packages/vue3#vuejsvue3)
|
||||
- Svelte real app examples;
|
||||
- SolidJS real app examples;
|
||||
- React Native real app examples;
|
||||
|
||||
## Previous releases
|
||||
- Support to MongoDB 5.0; [Migration Guide](https://guide.meteor.com/2.6-migration.html)
|
||||
- Add missing binaries to Fibers fork; [Issue](https://github.com/meteor/meteor/issues/11791)
|
||||
- [Meteor University launch](https://university.meteor.com/)
|
||||
- [2FA OTP support in Meteor Accounts](https://forums.meteor.com/t/2fa-otp-support-in-meteor-accounts-meteor-cloud/57248)
|
||||
- [Meteor + SolidJS demo](https://github.com/edemaine/solid-meteor-demo)
|
||||
- TypeScript update to v4.4.1
|
||||
- Mac M1 Support
|
||||
- HMR now works on all architectures and legacy browsers
|
||||
- New core package: accounts-passwordless
|
||||
- New Meteor NPM installer
|
||||
- Apollo skeleton upgraded to Apollo server v3
|
||||
- [Node.js update](https://docs.meteor.com/changelog.html#v2320210624) to v14 from 12.22.1
|
||||
- Cordova update to version 10
|
||||
- New Skeleton for Svelte
|
||||
- Repository with [Meteor Examples](https://github.com/meteor/examples)
|
||||
|
||||
For more completed items, refer to our [changelog](https://docs.meteor.com/changelog.html).
|
||||
@@ -5,6 +5,8 @@ edit_branch: 'devel'
|
||||
edit_path: 'guide'
|
||||
content_root: 'content'
|
||||
versions:
|
||||
- '2.7'
|
||||
- '2.6'
|
||||
- '2.5'
|
||||
- '2.4'
|
||||
- '2.3'
|
||||
@@ -34,7 +36,7 @@ sidebar_categories:
|
||||
- index
|
||||
- code-style
|
||||
- structure
|
||||
- 2.4-migration
|
||||
- 2.7-migration
|
||||
Data:
|
||||
- collections
|
||||
- data-loading
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
"test": "npm run clean; npm run build",
|
||||
"start": "npm run build && chexo meteor-hexo-config -- server"
|
||||
}
|
||||
}
|
||||
}
|
||||
39
guide/source/2.5-migration.md
Normal file
39
guide/source/2.5-migration.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Migrating to Meteor 2.5
|
||||
description: How to migrate your application to Meteor 2.5.
|
||||
---
|
||||
|
||||
Most of the new features in Meteor 2.5 are either applied directly behind the scenes (in a backwards compatible manner) or are opt-in. 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 implement to have easier time in the future.
|
||||
|
||||
<h3 id="cordova-android-10">Cordova Android 10</h3>
|
||||
|
||||
Cordova Android v10 now enables AndroidX. If you use any cordova-plugin that depends or uses any old support library, you need to include the cordova-plugin-androidx-adapter cordova-plugin, otherwise you will get build errors.
|
||||
|
||||
<h3 id="login-with-token">Login with token</h3>
|
||||
|
||||
`Meteor.loginWithToken` from the new package `accounts-passwordless` was conflicting with another method with the same name on `accounts-base` so we had to rename the method of `accounts-passwordless` package to `Meteor.passwordlessLoginWithToken`, this change was released in Meteor 2.5.1.
|
||||
|
||||
<h2 id="older-versions">Migrating from a version older than 2.4?</h2>
|
||||
|
||||
If you're migrating from a version of Meteor older than Meteor 2.4, there may be important considerations not listed in this guide (which specifically covers 2.3 to 2.4). Please review the older migration guides for details:
|
||||
|
||||
* [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)
|
||||
136
guide/source/2.6-migration.md
Normal file
136
guide/source/2.6-migration.md
Normal file
@@ -0,0 +1,136 @@
|
||||
---
|
||||
title: Migrating to Meteor 2.6
|
||||
description: How to migrate your application to Meteor 2.6.
|
||||
---
|
||||
|
||||
Most of the new features in Meteor 2.6 are either applied directly behind the scenes (in a backwards compatible manner) or are opt-in. 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 implement to have easier time in the future.
|
||||
|
||||
<h3 id="launch-screens-ios">Cordova - Launch Screens for iOS</h3>
|
||||
|
||||
You are now able to use dark theme specific splash screens for both iOS and Android by passing an object `{src: 'light-image-src-here.png', srcDarkMode: 'dark-mode-src-here.png'}` to the corresponding key in `App.launchScreens`
|
||||
|
||||
Legacy launch screens keys for iOS on `App.launchScreens` are now deprecated in favor of new storyboard compliant keys [PR #11797](https://github.com/meteor/meteor/pull/11797). This will drop the following keys we have: `['iphone5','iphone6','iphone6p_portrait','iphone6p_landscape','iphoneX_portrait','iphoneX_landscape','ipad_portrait_2x','ipad_landscape_2x','iphone','iphone_2x','ipad_portrait','ipad_landscape']`
|
||||
|
||||
To migrate replace the deprecated keys `['iphone5','iphone6','iphone6p_portrait','iphone6p_landscape','iphoneX_portrait','iphoneX_landscape','ipad_portrait_2x','ipad_landscape_2x','iphone','iphone_2x','ipad_portrait','ipad_landscape']` with the
|
||||
corresponding new key: `['ios_universal','ios_universal_3x','Default@2x~universal~comany','Default@2x~universal~comcom','Default@3x~universal~anycom','Default@3x~universal~comany','Default@2x~iphone~anyany','Default@2x~iphone~comany','Default@2x~iphone~comcom','Default@3x~iphone~anyany','Default@3x~iphone~anycom','Default@3x~iphone~comany','Default@2x~ipad~anyany','Default@2x~ipad~comany']`
|
||||
and adapt necessary splash images to the new dimensions asked by Apple. You can get more info [here](https://docs.meteor.com/api/mobile-config.html#App-launchScreens).
|
||||
|
||||
<h3 id="mongo-5">MongoDB 5.0</h3>
|
||||
|
||||
#### Introduction
|
||||
Meteor before 2.6 was supporting MongoDB Server 4.x, starting from this version we've upgraded to MongoDB Node.js driver from version 3.6 to 4.3.1 which supports MongoDB Server 5.x.
|
||||
|
||||
This change was necessary at the time of writing this guide (January 2022) as MongoDB Atlas is going to migrate automatically all the clusters in the plans Atlas M0 (Free Cluster), M2, and M5 to MongoDB 5.0 in February 2022, but this change would be necessary anyway as this is now the latest version of MongoDB Server. The migration in the M0, M2 and M5 is just a sign from MongoDB that they believe MongoDB 5.0 should be the version used by everybody as soon as possible.
|
||||
|
||||
If you are running on MongoDB Atlas and in one of these plans you have to run Meteor 2.6 in order to connect and interact with your MongoDB properly as your MongoDB is going to be upgraded to 5.0 in February. If you are not running at these plans, you can continue to use your MongoDB at previous versions and you can use previous versions of Meteor still without any problems.
|
||||
|
||||
An important note is that we have migrated everything supported by Meteor to be compatible with MongoDB 5.x and also MongoDB Node.js Driver 4.x but this doesn't include, as you should expect, what you do in your code or package using `rawCollection`. `rawCollection` is a way for Meteor to provide you the freedom to interact with MongoDB driver but that also comes with the responsibility to keep your code up-to-date with the version of the driver used by Meteor.
|
||||
|
||||
That said, we encourage everybody to run the latest version of Meteor as soon as possible as you can benefit from a new MongoDB driver and also other features that we are always adding to Meteor.
|
||||
|
||||
This version of Meteor is also compatible with previous version of MongoDB server, so you can continue using the latest Meteor without any issues even if you are not running MongoDB 5.x yet. You can check [here](https://docs.mongodb.com/drivers/node/current/compatibility/) which versions of MongoDB server the Node.js driver in the version 4.3.0 supports and as a consequence these are the versions of MongoDB server supported by Meteor 2.6 as well. In short, Meteor 2.6 supports these versions of MongoDB server: 5.1, 5.0, 4.4, 4.2, 4.0, 3.6.
|
||||
|
||||
#### Embedded MongoDB
|
||||
|
||||
If you are using Embedded MongoDB in your local environment you should run `meteor reset` in order to have your database working properly after this upgrade. `meteor reset` is going to remove all the data in your local database.
|
||||
|
||||
#### rawCollection()
|
||||
|
||||
If you depend on any method inside the rawCollection() object, you have to review every call with the new driver API [here](https://mongodb.github.io/node-mongodb-native/4.3/). Also make sure you check all the changes made to the driver [here](https://docs.mongodb.com/drivers/node/current/whats-new/) and [here](https://github.com/mongodb/node-mongodb-native/blob/4.0/docs/CHANGES_4.0.0.md).
|
||||
|
||||
You can check an example applied to the "aggregate" function, which had changes to its API. The collection.rawCollection().aggregate() function doesn't expect a callback any more like in older versions, and aggregate().toArray() now returns a promise.
|
||||
For this specific case, we have written the fix in this [PR](https://github.com/sakulstra/meteor-aggregate/pull/8).
|
||||
|
||||
If you are a user looking for errors that are showing in a custom package, please open an issue in the package owner repository so the maintainer can make the due changes.
|
||||
|
||||
#### Cursor.count()
|
||||
|
||||
`applySkipLimit` option for count() on find cursors is no longer supported. By default, this option will always be true. So, for example, let's say you have a collection with 50 documents and execute a `find` with a limit of 25:
|
||||
|
||||
```js
|
||||
const cursor = collection.find({}, { limit: 25 });
|
||||
```
|
||||
|
||||
When you call `cursor.fetch()`, the result will be 25 documents, and `cursor.count()` will be 25. Whereas, in the previous version, `cursor.count()` would result in 50, in this case, and you would need to provide the option `applySkipLimit` to get the result 25.
|
||||
|
||||
Now, you'll need to create a new cursor, but this time not providing a limit, in order to get the number of all documents in your collection:
|
||||
|
||||
```js
|
||||
const cursorWithLimit = collection.find({}, { limit: 25 });
|
||||
const cursorWithNoLimit = collection.find({});
|
||||
// cursorWithLimit.fetch() => returns 25 documents
|
||||
// cursorWithNoLimit.count() => returns 50
|
||||
```
|
||||
|
||||
Remember that a `find` is a wrapper for the query, so creating two or more cursors in a row is totally fine and not slower at all.
|
||||
|
||||
#### Changes
|
||||
|
||||
Here is a list of the changes that we have made to Meteor core packages in order to make it compatible with MongoDB Node.js Driver 4.3.x, most of them are not going to affect you but we recommend that you test your application well before upgrading to the latest version of Meteor as we have made many changes on how Meteor interact with MongoDB.
|
||||
- internal result of operations inside Node.js MongoDB driver have changed. If you are depending on rawCollection results (not only the effect inside the DB), please review the expected format as we have done [here](https://github.com/meteor/meteor/blob/155ae639ee590bae66237fc1c29295072ec92aef/packages/mongo/mongo_driver.js#L658)
|
||||
- useUnifiedTopology is not an option anymore, it defaults to true.
|
||||
- native parser is not an option anymore, it defaults to false in the mongo connection.
|
||||
- poolSize not an option anymore, we are using max/minPoolSize for the same behavior on mongo connection.
|
||||
- fields option is deprecated, we are maintaining a translation layer to "projection" field (now prefered) until the next minor version, where we will start showing alerts.
|
||||
- _ensureIndex is now showing a deprecation message
|
||||
- we are maintaining a translation layer for the new oplog format, so if you read or rely on any behavior of it please read our oplog_v2_converter.js code
|
||||
- update/insert/remove behavior is maintained in the Meteor way, documented in our docs, but we are now using replaceOne/updateOne/updateMany internally. This is subject to changes in the API rewrite of MongoDB without Fibers AND if you are using rawCollection directly you have to review your methods otherwise you will see deprecation messages if you are still using the old mongodb style directly.
|
||||
- waitForStepDownOnNonCommandShutdown=false is not needed anymore when spawning the mongodb process
|
||||
- _synchronousCursor._dbCursor.operation is not an option anymore in the raw cursor from nodejs mongodb driver. If you want to access the options, use _synchronousCursor._dbCursor.(GETTERS) - for example, _synchronousCursor._dbCursor.readPreference.
|
||||
- the default write preference for replica sets on mongo v5 is w:majority
|
||||
- If you are using MongoDB inside a Docker container in your dev environment, you might need to append directConnection=true in your mongouri to avoid the new mongo driver Service Discovery feature
|
||||
|
||||
It's worth mentioning that if you are using the built-in MongoDB that Meteor provides to run your app locally, you need to perform a `meteor reset` on your app to be able to use the version 2.6.
|
||||
|
||||
Below we describe a few common cases in this migration:
|
||||
|
||||
#### 1) Same version of MongoDB server
|
||||
|
||||
If you are not changing your MongoDB server version you don't need to change anything in your code, even if you are using `rawCollection` results, but as we did many changes on how Meteor interact with MongoDB in order to be compatible with the new driver we recommend that you test your application carefully before releasing to production with this Meteor version.
|
||||
|
||||
We've made many tests in real applications and also in our automatic tests suite, we believe we've fixed all the issues that we found along the way but Meteor interaction with MongoDB is so broad and open that maybe you have different use cases that could lead to different issues.
|
||||
|
||||
Again, we are not aware of any issues that were introduced by these changes, but it's important that you check your app behavior, especially if you have places where you believe you are not using MongoDB in a traditional way.
|
||||
|
||||
#### 2) Migrating from MongoDB 4.x to MongoDB 5.x
|
||||
|
||||
As we have made many changes to Meteor core packages in this version we recommend the following steps to migrate:
|
||||
- Upgrade your app to use Meteor 2.6 (meteor update --release 2.6) in a branch;
|
||||
- Create a staging environment with MongoDB 5.x and your app environment using the branch created in the previous step;
|
||||
- If you are using MongoDB Atlas, in MongoDB Atlas we were not able to migrate to a free MongoDB 5.x instance, so we had to migrate to a paid cluster in order to test the app properly, maybe this will change after February 2022;
|
||||
- Set up your staging database with MongoDB 5.x and restore your production data there, or populate this database in a way that you can reproduce the same cases as if you were in production;
|
||||
- Run your app pointing your MONGO_URL to this new database, that is running MongoDB 5.x;
|
||||
- Run your end-to-end tests in this environment. If you don't have a robust end-to-end test we recommend that you test your app manually to make sure everything is working properly.
|
||||
- Once you have a stable end-to-end test (or manual test), you can consider that you are ready to run using MongoDB 5.x, so you can consider it as any other database version migration.
|
||||
|
||||
We are not aware of any issues that were introduced by the necessary changes to support MongoDB, but it's important that you check your app behavior, especially if you have places where you believe you are not using MongoDB in a traditional way.
|
||||
|
||||
For example, the MongoDB Oplog suffered a lot of changes, and we had to create a conversor to keep our oplog tail understanding the changes coming from the oplog, so if you have complex features and queries that depend on oplog (Meteor real-time diff system), you should review if your app is working properly especially in this part.
|
||||
|
||||
As MongoDB also removed a few deprecated methods that were used by Meteor we recommend testing all important operations of your application.
|
||||
|
||||
<h2 id="older-versions">Migrating from a version older than 2.5?</h2>
|
||||
|
||||
If you're migrating from a version of Meteor older than Meteor 2.5, there may be important considerations not listed in this guide (which specifically covers 2.4 to 2.5). Please review the older migration guides for details:
|
||||
|
||||
* [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)
|
||||
73
guide/source/2.7-migration.md
Normal file
73
guide/source/2.7-migration.md
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Migrating to Meteor 2.7
|
||||
description: How to migrate your application to Meteor 2.7.
|
||||
---
|
||||
|
||||
Meteor `2.7` introduce the new `accounts-2fa` package, support for TailwindCSS 3.x, and built-in support for PostCSS in `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">Update meteor-node-stubs</h3>
|
||||
|
||||
As we added support for [node:](https://nodejs.org/api/esm.html#node-imports) imports, you need to
|
||||
update `meteor-node-stubs` to version `1.2.1`:
|
||||
|
||||
```bash
|
||||
meteor npm install meteor-node-stubs@1.2.1
|
||||
```
|
||||
|
||||
<h3 id="new-css-minifier">Support for PostCSS</h3>
|
||||
|
||||
Starting from this version of Meteor (and 1.8.0 of `standard-minifier-css`), Meteor will run PostCSS plugins if you have them configured. If you are using `juliancwirko:postcss` as your css minifier, it is recommended to migrate to using `standard-minifier-css`. For most apps, this will only requiring switching which minifier the app uses:
|
||||
|
||||
```bash
|
||||
meteor remove juliancwirko:postcss
|
||||
meteor add standard-minifier-css
|
||||
```
|
||||
|
||||
There are two differences with `juliancwirko:postcss`:
|
||||
|
||||
- The `excludedPackages` PostCSS option was renamed to `excludedMeteorPackages`
|
||||
- Files with the `.import.css` extension are not treated specially
|
||||
|
||||
> Note: In beta.1 of Meteor 2.7 we had added a new core package `minifier-css-postcss` but later decided to unify everything inside `standard-minifier-css`. So you shouldn't use `minifier-css-postcss`.
|
||||
|
||||
<h3 id="tailwind-css">TailwindCSS 3.x</h3>
|
||||
|
||||
Improvements in Meteor 2.7 enables minifiers to support TailwindCSS 3.x. These minifiers have been updated and tested with TailwindCSS 3:
|
||||
|
||||
- `juliancwirko:postcss`, starting with version `2.1.0`
|
||||
- `standard-minifier-css`
|
||||
|
||||
If updating from an older version of TailwindCSS to version 3, 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.
|
||||
|
||||
<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.7?</h2>
|
||||
|
||||
If you're migrating from a version of Meteor older than Meteor 2.7, there may be important considerations not listed in this guide. 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)
|
||||
@@ -24,7 +24,7 @@ By default Meteor will build certain files as controlled by your application [fi
|
||||
|
||||
<h3 id="concatenate-and-minify">Combines and minifies code</h3>
|
||||
|
||||
Another important feature of the Meteor build tool is that it automatically concatenates your application asset files, and in production minifies these bundles. This lets you add all of the comments and whitespace you want to your source code and split your code into as many files as necessary, all without worrying about app performance and load times. This is enabled by the [`standard-minifier-js`](https://atmospherejs.com/meteor/standard-minifiers-js) and [`standard-minifier-css`](https://atmospherejs.com/meteor/standard-minifiers-css) packages, which are included in all Meteor apps by default. If you need different minification behavior, you can replace these packages. See adding [PostCSS to your build process](#postcss) as an example.
|
||||
Another important feature of the Meteor build tool is that it automatically concatenates your application asset files, and in production minifies these bundles. This lets you add all of the comments and whitespace you want to your source code and split your code into as many files as necessary, all without worrying about app performance and load times. This is enabled by the [`standard-minifier-js`](https://atmospherejs.com/meteor/standard-minifiers-js) and [`standard-minifier-css`](https://atmospherejs.com/meteor/standard-minifiers-css) packages, which are included in all Meteor apps by default. If you need different minification behavior, you can replace these packages (see [zodern:standard-minifier-js](https://atmospherejs.com/zodern/standard-minifier-js) as an example).
|
||||
|
||||
<h3 id="dev-vs-prod">Development vs. production</h3>
|
||||
|
||||
@@ -240,42 +240,7 @@ In addition to CSS pre-processors like Sass, Less, and Stylus, there is now an e
|
||||
|
||||
The most popular CSS post-processor right now is [PostCSS](https://github.com/postcss/postcss), which supports a variety of plugins. [Autoprefixer](https://github.com/postcss/autoprefixer) is perhaps the most useful plugin, since it enables you to stop worrying about browser prefixes and compatibility and write standards-compliant CSS. No more copying 5 different statements every time you want a CSS gradient - you can write a standard gradient without any prefixes and Autoprefixer handles it for you.
|
||||
|
||||
Currently, Meteor doesn't have a separate build step for post-processing CSS, so the only way to integrate it is to build it into the minifier. Thankfully, there is a community package that has integrated PostCSS with plugin support into a replacement for Meteor's standard minification package.
|
||||
|
||||
<h3 id="juliancwirko-postcss">juliancwirko:postcss</h3>
|
||||
|
||||
>Note: This package is no longer actively maintained, therefore compatibility with newer versions of Meteor is not guaranteed. If you encouter problems with this, please let us know by [opening an issue on the Guide](https://github.com/meteor/guide/issues).
|
||||
|
||||
Use the package [juliancwirko:postcss](https://atmospherejs.com/juliancwirko/postcss) to your app to enable PostCSS for your Meteor app. To do so, we remove the standard CSS minifier and replace it with the postcss package:
|
||||
|
||||
```
|
||||
meteor remove standard-minifier-css
|
||||
meteor add juliancwirko:postcss
|
||||
```
|
||||
|
||||
As well as installing the postcss NPM package:
|
||||
|
||||
```
|
||||
meteor npm install postcss@^6.0.22 --save-dev
|
||||
meteor npm install postcss-load-config@^1.2.0 --save-dev
|
||||
```
|
||||
|
||||
Then we can install any npm CSS processing packages that we'd like to use and reference them from a `postcss` section of our `package.json`. In the Todos example app, we use `autoprefixer` package to increase browser support:
|
||||
|
||||
```
|
||||
{
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.3.1"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {"browsers": ["last 2 versions"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After doing the above, you'll need to ensure you `npm install` and restart the `meteor` process running your app to make sure the PostCSS system has had a chance to set itself up.
|
||||
Meteor automatically runs PostCSS for you once you've configured it. Learn more about enabling it in the docs for [standard-minifier-css](https://docs.meteor.com/packages/standard-minifier-css.html).
|
||||
|
||||
<h2 id="hot-module-replacement">Hot Module Replacement</h2>
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ In order to build and run mobile apps, you will need to install some prerequisit
|
||||
|
||||
<h3 id="installing-prerequisites-ios">iOS</h3>
|
||||
|
||||
In order to build and run iOS apps, you will need a Mac with [Apple Xcode](https://developer.apple.com/xcode/) developer tools installed. We recommend installing the latest version, but you should also check the [Meteor history](https://github.com/meteor/meteor/blob/devel/History.md) for any specific version dependencies. NOTE: To build with Xcode 10.2+, your webapp package must be v1.7.4 or higher.
|
||||
In order to build and run iOS apps, you will need a Mac with [Apple Xcode](https://developer.apple.com/xcode/) developer tools installed. We recommend installing the latest version, but you should also check the [Meteor history](https://docs.meteor.com/changelog.html) for any specific version dependencies. NOTE: To build with Xcode 10.2+, your webapp package must be v1.7.4 or higher.
|
||||
|
||||
<h4>Installing Xcode from the App Store</h4>
|
||||
|
||||
@@ -91,12 +91,14 @@ A shortcut is to run `sudo xcodebuild -license accept` from the command line. (Y
|
||||
|
||||
<h4>Enabling Xcode command line tools</h4>
|
||||
|
||||
After installing Xcode from the Mac App Store, it is still necesssary to enable those tools in the terminal environment. This can be accompilshed by running the following from the command prompt:
|
||||
After installing Xcode from the Mac App Store, it is still necessary to enable those tools in the terminal environment. This can be accomplished by running the following from the command prompt:
|
||||
```
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
```
|
||||
<h3 id="installing-prerequisites-android">Android</h3>
|
||||
|
||||
{% youtube vhlNO0dVvjE %}
|
||||
|
||||
In order to build and run Android apps, you will need to:
|
||||
|
||||
- Install a Java Development Kit (JDK)
|
||||
@@ -123,15 +125,15 @@ In order to build and run Android apps, you will need to:
|
||||
|
||||
<h4>Installing Android Studio</h4>
|
||||
|
||||
The easiest way to get a working Android development environment is by installing [Android Studio](http://developer.android.com/sdk/index.html), which offers a setup wizard on first launch that installs the Android SDK for you, and downloads a default set of tools, platforms, and other components that you will need to start developing.
|
||||
The easiest way to get a working Android development environment is by installing [Android Studio](https://developer.android.com/studio), which offers a setup wizard on first launch that installs the Android SDK for you, and downloads a default set of tools, platforms, and other components that you will need to start developing.
|
||||
|
||||
Please refer to [the Android Studio installation instructions](http://developer.android.com/sdk/installing/index.html?pkg=studio) for more details on the exact steps to follow.
|
||||
Please refer to [the Android Studio installation instructions](https://developer.android.com/studio/install) for more details on the exact steps to follow.
|
||||
|
||||
> There is no need to use Android Studio if you prefer a stand-alone install. Just make sure you install the most recent versions of the [Android SDK Tools](http://developer.android.com/sdk/index.html#Other) and download the required [additional packages](http://developer.android.com/sdk/installing/adding-packages.html) yourself using the [Android SDK Manager](http://developer.android.com/tools/help/sdk-manager.html).
|
||||
> There is no need to use Android Studio if you prefer a stand-alone install. Just make sure you install the most recent versions of the [Android Command Line Tools](https://developer.android.com/studio#command-tools).
|
||||
|
||||
Make sure to select the correct version of the [Android Studio SDK Tools](https://developer.android.com/studio/releases/sdk-tools.html):
|
||||
Make sure to select the correct version of the [Android Studio SDK Tools](https://developer.android.com/studio/intro/update):
|
||||
|
||||
* Meteor 1.4.3.1 or later: Android SDK Tools v.25.**2**.x ([mac](https://dl.google.com/android/repository/tools_r25.2.3-macosx.zip), [linux](https://dl.google.com/android/repository/tools_r25.2.3-linux.zip), [windows](https://dl.google.com/android/repository/tools_r25.2.3-windows.zip)) or v.26.0.0 or later
|
||||
* Meteor 1.4.3.1 onward: Android SDK Tools v.25.**2**.x ([mac](https://dl.google.com/android/repository/tools_r25.2.3-macosx.zip), [linux](https://dl.google.com/android/repository/tools_r25.2.3-linux.zip), [windows](https://dl.google.com/android/repository/tools_r25.2.3-windows.zip)) or v.26.0.0 or later
|
||||
* v.25.**3.0** **will not work** due to [extensive changes](https://developer.android.com/studio/releases/sdk-tools.html). See [issue #8464](https://github.com/meteor/meteor/issues/8464) for more information.
|
||||
* Meteor 1.4.2.x or before: Android SDK Tools v.23 ([mac](https://dl.google.com/android/repository/tools_r23.0.1-macosx.zip), [linux](https://dl.google.com/android/repository/tools_r23.0.1-linux.zip), [windows](https://dl.google.com/android/repository/tools_r23.0.1-windows.zip))
|
||||
|
||||
|
||||
@@ -652,8 +652,12 @@ const helpmentOptions = {
|
||||
// connection available.
|
||||
// Run your project with --production flag to simulate script-src hashing
|
||||
if (!usesHttps && Meteor.isDevelopment) {
|
||||
delete opt.contentSecurityPolicy.directives.blockAllMixedContent
|
||||
opt.contentSecurityPolicy.directives.scriptSrc = [self, unsafeEval, unsafeInline]
|
||||
delete helpmentOptions.contentSecurityPolicy.blockAllMixedContent;
|
||||
helpmentOptions.contentSecurityPolicy.directives.scriptSrc = [
|
||||
self,
|
||||
unsafeEval,
|
||||
unsafeInline,
|
||||
];
|
||||
}
|
||||
|
||||
// finally pass the options to helmet to make them apply
|
||||
@@ -694,6 +698,7 @@ This is a collection of points to check about your app that might catch common e
|
||||
1. Secure the data, not the UI - redirecting away from a client-side route does nothing for security, it's a nice UX feature.
|
||||
1. [Don't ever trust user IDs passed from the client.](http://guide.meteor.com/security.html#user-id-client) Use `this.userId` inside Methods and publications.
|
||||
1. Set up secure [HTTP headers](https://guide.meteor.com/security.html#httpheaders) using [Helmet](https://www.npmjs.com/package/helmet), but know that not all browsers support it so it provides an extra layer of security to users with modern browsers.
|
||||
1. At the end of the day, Meteor is a Node.js app so make sure to also follow the [best practises](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html) to ensure maximum security.
|
||||
|
||||
<h2 id="appProtection">App Protection</h2>
|
||||
App Protection on Galaxy Hosting is a feature in our proxy server layer that sits in front of every request to your application. This means that all requests across servers are analyzed and measured against expected limits. This will help protect against DoS and DDoS attacks that aimed to overload servers and make your app unavailable for legitimate requests.
|
||||
|
||||
@@ -36,10 +36,11 @@ The primary way to test your application in Meteor is the `meteor test` command.
|
||||
|
||||
This loads your application in a special "test mode". What this does is:
|
||||
|
||||
1. *Doesn't* eagerly load *any* of our application code as Meteor normally would.
|
||||
2. *Does* eagerly load any file in our application (including in `imports/` folders) that look like `*.test[s].*`, or `*.spec[s].*`
|
||||
3. Sets the `Meteor.isTest` flag to be true.
|
||||
4. Starts up the test driver package ([see below](#driver-packages)).
|
||||
- *Doesn't* eagerly load *any* of our application code as Meteor normally would.
|
||||
- *This is a highly important note as Meteor wouldn't know of any methods/collections/publications unless you import them in your test files.*
|
||||
- *Does* eagerly load any file in our application (including in `imports/` folders) that look like `*.test[s].*`, or `*.spec[s].*`
|
||||
- Sets the `Meteor.isTest` flag to be true.
|
||||
- Starts up the test driver package ([see below](#driver-packages)).
|
||||
|
||||
> The [Meteor build tool](build-tool.html#what-it-does) and the `meteor test` command ignore any files located in any `tests/` directory. This allows you to put tests in this directory that you can run using a test runner outside of Meteor's built-in test tools and still not have those files loaded in your application. See Meteor's [default file load order](structure.html#load-order) rules.
|
||||
|
||||
@@ -71,7 +72,7 @@ There are two main kinds of test driver packages:
|
||||
|
||||
<h3 id="mocha">Recommended: Mocha</h3>
|
||||
|
||||
In this article, we'll use the popular [Mocha](https://mochajs.org) test runner alongside the [Chai](http://chaijs.com) assertion library to test our application. In order to write and run tests in Mocha, we need to add an appropriate test driver package.
|
||||
In this article, we'll use the popular [Mocha](https://mochajs.org) test runner. And you can pair it with any assertion library you want like[Chai](http://chaijs.com) or [expect](https://jestjs.io/docs/expect). In order to write and run tests in Mocha, we need to add an appropriate test driver package.
|
||||
|
||||
There are several options. Choose the ones that makes sense for your app. You may depend on more than one and set up different test commands for different situations.
|
||||
|
||||
@@ -104,9 +105,29 @@ Note that arrow function use with Mocha [is discouraged](http://mochajs.org/#arr
|
||||
|
||||
When your app is run in test mode, it is initialized with a clean test database.
|
||||
|
||||
If you are running a test that relies on using the database, and specifically the content of the database, you'll need to perform some *setup* steps in your test to ensure the database is in the state you expect. There are some tools you can use to do this.
|
||||
If you are running a test that relies on using the database, and specifically the content of the database, you'll need to perform some *setup* steps in your test to ensure the database is in the state you expect.
|
||||
|
||||
To ensure the database is clean, the [`xolvio:cleaner`](https://atmospherejs.com/xolvio/cleaner) package is useful. You can use it to reset the database in a `beforeEach` block:
|
||||
```js
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import expect from 'expect';
|
||||
|
||||
import { Notes } from './notes';
|
||||
|
||||
describe('notes', function () {
|
||||
const noteOne = {
|
||||
_id: 'testNote1',
|
||||
title: 'Groceries',
|
||||
body: 'Milk, Eggs and Oatmeal'
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
Notes.remove({});
|
||||
Notes.insert(noteOne);
|
||||
});
|
||||
...
|
||||
```
|
||||
|
||||
You can also use [`xolvio:cleaner`](https://atmospherejs.com/xolvio/cleaner) which is useful for resetting the entire database if you wish to do so. You can use it to reset the database in a `beforeEach` block:
|
||||
|
||||
```js
|
||||
import { resetDatabase } from 'meteor/xolvio:cleaner';
|
||||
@@ -118,7 +139,18 @@ describe('my module', function () {
|
||||
});
|
||||
```
|
||||
|
||||
This technique will only work on the server. If you need to reset the database from a client test, you can use a method to do so:
|
||||
This technique will only work on the server. If you need to reset the database from a client test, [`xolvio:cleaner`](https://github.com/xolvio/cleaner) provides you with a built-in method called [`xolvio:cleaner/resetDatabase`](https://github.com/xolvio/cleaner/blob/master/cleaner.js#L30):
|
||||
|
||||
```js
|
||||
describe('my module', function (done) {
|
||||
beforeEach(function (done) {
|
||||
// We need to wait until the method call is done before moving on, so we
|
||||
// use Mocha's async mechanism (calling a done callback)
|
||||
Meteor.call('xolvio:cleaner/resetDatabase', done);
|
||||
});
|
||||
});
|
||||
```
|
||||
You can also invoke `resetDatabase` in your methods in case you wanted to apply custom code before or after:
|
||||
|
||||
```js
|
||||
import { resetDatabase } from 'meteor/xolvio:cleaner';
|
||||
@@ -126,15 +158,11 @@ import { resetDatabase } from 'meteor/xolvio:cleaner';
|
||||
// NOTE: Before writing a method like this you'll want to double check
|
||||
// that this file is only going to be loaded in test mode!!
|
||||
Meteor.methods({
|
||||
'test.resetDatabase': () => resetDatabase(),
|
||||
});
|
||||
|
||||
describe('my module', function (done) {
|
||||
beforeEach(function (done) {
|
||||
// We need to wait until the method call is done before moving on, so we
|
||||
// use Mocha's async mechanism (calling a done callback)
|
||||
Meteor.call('test.resetDatabase', done);
|
||||
});
|
||||
'test.resetDatabase': () => {
|
||||
// custom code goes here...
|
||||
resetDatabase()
|
||||
// or here
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
@@ -144,10 +172,10 @@ As we've placed the code above in a test file, it *will not* load in normal deve
|
||||
|
||||
Often it's sensible to create a set of data to run your test against. You can use standard `insert()` calls against your collections to do this, but often it's easier to create *factories* which help encode random test data. A great package to use to do this is [`dburles:factory`](https://atmospherejs.com/dburles/factory).
|
||||
|
||||
In the [Todos](https://github.com/meteor/todos) example app, we define a factory to describe how to create a test todo item, using the [`faker`](https://www.npmjs.com/package/faker) npm package:
|
||||
In the [Todos](https://github.com/meteor/todos) example app, we define a factory to describe how to create a test todo item, using the [`faker`](https://www.npmjs.com/package/@faker-js/faker) npm package:
|
||||
|
||||
```js
|
||||
import faker from 'faker';
|
||||
import faker from '@faker-js/faker';
|
||||
|
||||
Factory.define('todo', Todos, {
|
||||
listId: () => Factory.get('list'),
|
||||
@@ -202,7 +230,7 @@ To do so, we'll use a very simple test helper that renders a Blaze component off
|
||||
[`imports/ui/test-helpers.js`](https://github.com/meteor/todos/blob/master/imports/ui/test-helpers.js):
|
||||
|
||||
```js
|
||||
import { _ } from 'meteor/underscore';
|
||||
import isString from 'lodash.isstring';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Blaze } from 'meteor/blaze';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
@@ -219,7 +247,7 @@ const withDiv = function withDiv(callback) {
|
||||
|
||||
export const withRenderedTemplate = function withRenderedTemplate(template, data, callback) {
|
||||
withDiv((el) => {
|
||||
const ourTemplate = _.isString(template) ? Template[template] : template;
|
||||
const ourTemplate = isString(template) ? Template[template] : template;
|
||||
Blaze.renderWithData(ourTemplate, data, el);
|
||||
Tracker.flush();
|
||||
callback(el);
|
||||
@@ -238,7 +266,7 @@ An example of a reusable component to test is the [`Todos_item`](https://github.
|
||||
import { Factory } from 'meteor/dburles:factory';
|
||||
import chai from 'chai';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import $ from 'jquery';
|
||||
import { Todos } from '../../../api/todos/todos';
|
||||
|
||||
|
||||
@@ -408,22 +436,68 @@ There's a lot of scope for better isolation and testing utilities.
|
||||
|
||||
<h4 id="testing-publications">Testing publications</h4>
|
||||
|
||||
Using the [`johanbrook:publication-collector`](https://atmospherejs.com/johanbrook/publication-collector) package, you're able to test individual publication's output without needing to create a traditional subscription:
|
||||
Let's take this simple publication for example:
|
||||
|
||||
```js
|
||||
describe('lists.public', function () {
|
||||
it('sends all public lists', function (done) {
|
||||
// server/publications/notes
|
||||
Meteor.publish('user.notes', function () {
|
||||
return Notes.find({ userId: this.userId });
|
||||
});
|
||||
```
|
||||
We access Meteor publications using `Meteor.server.publish_handlers`, then use `.apply` to provide the needed parameters for the publication and test what it returns.
|
||||
|
||||
```js
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import expect from 'expect';
|
||||
|
||||
import { Notes } from './notes';
|
||||
|
||||
describe('notes', function () {
|
||||
const noteOne = {
|
||||
_id: 'testNote1',
|
||||
title: 'Groceries',
|
||||
body: 'Milk, Eggs and Oatmeal'
|
||||
userId: 'userId1'
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
Notes.remove({});
|
||||
Notes.insert(noteOne);
|
||||
});
|
||||
|
||||
it('should return a users notes', function () {
|
||||
const res = Meteor.server.publish_handlers['user.notes'].apply({ userId: noteOne.userId });
|
||||
const notes = res.fetch();
|
||||
|
||||
expect(notes.length).toBe(1);
|
||||
expect(notes[0]).toEqual(noteOne);
|
||||
});
|
||||
|
||||
it('should return no notes for user that has none', function () {
|
||||
const res = Meteor.server.publish_handlers.notes.apply({ userId: 'testid' });
|
||||
const notes = res.fetch();
|
||||
|
||||
expect(notes.length).toBe(0);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
A useful package for testing publications is [`johanbrook:publication-collector`](https://atmospherejs.com/johanbrook/publication-collector), it allows you to test individual publication's output without needing to create a traditional subscription:
|
||||
|
||||
```js
|
||||
describe('notes', function () {
|
||||
it('should return a users notes', function (done) {
|
||||
// Set a user id that will be provided to the publish function as `this.userId`,
|
||||
// in case you want to test authentication.
|
||||
const collector = new PublicationCollector({userId: 'some-id'});
|
||||
const collector = new PublicationCollector({userId: noteOne.userId});
|
||||
|
||||
// Collect the data published from the `lists.public` publication.
|
||||
collector.collect('lists.public', (collections) => {
|
||||
collector.collect('user.notes', (collections) => {
|
||||
// `collections` is a dictionary with collection names as keys,
|
||||
// and their published documents as values in an array.
|
||||
// Here, documents from the collection 'Lists' are published.
|
||||
chai.assert.typeOf(collections.Lists, 'array');
|
||||
chai.assert.equal(collections.Lists.length, 3);
|
||||
chai.assert.equal(collections.Lists.length, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -432,6 +506,138 @@ describe('lists.public', function () {
|
||||
|
||||
Note that user documents – ones that you would normally query with `Meteor.users.find()` – will be available as the key `users` on the dictionary passed from a `PublicationCollector.collect()` call. See the [tests](https://github.com/johanbrook/meteor-publication-collector/blob/master/tests/publication-collector.test.js) in the package for more details.
|
||||
|
||||
<h4 id="testing-methods">Testing methods</h4>
|
||||
|
||||
We can also access methods using `Meteor.server.method_handlers` and apply the same principles. Take note of how we can use `sinon.fake()` to mock `this.unblock()`.
|
||||
|
||||
```js
|
||||
Meteor.methods({
|
||||
'notes.insert'(title, body) {
|
||||
if (!this.userId || Meteor.users.findOne({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You have to be authorized');
|
||||
}
|
||||
|
||||
check(title, String);
|
||||
check(body, String);
|
||||
|
||||
this.unblock();
|
||||
|
||||
return Notes.insert({
|
||||
title,
|
||||
body,
|
||||
userId: this.userId
|
||||
});
|
||||
},
|
||||
'notes.remove'(_id) {
|
||||
if (!this.userId || Meteor.users.findOne({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You have to be authorized');
|
||||
}
|
||||
|
||||
check(_id, String);
|
||||
|
||||
Notes.remove({ _id, userId: this.userId });
|
||||
},
|
||||
'notes.update'(_id, {title, body}) {
|
||||
if (!this.userId || Meteor.users.findOne({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You have to be authorized');
|
||||
}
|
||||
|
||||
check(_id, String);
|
||||
check(title, String);
|
||||
check(body, String);
|
||||
|
||||
Notes.update({
|
||||
_id,
|
||||
userId: this.userId
|
||||
}, {
|
||||
$set: {
|
||||
title,
|
||||
body
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
describe('notes', function () {
|
||||
const noteOne = {
|
||||
_id: 'testNote1',
|
||||
title: 'Groceries',
|
||||
body: 'Milk, Eggs and Oatmeal'
|
||||
userId: 'testUserId1'
|
||||
};
|
||||
beforeEach(function () {
|
||||
Notes.remove({});
|
||||
});
|
||||
|
||||
it('should insert new note', function () {
|
||||
const _id = Meteor.server.method_handlers['notes.insert'].apply({ userId: noteOne.userId, unblock: sinon.fake() }. [title: noteOne.title, body: noteOne.body]);
|
||||
|
||||
expect(Notes.findOne({ _id })).toMatchObject(
|
||||
expect.objectContaining(noteOne)
|
||||
);
|
||||
});
|
||||
|
||||
it('should not insert note if not authenticated', function () {
|
||||
expect(() => {
|
||||
Meteor.server.method_handlers['notes.insert']();
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should remove note', function () {
|
||||
Meteor.server.method_handlers['notes.remove'].apply({ userId: noteOne.userId }, [noteOne._id]);
|
||||
|
||||
expect(Notes.findOne({ _id: noteOne._id})).toNotExist();
|
||||
});
|
||||
|
||||
it('should not remove note if invalid _id', function () {
|
||||
expect(() => {
|
||||
Meteor.server.method_handlers['notes.remove'].apply({ userId: noteOne.userId});
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should update note', function () {
|
||||
const title = 'To Buy';
|
||||
const beef = 'Beef, Salmon'
|
||||
|
||||
Meteor.server.method_handlers['notes.update'].apply({
|
||||
userId: noteOne.userId
|
||||
}, [
|
||||
noteOne._id,
|
||||
{title, body}
|
||||
]);
|
||||
|
||||
const note = Notes.findOne(noteOne._id);
|
||||
|
||||
expect(note).toInclude({
|
||||
title,
|
||||
body
|
||||
});
|
||||
});
|
||||
|
||||
it('should not update note if user was not creator', function () {
|
||||
const title = 'This is an updated title';
|
||||
|
||||
Meteor.server.method_handlers['notes.update'].apply({
|
||||
userId: 'testid'
|
||||
}, [
|
||||
noteOne._id,
|
||||
{ title }
|
||||
]);
|
||||
|
||||
const note = Notes.findOne(noteOne._id);
|
||||
|
||||
expect(note).toInclude(noteOne);
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
These examples are heavily inspired by [Andrew Mead example app](https://github.com/andrewjmead/notes-meteor-course).
|
||||
|
||||
<h2 id="integration-testing">Integration testing</h2>
|
||||
|
||||
An integration test is a test that crosses module boundaries. In the simplest case, this means something very similar to a unit test, where you perform your isolation around multiple modules, creating a non-singular "system under test".
|
||||
@@ -460,8 +666,7 @@ import { Random } from 'meteor/random';
|
||||
import chai from 'chai';
|
||||
import StubCollections from 'meteor/hwillson:stub-collections';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import $ from 'jquery';
|
||||
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
|
||||
import sinon from 'sinon';
|
||||
|
||||
@@ -481,7 +686,7 @@ describe('Lists_show_page', function () {
|
||||
sinon.stub(Meteor, 'subscribe').returns.({
|
||||
subscriptionId: 0,
|
||||
ready: () => true,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -494,7 +699,7 @@ describe('Lists_show_page', function () {
|
||||
it('renders correctly with simple data', function () {
|
||||
Factory.create('list', { _id: listId });
|
||||
const timestamp = new Date();
|
||||
const todos = _.times(3, i => Factory.create('todo', {
|
||||
const todos = [...Array(3).keys()].forEach(i => Factory.create('todo', {
|
||||
listId,
|
||||
createdAt: new Date(timestamp - (3 - i)),
|
||||
}));
|
||||
@@ -543,7 +748,7 @@ import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { Promise } from 'meteor/promise';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import $ from 'jquery';
|
||||
|
||||
import { denodeify } from '../../utils/denodeify';
|
||||
import { generateData } from './../../api/generate-data.app-tests.js';
|
||||
@@ -627,13 +832,12 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { Factory } from 'meteor/dburles:factory';
|
||||
import { resetDatabase } from 'meteor/xolvio:cleaner';
|
||||
import { Random } from 'meteor/random';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
import { denodeify } from '../utils/denodeify';
|
||||
|
||||
const createList = (userId) => {
|
||||
const list = Factory.create('list', { userId });
|
||||
_.times(3, () => Factory.create('todo', { listId: list._id }));
|
||||
[...Array(3).keys()].forEach(() => Factory.create('todo', { listId: list._id }));
|
||||
return list;
|
||||
};
|
||||
|
||||
@@ -644,10 +848,10 @@ Meteor.methods({
|
||||
resetDatabase();
|
||||
|
||||
// create 3 public lists
|
||||
_.times(3, () => createList());
|
||||
[...Array(3).keys()].forEach(() => createList());
|
||||
|
||||
// create 3 private lists
|
||||
_.times(3, () => createList(Random.id()));
|
||||
[...Array(3).keys()].forEach(() => createList(Random.id()));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -674,102 +878,77 @@ Also of note is the way we use a second DDP connection to the server in order to
|
||||
|
||||
Acceptance testing is the process of taking an unmodified version of our application and testing it from the "outside" to make sure it behaves in a way we expect. Typically if an app passes acceptance tests, we have done our job properly from a product perspective.
|
||||
|
||||
As acceptance tests test the behavior of the application in a full browser context in a generic way, there are a range of tools that you can use to specify and run such tests. In this guide we'll demonstrate using [Chimp](https://chimp.readme.io), an acceptance testing tool with a few neat Meteor-specific features that makes it easy to use.
|
||||
As acceptance tests test the behavior of the application in a full browser context in a generic way, there are a range of tools that you can use to specify and run such tests. In this guide we'll demonstrate using [Cypress](https://www.cypress.io/), an acceptance testing tool with a few neat Meteor-specific features that makes it easy to use.
|
||||
|
||||
Chimp requires node version 4 or 5. You can check your node version by running:
|
||||
Install Cypress as a dev dependency:
|
||||
|
||||
```sh
|
||||
node -v
|
||||
```bash
|
||||
cd /your/project/path
|
||||
meteor npm install cypress --save-dev
|
||||
```
|
||||
|
||||
You can install version 4 from [nodejs.org](https://nodejs.org/en/download/) or version 5 with `brew install node`. Then we can install the Chimp tool globally using:
|
||||
Designate a special directory for cypress test to avoid Meteor eagerly loading it:
|
||||
|
||||
```sh
|
||||
npm install --global chimp
|
||||
```bash
|
||||
mkdir tests
|
||||
mv cypress/ tests/cypress
|
||||
```
|
||||
|
||||
> Note that you can also install Chimp as a `devDependency` in your `package.json` but you may run into problems deploying your application as it includes binary dependencies. You can avoid such problems by running `meteor npm prune` to remove non-production dependencies before deploying.
|
||||
|
||||
Chimp has a variety of options for setting it up, but we can add some npm scripts which will run the currently tests we define in Chimp's two main modes. We can add them to our `package.json`:
|
||||
Create `cypress.json` file at the root of your project to config Cypress:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests",
|
||||
"chimp-test": "chimp --mocha --path=tests"
|
||||
}
|
||||
"fixturesFolder": "tests/cypress/fixtures",
|
||||
"integrationFolder": "tests/cypress/integration",
|
||||
"pluginsFile": "tests/cypress/plugins/index.js",
|
||||
"screenshotsFolder": "tests/cypress/screenshots",
|
||||
"supportFile": "tests/cypress/support/index.js",
|
||||
"videosFolder": "tests/cypress/videos"
|
||||
}
|
||||
```
|
||||
|
||||
Chimp will now look in the `tests/` directory (otherwise ignored by the Meteor tool) for files in which you define acceptance tests. In the [Todos](https://github.com/meteor/todos) example app, we define a simple test that ensures we can click the "create list" button.
|
||||
|
||||
[`tests/lists.js`](https://github.com/meteor/todos/blob/master/tests/lists.js):
|
||||
Add commands to your `package.json`
|
||||
|
||||
```js
|
||||
/* eslint-env mocha */
|
||||
/* eslint-disable func-names, prefer-arrow-callback */
|
||||
"scripts": {
|
||||
"cypress:gui": "cypress open",
|
||||
"cypress:headless": "cypress run"
|
||||
},
|
||||
```
|
||||
|
||||
// These are Chimp globals
|
||||
/* globals browser assert server */
|
||||
Now, let's create a simple test by adding a new file called `signup_tests.js` in the `tests/cypress/integration/` directory.
|
||||
|
||||
function countLists() {
|
||||
browser.waitForExist('.list-todo');
|
||||
const elements = browser.elements('.list-todo');
|
||||
return elements.value.length;
|
||||
};
|
||||
|
||||
describe('list ui', function () {
|
||||
beforeEach(function () {
|
||||
browser.url('http://localhost:3000');
|
||||
server.call('generateFixtures');
|
||||
```js
|
||||
describe("sign-up", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("http://localhost:3000/");
|
||||
});
|
||||
|
||||
it('can create a list @watch', function () {
|
||||
const initialCount = countLists();
|
||||
it("should create and log the new user", () => {
|
||||
cy.contains("Register").click();
|
||||
cy.get("input#at-field-email").type("jean-peter.mac.calloway@gmail.com");
|
||||
cy.get("input#at-field-password").type("awesome-password");
|
||||
cy.get("input#at-field-password_again").type("awesome-password");
|
||||
// I added a name field on meteor user accounts system
|
||||
cy.get("input#at-field-name").type("Jean-Peter");
|
||||
cy.get("button#at-btn").click();
|
||||
|
||||
browser.click('.js-new-list');
|
||||
cy.url().should("eq", "http://localhost:3000/board");
|
||||
|
||||
assert.equal(countLists(), initialCount + 1);
|
||||
cy.window().then(win => {
|
||||
// this allows accessing the window object within the browser
|
||||
const user = win.Meteor.user();
|
||||
expect(user).to.exist;
|
||||
expect(user.profile.name).to.equal("Jean-Peter");
|
||||
expect(user.emails[0].address).to.equal(
|
||||
"jean-peter.mac.calloway@gmail.com"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
<h3 id="running-acceptance-tests">Running acceptance tests</h3>
|
||||
|
||||
To run acceptance tests, we need to start our Meteor app as usual, and point Chimp at it.
|
||||
|
||||
In one terminal, we can do:
|
||||
|
||||
```bash
|
||||
meteor
|
||||
```
|
||||
|
||||
In another:
|
||||
|
||||
```bash
|
||||
meteor npm run chimp-watch
|
||||
```
|
||||
|
||||
The `chimp-watch` command will then run the test in a browser, and continue to re-run it as we change the test or the application. (Note that the test assumes we are running the app on port `3000`).
|
||||
|
||||
|
||||
Thus it's a good way to develop the test---this is why chimp has a feature where we mark tests with a `@watch` in the name to call out the tests we want to work on (running our entire acceptance test suite can be time consuming in a large application).
|
||||
|
||||
The `chimp-test` command will run all of the tests *once only* and is good for testing that our suite passes, either as a manual step, or as part of a [continuous integration](#ci) process.
|
||||
|
||||
|
||||
<h3 id="creating-acceptance-test-data">Creating data</h3>
|
||||
|
||||
Although we can run the acceptance test against our "pure" Meteor app, as we've done above, it often makes sense to start our meteor server with a special test driver, `tmeasday:acceptance-test-driver`. (You'll need to `meteor add` it to your app):
|
||||
|
||||
```txt
|
||||
meteor test --full-app --driver-package tmeasday:acceptance-test-driver
|
||||
```
|
||||
|
||||
The advantage of running our acceptance test suite pointed at an app that runs in full app test mode is that all of the [data generating methods](#creating-integration-test-data) that we've created remain available. Otherwise the `acceptance-test-driver` does nothing.
|
||||
|
||||
In Chimp tests, you have a DDP connection to the server available on the `server` variable. You can thus use `server.call()` (which is wrapped to be synchronous in Chimp tests) to call these methods. This is a convenient way to share data preparation code between acceptance and integration tests.
|
||||
|
||||
This is example is sampled from [Jean-Denis Gallego post](https://dev.to/splitified/test-your-meteor-app-with-docker-jenkins-and-cypress-part-1-12om). You may also check out this [entry](https://blog.meteor.com/testing-a-meteor-app-with-cypress-bfb3d3c6ed6f?gi=4f799b6211b7) on Meteor blog and [marmelab](https://marmelab.com/blog/2019/02/28/cypress-on-meteor.html) article for more information.
|
||||
|
||||
<h2 id="ci">Continuous Integration</h2>
|
||||
|
||||
@@ -779,7 +958,7 @@ There are two principal ways to do it: on the developer's machine before allowin
|
||||
|
||||
<h3 id="command-line">Command line</h3>
|
||||
|
||||
We've seen one example of running tests on the command line, using our `meteor npm run chimp-test` mode.
|
||||
We've seen one example of running tests on the command line, using our `meteor npm run cypress:headless` mode.
|
||||
|
||||
We can also use a command-line driver for Mocha [`meteortesting:mocha`](https://atmospherejs.com/meteortesting/mocha) to run our standard tests on the command line.
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ This documentation is purely focused on integrating it with Meteor.
|
||||
> There is also a [Vue tutorial](https://vue-tutorial.meteor.com/) which covers the basics of this section.
|
||||
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
|
||||
[Vue](https://vuejs.org/v2/guide/) (pronounced /vjuː/, like view) is a progressive framework for building user interfaces.
|
||||
Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable.
|
||||
The core library is focused on the view layer only, and is easy to
|
||||
@@ -338,9 +339,11 @@ Application Structure is documented here:
|
||||
|
||||
|
||||
<h2 id="ssr-code-splitting">SSR and Code Splitting</h2>
|
||||
|
||||
Vue has [an excellent guide on how to render your Vue application on the server](https://vuejs.org/v2/guide/ssr.html). It includes code splitting, async data fetching and many other practices that are used in most apps that require this.
|
||||
|
||||
<h3 id="basic-example">Basic Example</h3>
|
||||
|
||||
Making Vue SSR to work with Meteor is not more complex then for example with [Express](https://expressjs.com/).
|
||||
However instead of defining a wildcard route, Meteor uses its own [server-render](https://docs.meteor.com/packages/server-render.html) package that exposes an `onPageLoad` function. Every time a call is made to
|
||||
the server side, this function is triggered. This is where we should put our code like how its described on the [VueJS SSR Guide](https://ssr.vuejs.org/guide/#integrating-with-a-server).
|
||||
|
||||
2
meteor
2
meteor
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BUNDLE_VERSION=14.18.2.3
|
||||
BUNDLE_VERSION=14.19.1.0
|
||||
|
||||
# OS Check. Put here because here is where we download the precompiled
|
||||
# bundles that are arch specific.
|
||||
|
||||
@@ -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.1",
|
||||
// Keep the versions of these packages consistent with the versions
|
||||
// found in dev-bundle-server-package.js.
|
||||
"meteor-promise": "0.9.0",
|
||||
|
||||
688
npm-packages/meteor-babel/package-lock.json
generated
688
npm-packages/meteor-babel/package-lock.json
generated
@@ -1,15 +1,23 @@
|
||||
{
|
||||
"name": "@meteorjs/babel",
|
||||
"version": "7.15.0",
|
||||
"version": "7.16.0-beta.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
|
||||
"integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
|
||||
"@ampproject/remapping": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz",
|
||||
"integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==",
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.14.5"
|
||||
"@jridgewell/trace-mapping": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
|
||||
"integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/compat-data": {
|
||||
@@ -18,56 +26,83 @@
|
||||
"integrity": "sha512-p3QjZmMGHDGdpcwEYYWu7i7oJShJvtgMjJeb0W95PPhSm++3lm8YXYOh45Y6iCN9PkZLTZ7CIX5nFrp7pw7TXw=="
|
||||
},
|
||||
"@babel/core": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz",
|
||||
"integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==",
|
||||
"version": "7.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz",
|
||||
"integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/generator": "^7.15.0",
|
||||
"@babel/helper-compilation-targets": "^7.15.0",
|
||||
"@babel/helper-module-transforms": "^7.15.0",
|
||||
"@babel/helpers": "^7.14.8",
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/template": "^7.14.5",
|
||||
"@babel/traverse": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@ampproject/remapping": "^2.0.0",
|
||||
"@babel/code-frame": "^7.16.7",
|
||||
"@babel/generator": "^7.17.0",
|
||||
"@babel/helper-compilation-targets": "^7.16.7",
|
||||
"@babel/helper-module-transforms": "^7.16.7",
|
||||
"@babel/helpers": "^7.17.2",
|
||||
"@babel/parser": "^7.17.0",
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/traverse": "^7.17.0",
|
||||
"@babel/types": "^7.17.0",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.1.2",
|
||||
"semver": "^6.3.0",
|
||||
"source-map": "^0.5.0"
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/compat-data": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz",
|
||||
"integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA=="
|
||||
"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/helper-compilation-targets": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz",
|
||||
"integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
|
||||
"integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.15.0",
|
||||
"@babel/helper-validator-option": "^7.14.5",
|
||||
"browserslist": "^4.16.6",
|
||||
"@babel/compat-data": "^7.16.4",
|
||||
"@babel/helper-validator-option": "^7.16.7",
|
||||
"browserslist": "^4.17.5",
|
||||
"semver": "^6.3.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
"@babel/helper-validator-option": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
|
||||
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
|
||||
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001286",
|
||||
"electron-to-chromium": "^1.4.17",
|
||||
"escalade": "^3.1.1",
|
||||
"node-releases": "^2.0.1",
|
||||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001312",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
|
||||
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.68",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz",
|
||||
"integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA=="
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
|
||||
"integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz",
|
||||
"integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==",
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz",
|
||||
"integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.0",
|
||||
"@babel/types": "^7.17.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
},
|
||||
@@ -111,6 +146,7 @@
|
||||
"version": "7.14.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.8.tgz",
|
||||
"integrity": "sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-annotate-as-pure": "^7.14.5",
|
||||
"@babel/helper-function-name": "^7.14.5",
|
||||
@@ -130,9 +166,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz",
|
||||
"integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-compilation-targets": "^7.13.0",
|
||||
"@babel/helper-module-imports": "^7.12.13",
|
||||
@@ -144,6 +180,14 @@
|
||||
"semver": "^6.1.2"
|
||||
}
|
||||
},
|
||||
"@babel/helper-environment-visitor": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
|
||||
"integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-explode-assignable-expression": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz",
|
||||
@@ -171,11 +215,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz",
|
||||
"integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.14.5"
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-member-expression-to-functions": {
|
||||
@@ -195,37 +239,34 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-transforms": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz",
|
||||
"integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
|
||||
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.14.5",
|
||||
"@babel/helper-replace-supers": "^7.15.0",
|
||||
"@babel/helper-simple-access": "^7.14.8",
|
||||
"@babel/helper-split-export-declaration": "^7.14.5",
|
||||
"@babel/helper-validator-identifier": "^7.14.9",
|
||||
"@babel/template": "^7.14.5",
|
||||
"@babel/traverse": "^7.15.0",
|
||||
"@babel/types": "^7.15.0"
|
||||
"@babel/helper-environment-visitor": "^7.16.7",
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/helper-simple-access": "^7.16.7",
|
||||
"@babel/helper-split-export-declaration": "^7.16.7",
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/traverse": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-member-expression-to-functions": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz",
|
||||
"integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==",
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
|
||||
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.0"
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-replace-supers": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz",
|
||||
"integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==",
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-member-expression-to-functions": "^7.15.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.14.5",
|
||||
"@babel/traverse": "^7.15.0",
|
||||
"@babel/types": "^7.15.0"
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,11 +306,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-simple-access": {
|
||||
"version": "7.14.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz",
|
||||
"integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.14.8"
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-skip-transparent-expression-wrappers": {
|
||||
@@ -289,9 +330,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
|
||||
"integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g=="
|
||||
"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",
|
||||
@@ -310,29 +351,29 @@
|
||||
}
|
||||
},
|
||||
"@babel/helpers": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz",
|
||||
"integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==",
|
||||
"version": "7.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz",
|
||||
"integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==",
|
||||
"requires": {
|
||||
"@babel/template": "^7.14.5",
|
||||
"@babel/traverse": "^7.15.0",
|
||||
"@babel/types": "^7.15.0"
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/traverse": "^7.17.0",
|
||||
"@babel/types": "^7.17.0"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
|
||||
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
|
||||
"version": "7.16.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
|
||||
"integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.5",
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"chalk": "^2.0.0",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz",
|
||||
"integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA=="
|
||||
"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.14.9",
|
||||
@@ -345,12 +386,95 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-class-properties": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz",
|
||||
"integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
"@babel/helper-create-class-features-plugin": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-create-class-features-plugin": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-annotate-as-pure": "^7.16.7",
|
||||
"@babel/helper-environment-visitor": "^7.16.7",
|
||||
"@babel/helper-function-name": "^7.16.7",
|
||||
"@babel/helper-member-expression-to-functions": "^7.16.7",
|
||||
"@babel/helper-optimise-call-expression": "^7.16.7",
|
||||
"@babel/helper-replace-supers": "^7.16.7",
|
||||
"@babel/helper-split-export-declaration": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
|
||||
"integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
|
||||
"requires": {
|
||||
"@babel/helper-get-function-arity": "^7.16.7",
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-get-function-arity": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-member-expression-to-functions": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-optimise-call-expression": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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-replace-supers": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
|
||||
"integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==",
|
||||
"requires": {
|
||||
"@babel/helper-environment-visitor": "^7.16.7",
|
||||
"@babel/helper-member-expression-to-functions": "^7.16.7",
|
||||
"@babel/helper-optimise-call-expression": "^7.16.7",
|
||||
"@babel/traverse": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-decorators": {
|
||||
@@ -447,11 +571,18 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-syntax-jsx": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz",
|
||||
"integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz",
|
||||
"integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
"@babel/helper-plugin-utils": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-syntax-logical-assignment-operators": {
|
||||
@@ -584,14 +715,21 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-modules-commonjs": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz",
|
||||
"integrity": "sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-module-transforms": "^7.15.0",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-simple-access": "^7.14.8",
|
||||
"@babel/helper-module-transforms": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"@babel/helper-simple-access": "^7.16.7",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-transform-object-super": {
|
||||
@@ -620,40 +758,85 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-react-display-name": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz",
|
||||
"integrity": "sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
"@babel/helper-plugin-utils": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-transform-react-jsx": {
|
||||
"version": "7.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz",
|
||||
"integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-annotate-as-pure": "^7.14.5",
|
||||
"@babel/helper-module-imports": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/plugin-syntax-jsx": "^7.14.5",
|
||||
"@babel/types": "^7.14.9"
|
||||
"@babel/helper-annotate-as-pure": "^7.16.7",
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"@babel/plugin-syntax-jsx": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
|
||||
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-transform-react-jsx-development": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.14.5.tgz",
|
||||
"integrity": "sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/plugin-transform-react-jsx": "^7.14.5"
|
||||
"@babel/plugin-transform-react-jsx": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-react-pure-annotations": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.14.5.tgz",
|
||||
"integrity": "sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-annotate-as-pure": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
"@babel/helper-annotate-as-pure": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-transform-regenerator": {
|
||||
@@ -665,16 +848,31 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-runtime": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz",
|
||||
"integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
||||
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
||||
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"babel-plugin-polyfill-corejs2": "^0.3.0",
|
||||
"babel-plugin-polyfill-corejs3": "^0.5.0",
|
||||
"babel-plugin-polyfill-regenerator": "^0.3.0",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
|
||||
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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/plugin-transform-shorthand-properties": {
|
||||
@@ -728,61 +926,121 @@
|
||||
}
|
||||
},
|
||||
"@babel/preset-react": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.14.5.tgz",
|
||||
"integrity": "sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-validator-option": "^7.14.5",
|
||||
"@babel/plugin-transform-react-display-name": "^7.14.5",
|
||||
"@babel/plugin-transform-react-jsx": "^7.14.5",
|
||||
"@babel/plugin-transform-react-jsx-development": "^7.14.5",
|
||||
"@babel/plugin-transform-react-pure-annotations": "^7.14.5"
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"@babel/helper-validator-option": "^7.16.7",
|
||||
"@babel/plugin-transform-react-display-name": "^7.16.7",
|
||||
"@babel/plugin-transform-react-jsx": "^7.16.7",
|
||||
"@babel/plugin-transform-react-jsx-development": "^7.16.7",
|
||||
"@babel/plugin-transform-react-pure-annotations": "^7.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"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-validator-option": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
|
||||
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz",
|
||||
"integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==",
|
||||
"version": "7.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
||||
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
|
||||
"integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
|
||||
"integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/parser": "^7.14.5",
|
||||
"@babel/types": "^7.14.5"
|
||||
"@babel/code-frame": "^7.16.7",
|
||||
"@babel/parser": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz",
|
||||
"integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==",
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz",
|
||||
"integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/generator": "^7.15.0",
|
||||
"@babel/helper-function-name": "^7.14.5",
|
||||
"@babel/helper-hoist-variables": "^7.14.5",
|
||||
"@babel/helper-split-export-declaration": "^7.14.5",
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@babel/code-frame": "^7.16.7",
|
||||
"@babel/generator": "^7.17.0",
|
||||
"@babel/helper-environment-visitor": "^7.16.7",
|
||||
"@babel/helper-function-name": "^7.16.7",
|
||||
"@babel/helper-hoist-variables": "^7.16.7",
|
||||
"@babel/helper-split-export-declaration": "^7.16.7",
|
||||
"@babel/parser": "^7.17.0",
|
||||
"@babel/types": "^7.17.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
|
||||
"integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
|
||||
"requires": {
|
||||
"@babel/helper-get-function-arity": "^7.16.7",
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-get-function-arity": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz",
|
||||
"integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==",
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
|
||||
"integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.9",
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew=="
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
|
||||
"integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg=="
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
|
||||
"integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"@meteorjs/reify": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@meteorjs/reify/-/reify-0.23.0.tgz",
|
||||
@@ -979,30 +1237,30 @@
|
||||
}
|
||||
},
|
||||
"babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz",
|
||||
"integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.13.11",
|
||||
"@babel/helper-define-polyfill-provider": "^0.2.2",
|
||||
"@babel/helper-define-polyfill-provider": "^0.3.1",
|
||||
"semver": "^6.1.1"
|
||||
}
|
||||
},
|
||||
"babel-plugin-polyfill-corejs3": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz",
|
||||
"integrity": "sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.2.2",
|
||||
"core-js-compat": "^3.14.0"
|
||||
"@babel/helper-define-polyfill-provider": "^0.3.1",
|
||||
"core-js-compat": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-polyfill-regenerator": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz",
|
||||
"integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.2.2"
|
||||
"@babel/helper-define-polyfill-provider": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-inline-consecutive-adds": {
|
||||
@@ -1278,26 +1536,41 @@
|
||||
}
|
||||
},
|
||||
"core-js-compat": {
|
||||
"version": "3.16.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.1.tgz",
|
||||
"integrity": "sha512-NHXQXvRbd4nxp9TEmooTJLUf94ySUG6+DSsscBpTftN1lQLQ4LjnWvc7AoIo4UjDsFF3hB8Uh5LLCRRdaiT5MQ==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"browserslist": "^4.16.7",
|
||||
"browserslist": "^4.19.1",
|
||||
"semver": "7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"browserslist": {
|
||||
"version": "4.16.7",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz",
|
||||
"integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==",
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
|
||||
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001248",
|
||||
"colorette": "^1.2.2",
|
||||
"electron-to-chromium": "^1.3.793",
|
||||
"caniuse-lite": "^1.0.30001286",
|
||||
"electron-to-chromium": "^1.4.17",
|
||||
"escalade": "^3.1.1",
|
||||
"node-releases": "^1.1.73"
|
||||
"node-releases": "^2.0.1",
|
||||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001312",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
|
||||
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.68",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz",
|
||||
"integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA=="
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
|
||||
"integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
|
||||
@@ -1592,9 +1865,9 @@
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
@@ -1876,9 +2149,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz",
|
||||
"integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==",
|
||||
"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==",
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
@@ -2234,6 +2507,11 @@
|
||||
"is-reference": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||
},
|
||||
"promise": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
|
||||
@@ -2315,12 +2593,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
"is-core-module": "^2.8.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"rw": {
|
||||
@@ -2432,15 +2711,20 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"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.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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@meteorjs/babel",
|
||||
"author": "Meteor <dev@meteor.com>",
|
||||
"version": "7.15.0",
|
||||
"version": "7.16.0-beta.1",
|
||||
"license": "MIT",
|
||||
"description": "Babel wrapper package for use with Meteor",
|
||||
"keywords": [
|
||||
@@ -30,24 +30,24 @@
|
||||
"url": "https://github.com/meteor/babel/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/parser": "^7.15.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/core": "^7.17.2",
|
||||
"@babel/parser": "^7.17.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.15.0",
|
||||
"@babel/plugin-transform-runtime": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/runtime": "^7.15.3",
|
||||
"@babel/template": "^7.14.5",
|
||||
"@babel/traverse": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.16.8",
|
||||
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"@babel/runtime": "^7.17.2",
|
||||
"@babel/template": "^7.16.7",
|
||||
"@babel/traverse": "^7.17.0",
|
||||
"@babel/types": "^7.17.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",
|
||||
|
||||
@@ -12,20 +12,40 @@ npm install -g meteor
|
||||
|
||||
| NPM Package | Meteor Official Release |
|
||||
|-------------|-------------------------|
|
||||
| 2.3.1 | 2.2.1 |
|
||||
| 2.3.2 | 2.3.1 |
|
||||
| 2.3.3 | 2.3.2 |
|
||||
| 2.3.4 | 2.3.4 |
|
||||
| 2.3.5 | 2.3.5 |
|
||||
| 2.3.6 | 2.3.5 |
|
||||
| 2.3.7 | 2.3.6 |
|
||||
| 2.4.0 | 2.4 |
|
||||
| 2.4.1 | 2.4 |
|
||||
| 2.5.0 | 2.5 |
|
||||
| 2.5.1 | 2.5.1 |
|
||||
| 2.5.2 | 2.5.1 |
|
||||
| 2.7.2 | 2.7.1 |
|
||||
| 2.7.1 | 2.7 |
|
||||
| 2.7.0 | 2.7 |
|
||||
| 2.6.2 | 2.6.1 |
|
||||
| 2.6.1 | 2.6 |
|
||||
| 2.6.0 | 2.6 |
|
||||
| 2.5.7 | 2.5.6 |
|
||||
| 2.5.6 | 2.5.5 |
|
||||
| 2.5.5 | 2.5.4 |
|
||||
| 2.5.4 | 2.5.3 |
|
||||
| 2.5.3 | 2.5.2 |
|
||||
| 2.5.2 | 2.5.1 |
|
||||
| 2.5.1 | 2.5.1 |
|
||||
| 2.5.0 | 2.5 |
|
||||
| 2.4.1 | 2.4 |
|
||||
| 2.4.0 | 2.4 |
|
||||
| 2.3.7 | 2.3.6 |
|
||||
| 2.3.6 | 2.3.5 |
|
||||
| 2.3.5 | 2.3.5 |
|
||||
| 2.3.4 | 2.3.4 |
|
||||
| 2.3.3 | 2.3.2 |
|
||||
| 2.3.2 | 2.3.1 |
|
||||
| 2.3.1 | 2.2.1 |
|
||||
|
||||
### 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`)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
const METEOR_LATEST_VERSION = '2.5.2';
|
||||
const METEOR_LATEST_VERSION = '2.7.1';
|
||||
const sudoUser = process.env.SUDO_USER || '';
|
||||
function isRoot() {
|
||||
return process.getuid && process.getuid() === 0;
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ const {
|
||||
isSudo,
|
||||
isMac,
|
||||
METEOR_LATEST_VERSION,
|
||||
shouldSetupExecPath,
|
||||
} = require('./config.js');
|
||||
const { uninstall } = require('./uninstall');
|
||||
const {
|
||||
@@ -43,7 +44,7 @@ process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
});
|
||||
if (os.arch() !== 'x64') {
|
||||
const isValidM1Version = semver.gte(METEOR_LATEST_VERSION, '2.5.1-beta.3');
|
||||
const isValidM1Version = semver.gte(semver.coerce(METEOR_LATEST_VERSION), '2.5.1-beta.3');
|
||||
if (os.arch() !== 'arm64' || !isMac() || !isValidM1Version) {
|
||||
console.error(
|
||||
'The current architecture is not supported in this version: ',
|
||||
@@ -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}"`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meteor",
|
||||
"version": "2.5.3",
|
||||
"version": "2.7.2",
|
||||
"description": "Install Meteor",
|
||||
"main": "install.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
v1.2.1 - 2022-03-17
|
||||
|
||||
* Fix the missing dependencies.
|
||||
|
||||
v1.2.0 - 2022-03-11
|
||||
|
||||
* Adds support for [node: imports](https://nodejs.org/api/esm.html#node-imports).
|
||||
|
||||
v1.1.0 - 2021-07-19
|
||||
|
||||
* Updated dependencies to their latest versions
|
||||
|
||||
@@ -6,11 +6,11 @@ Object.keys(map).forEach(function (id) {
|
||||
var aliasParts = module.id.split("/");
|
||||
aliasParts.pop();
|
||||
aliasParts.push("node_modules", map[id]);
|
||||
exports[id] = meteorAliases[id + ".js"] =
|
||||
exports[id] = meteorAliases[id + ".js"] = meteorAliases["node:" + id] =
|
||||
aliasParts.join("/");
|
||||
} else {
|
||||
exports[id] = map[id];
|
||||
meteorAliases[id + ".js"] = function(){};
|
||||
meteorAliases[id + ".js"] = meteorAliases["node:" + id] = function(){};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
2
npm-packages/meteor-node-stubs/package-lock.json
generated
2
npm-packages/meteor-node-stubs/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meteor-node-stubs",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "meteor-node-stubs",
|
||||
"author": "Ben Newman <ben@meteor.com>",
|
||||
"description": "Stub implementations of Node built-in modules, a la Browserify",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
2
packages/accounts-2fa/.gitignore
vendored
Normal file
2
packages/accounts-2fa/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.build*
|
||||
.versions
|
||||
76
packages/accounts-2fa/2fa-client.js
Normal file
76
packages/accounts-2fa/2fa-client.js
Normal 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 logged user has 2FA enabled
|
||||
* @locus Client
|
||||
* @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 = callback => {
|
||||
Accounts.connection.call('has2faEnabled', 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 single `Error` argument on failure.
|
||||
* Or, on success, called with an object containing the QR code in SVG format (svg),
|
||||
* the QR secret (secret), and the URI so the user can manually activate the 2FA without reading the QR code (uri).
|
||||
*/
|
||||
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);
|
||||
};
|
||||
132
packages/accounts-2fa/2fa-server.js
Normal file
132
packages/accounts-2fa/2fa-server.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import twofactor from 'node-2fa';
|
||||
import QRCode from 'qrcode-svg';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check, Match } from 'meteor/check';
|
||||
|
||||
Accounts._check2faEnabled = user => {
|
||||
const { services: { twoFactorAuthentication } = {} } = user;
|
||||
return !!(
|
||||
twoFactorAuthentication &&
|
||||
twoFactorAuthentication.secret &&
|
||||
twoFactorAuthentication.type === 'otp'
|
||||
);
|
||||
};
|
||||
|
||||
Accounts._is2faEnabledForUser = () => {
|
||||
const user = Meteor.user();
|
||||
if (!user) {
|
||||
throw new Meteor.Error('no-logged-user', 'No user logged in.');
|
||||
}
|
||||
return Accounts._check2faEnabled(user);
|
||||
};
|
||||
|
||||
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'
|
||||
);
|
||||
}
|
||||
return twofactor.verifyToken(secret, code, 10) !== null;
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
generate2faActivationQrCode(appName) {
|
||||
check(appName, String);
|
||||
const user = Meteor.user();
|
||||
|
||||
if (!user) {
|
||||
throw new Meteor.Error(
|
||||
400,
|
||||
'There must be a user logged in to generate the QR code.'
|
||||
);
|
||||
}
|
||||
|
||||
if (Accounts._check2faEnabled(user)) {
|
||||
throw new Meteor.Error(
|
||||
'2fa-activated',
|
||||
'The 2FA is activated. You need to disable the 2FA first before trying to generate a new activation code.'
|
||||
);
|
||||
}
|
||||
|
||||
const emails = user.emails || [];
|
||||
const { secret, uri } = twofactor.generateSecret({
|
||||
name: appName.trim(),
|
||||
account: user.username || emails[0]?.address || user._id,
|
||||
});
|
||||
const svg = new QRCode(uri).svg();
|
||||
|
||||
Meteor.users.update(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'services.twoFactorAuthentication': {
|
||||
secret,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return { svg, secret, uri };
|
||||
},
|
||||
enableUser2fa(code) {
|
||||
check(code, String);
|
||||
const user = Meteor.user();
|
||||
|
||||
if (!user) {
|
||||
throw new Meteor.Error(400, 'No user logged in.');
|
||||
}
|
||||
|
||||
const {
|
||||
services: { twoFactorAuthentication },
|
||||
} = 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)) {
|
||||
Accounts._handleError('Invalid 2FA code', true, 'invalid-2fa-code');
|
||||
}
|
||||
|
||||
Meteor.users.update(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'services.twoFactorAuthentication': {
|
||||
...twoFactorAuthentication,
|
||||
type: 'otp',
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
disableUser2fa() {
|
||||
const userId = Meteor.userId();
|
||||
|
||||
if (!userId) {
|
||||
throw new Meteor.Error(400, 'No user logged in.');
|
||||
}
|
||||
|
||||
Meteor.users.update(
|
||||
{ _id: userId },
|
||||
{
|
||||
$unset: {
|
||||
'services.twoFactorAuthentication': 1,
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
has2faEnabled() {
|
||||
return Accounts._is2faEnabledForUser();
|
||||
},
|
||||
});
|
||||
|
||||
Accounts.addAutopublishFields({
|
||||
forLoggedInUser: ['services.twoFactorAuthentication.type'],
|
||||
});
|
||||
7
packages/accounts-2fa/README.md
Normal file
7
packages/accounts-2fa/README.md
Normal 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.
|
||||
14
packages/accounts-2fa/client_tests.js
Normal file
14
packages/accounts-2fa/client_tests.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { Random } from 'meteor/random';
|
||||
|
||||
Tinytest.addAsync('account - 2fa - has2faEnabled - client', (test, done) => {
|
||||
Accounts.createUser({
|
||||
username: Random.id(),
|
||||
password: Random.id(),
|
||||
});
|
||||
|
||||
Accounts.has2faEnabled((error, result) => {
|
||||
test.isFalse(result);
|
||||
done();
|
||||
});
|
||||
});
|
||||
37
packages/accounts-2fa/package.js
Normal file
37
packages/accounts-2fa/package.js
Normal file
@@ -0,0 +1,37 @@
|
||||
Package.describe({
|
||||
version: '2.0.1',
|
||||
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.use('check', 'server');
|
||||
|
||||
api.addFiles(['2fa-client.js'], 'client');
|
||||
api.addFiles(['2fa-server.js'], 'server');
|
||||
});
|
||||
|
||||
Package.onTest(function(api) {
|
||||
api.use([
|
||||
'accounts-base',
|
||||
'accounts-password',
|
||||
'ecmascript',
|
||||
'tinytest',
|
||||
'random',
|
||||
'accounts-2fa',
|
||||
]);
|
||||
|
||||
api.mainModule('server_tests.js', 'server');
|
||||
api.mainModule('client_tests.js', 'client');
|
||||
});
|
||||
28
packages/accounts-2fa/server_tests.js
Normal file
28
packages/accounts-2fa/server_tests.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { Random } from 'meteor/random';
|
||||
|
||||
const findUserById = id => Meteor.users.findOne(id);
|
||||
|
||||
Tinytest.add('account - 2fa - has2faEnabled - server', test => {
|
||||
// Create users
|
||||
const userWithout2FA = Accounts.insertUserDoc(
|
||||
{},
|
||||
{ emails: [{ address: `${Random.id()}@meteorapp.com`, verified: true }] }
|
||||
);
|
||||
const userWith2FA = Accounts.insertUserDoc(
|
||||
{},
|
||||
{
|
||||
emails: [{ address: `${Random.id()}@meteorapp.com`, verified: true }],
|
||||
services: {
|
||||
twoFactorAuthentication: { type: 'otp', secret: 'superSecret' },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
test.equal(Accounts._check2faEnabled(findUserById(userWithout2FA)), false);
|
||||
test.equal(Accounts._check2faEnabled(findUserById(userWith2FA)), true);
|
||||
|
||||
// cleanup
|
||||
Accounts.users.remove(userWithout2FA);
|
||||
Accounts.users.remove(userWith2FA);
|
||||
});
|
||||
@@ -31,6 +31,10 @@ export class AccountsClient extends AccountsCommon {
|
||||
|
||||
// This is for .registerClientLoginFunction & .callLoginFunction.
|
||||
this._loginFuncs = {};
|
||||
|
||||
// This tracks whether callbacks registered with
|
||||
// Accounts.onLogin have been called
|
||||
this._loginCallbacksCalled = false;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -119,6 +123,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
wait: true
|
||||
}, (error, result) => {
|
||||
this._loggingOut.set(false);
|
||||
this._loginCallbacksCalled = false;
|
||||
if (error) {
|
||||
callback && callback(error);
|
||||
} else {
|
||||
@@ -202,7 +207,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
// logged in, or with the error on error.
|
||||
//
|
||||
callLoginMethod(options) {
|
||||
options = {
|
||||
options = {
|
||||
methodName: 'login',
|
||||
methodArguments: [{}],
|
||||
_suppressLoggingIn: false,
|
||||
@@ -216,11 +221,12 @@ export class AccountsClient extends AccountsCommon {
|
||||
options[f] = () => null;
|
||||
})
|
||||
|
||||
// Prepare callbacks: user provided and onLogin/onLoginFailure hooks.
|
||||
let called;
|
||||
// Prepare callbacks: user provided and onLogin/onLoginFailure hooks.
|
||||
const loginCallbacks = ({ error, loginDetails }) => {
|
||||
if (!called) {
|
||||
called = true;
|
||||
this._loginCallbacksCalled = true;
|
||||
if (!error) {
|
||||
this._onLoginHook.each(callback => {
|
||||
callback(loginDetails);
|
||||
@@ -355,7 +361,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
|
||||
// Make the client logged in. (The user data should already be loaded!)
|
||||
this.makeClientLoggedIn(result.id, result.token, result.tokenExpires);
|
||||
loginCallbacks({ loginDetails: { type: result.type } });
|
||||
loginCallbacks({ loginDetails: result });
|
||||
};
|
||||
|
||||
if (!options._suppressLoggingIn) {
|
||||
@@ -380,7 +386,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
this.connection.setUserId(null);
|
||||
this._reconnectStopper && this._reconnectStopper.stop();
|
||||
}
|
||||
|
||||
|
||||
makeClientLoggedIn(userId, token, tokenExpires) {
|
||||
this._storeLoginToken(userId, token, tokenExpires);
|
||||
this.connection.setUserId(userId);
|
||||
@@ -443,7 +449,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
// before callbacks are registered see #10157
|
||||
_startupCallback(callback) {
|
||||
// Are we already logged in?
|
||||
if (this.connection._userId) {
|
||||
if (this._loginCallbacksCalled) {
|
||||
// If already logged in before handler is registered, it's safe to
|
||||
// assume type is a 'resume', so we execute the callback at the end
|
||||
// of the queue so that Meteor.startup can complete before any
|
||||
@@ -635,14 +641,14 @@ export class AccountsClient extends AccountsCommon {
|
||||
_initUrlMatching() {
|
||||
// By default, allow the autologin process to happen.
|
||||
this._autoLoginEnabled = true;
|
||||
|
||||
|
||||
// We only support one callback per URL.
|
||||
this._accountsCallbacks = {};
|
||||
|
||||
|
||||
// Try to match the saved value of window.location.hash.
|
||||
this._attemptToMatchHash();
|
||||
};
|
||||
|
||||
|
||||
// Separate out this functionality for testing
|
||||
_attemptToMatchHash() {
|
||||
attemptToMatchHash(this, this.savedHash, defaultSuccessHandler);
|
||||
@@ -731,8 +737,8 @@ export class AccountsClient extends AccountsCommon {
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary True if a login method (such as `Meteor.loginWithPassword`,
|
||||
* `Meteor.loginWithFacebook`, or `Accounts.createUser`) is currently in
|
||||
* @summary True if a login method (such as `Meteor.loginWithPassword`,
|
||||
* `Meteor.loginWithFacebook`, or `Accounts.createUser`) is currently in
|
||||
* progress. A reactive data source.
|
||||
* @locus Client
|
||||
* @importFromPackage meteor
|
||||
@@ -740,7 +746,7 @@ export class AccountsClient extends AccountsCommon {
|
||||
Meteor.loggingIn = () => Accounts.loggingIn();
|
||||
|
||||
/**
|
||||
* @summary True if a logout method (such as `Meteor.logout`) is currently in
|
||||
* @summary True if a logout method (such as `Meteor.logout`) is currently in
|
||||
* progress. A reactive data source.
|
||||
* @locus Client
|
||||
* @importFromPackage meteor
|
||||
@@ -766,7 +772,7 @@ Meteor.logoutOtherClients = callback => Accounts.logoutOtherClients(callback);
|
||||
/**
|
||||
* @summary Login with a Meteor access token.
|
||||
* @locus Client
|
||||
* @param {Object} [token] Local storage token for use with login across
|
||||
* @param {Object} [token] Local storage token for use with login across
|
||||
* multiple tabs in the same browser.
|
||||
* @param {Function} [callback] Optional callback. Called with no arguments on
|
||||
* success.
|
||||
@@ -815,7 +821,7 @@ if (Package.blaze) {
|
||||
* @summary Calls [Meteor.loggingIn()](#meteor_loggingin) or [Meteor.loggingOut()](#meteor_loggingout).
|
||||
*/
|
||||
Template.registerHelper(
|
||||
'loggingInOrOut',
|
||||
'loggingInOrOut',
|
||||
() => Meteor.loggingIn() || Meteor.loggingOut()
|
||||
);
|
||||
}
|
||||
@@ -872,6 +878,6 @@ const attemptToMatchHash = (accounts, hash, success) => {
|
||||
|
||||
// Export for testing
|
||||
export const AccountsTest = {
|
||||
attemptToMatchHash: (hash, success) =>
|
||||
attemptToMatchHash: (hash, success) =>
|
||||
attemptToMatchHash(Accounts, hash, success),
|
||||
};
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
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,
|
||||
[defaultExcludeField]: excludeValue,
|
||||
}
|
||||
};
|
||||
|
||||
const logoutAndCreateUser = (test, done, nextTests) => {
|
||||
Meteor.logout(() => {
|
||||
@@ -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',
|
||||
{ selector: { 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((err, isEnabled) => {
|
||||
test.isTrue(isEnabled);
|
||||
// disable 2fa
|
||||
Accounts.disableUser2fa(() => {
|
||||
// verifies if 2fa is disabled
|
||||
Accounts.has2faEnabled((err, isEnabled) => {
|
||||
test.isFalse(!!isEnabled);
|
||||
removeTestUser(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -765,13 +765,22 @@ export class AccountsServer extends AccountsCommon {
|
||||
// Use Meteor.startup to give other packages a chance to call
|
||||
// setDefaultPublishFields.
|
||||
Meteor.startup(() => {
|
||||
// Merge custom fields selector and default publish fields so that the client
|
||||
// gets all the necessary fields to run properly
|
||||
const customFields = this._addDefaultFieldSelector().fields || {};
|
||||
const keys = Object.keys(customFields);
|
||||
// If the custom fields are negative, then ignore them and only send the necessary fields
|
||||
const fields = keys.length > 0 && customFields[keys[0]] ? {
|
||||
...this._addDefaultFieldSelector().fields,
|
||||
..._defaultPublishFields.projection
|
||||
} : _defaultPublishFields.projection
|
||||
// Publish the current user's record to the client.
|
||||
this._server.publish(null, function () {
|
||||
if (this.userId) {
|
||||
return users.find({
|
||||
_id: this.userId
|
||||
}, {
|
||||
fields: _defaultPublishFields.projection,
|
||||
fields,
|
||||
});
|
||||
} else {
|
||||
return null;
|
||||
@@ -1468,9 +1477,9 @@ export class AccountsServer extends AccountsCommon {
|
||||
return userId;
|
||||
}
|
||||
|
||||
_handleError = (msg, throwError = true) => {
|
||||
_handleError = (msg, throwError = true, errorCode = 403) => {
|
||||
const error = new Meteor.Error(
|
||||
403,
|
||||
errorCode,
|
||||
this._options.ambiguousErrorMessages
|
||||
? "Something went wrong. Please check your credentials."
|
||||
: msg
|
||||
|
||||
@@ -13,7 +13,7 @@ Meteor.methods({
|
||||
// *are* validated, but Accounts._options is global state which makes this hard
|
||||
// (impossible?)
|
||||
Tinytest.add(
|
||||
'accounts - config validates keys',
|
||||
'accounts - config validates keys',
|
||||
test => test.throws(() => Accounts.config({foo: "bar"}))
|
||||
);
|
||||
|
||||
@@ -202,7 +202,7 @@ Tinytest.add('accounts - insertUserDoc username', test => {
|
||||
|
||||
// run the hook again. now the user exists, so it throws an error.
|
||||
test.throws(
|
||||
() => Accounts.insertUserDoc({profile: {name: 'Foo Bar'}}, userIn),
|
||||
() => Accounts.insertUserDoc({profile: {name: 'Foo Bar'}}, userIn),
|
||||
'Username already exists.'
|
||||
);
|
||||
|
||||
@@ -238,13 +238,13 @@ Tinytest.add('accounts - insertUserDoc email', test => {
|
||||
);
|
||||
|
||||
// now with only one of them.
|
||||
test.throws(() =>
|
||||
Accounts.insertUserDoc({}, {emails: [{address: email1}]}),
|
||||
test.throws(() =>
|
||||
Accounts.insertUserDoc({}, {emails: [{address: email1}]}),
|
||||
'Email already exists.'
|
||||
);
|
||||
|
||||
test.throws(() =>
|
||||
Accounts.insertUserDoc({}, {emails: [{address: email2}]}),
|
||||
test.throws(() =>
|
||||
Accounts.insertUserDoc({}, {emails: [{address: email2}]}),
|
||||
'Email already exists.'
|
||||
);
|
||||
|
||||
@@ -452,14 +452,14 @@ Tinytest.add(
|
||||
test.equal(Meteor.userId(), validateAttemptExpectedUserId, "validateLoginAttempt");
|
||||
return true;
|
||||
});
|
||||
const onLoginStopper = Accounts.onLogin(attempt =>
|
||||
const onLoginStopper = Accounts.onLogin(attempt =>
|
||||
test.equal(Meteor.userId(), onLoginExpectedUserId, "onLogin")
|
||||
);
|
||||
const onLogoutStopper = Accounts.onLogout(logoutContext => {
|
||||
test.equal(logoutContext.user._id, onLogoutExpectedUserId, "onLogout");
|
||||
test.instanceOf(logoutContext.connection, Object);
|
||||
});
|
||||
const onLoginFailureStopper = Accounts.onLoginFailure(attempt =>
|
||||
const onLoginFailureStopper = Accounts.onLoginFailure(attempt =>
|
||||
test.equal(Meteor.userId(), onLoginFailureExpectedUserId, "onLoginFailure")
|
||||
);
|
||||
|
||||
@@ -552,7 +552,8 @@ Tinytest.add(
|
||||
'accounts - Meteor.user() obeys options.defaultFieldSelector',
|
||||
test => {
|
||||
const ignoreFieldName = "bigArray";
|
||||
const userId = Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1] });
|
||||
const customField = "customField";
|
||||
const userId = Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1], [customField]: 'test' });
|
||||
const stampedToken = Accounts._generateStampedLoginToken();
|
||||
Accounts._insertLoginToken(userId, stampedToken);
|
||||
const options = Accounts._options;
|
||||
@@ -589,6 +590,15 @@ Tinytest.add(
|
||||
test.isNotUndefined(user[ignoreFieldName], 'full selector');
|
||||
test.isNotUndefined(user.username, 'full selector username');
|
||||
|
||||
Accounts._options = {};
|
||||
|
||||
// Test that a custom field gets retrieved properly
|
||||
Accounts.config({defaultFieldSelector: {[customField]: 1}});
|
||||
user = Meteor.user()
|
||||
test.isNotUndefined(user[customField]);
|
||||
test.isUndefined(user.username);
|
||||
test.isUndefined(user[ignoreFieldName]);
|
||||
|
||||
Accounts._options = options;
|
||||
Accounts.userId = origAccountsUserId;
|
||||
}
|
||||
@@ -702,14 +712,14 @@ Tinytest.add(
|
||||
// create test user, without a google service
|
||||
const testEmail = "test@testdomain.com"
|
||||
const uid0 = Accounts.createUser({email: testEmail})
|
||||
|
||||
|
||||
// Verify that user is found from email and service merged
|
||||
Accounts.setAdditionalFindUserOnExternalLogin(({serviceName, serviceData}) => {
|
||||
if (serviceName === "google") {
|
||||
return Accounts.findUserByEmail(serviceData.email)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let googleId = Random.id();
|
||||
const uid1 = Accounts.updateOrCreateUserFromExternalService(
|
||||
'google',
|
||||
@@ -744,4 +754,4 @@ if(Meteor.isServer) {
|
||||
test.equal(enrollAccountURL.searchParams.get('test'), extraParams.test);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
const getTokenFromSecret = ({ selector, secret: secretParam }) => {
|
||||
let secret = secretParam;
|
||||
|
||||
if (!secret) {
|
||||
const { services: { twoFactorAuthentication } = {} } =
|
||||
Meteor.users.findOne(selector) || {};
|
||||
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(selector, secret) {
|
||||
Meteor.users.update(
|
||||
selector,
|
||||
{
|
||||
$set: {
|
||||
'services.twoFactorAuthentication': {
|
||||
secret,
|
||||
type: 'otp',
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
return getTokenFromSecret({ selector, secret });
|
||||
},
|
||||
getTokenFromSecret,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'A user account system',
|
||||
version: '2.2.0',
|
||||
version: '2.2.2',
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
@@ -60,6 +60,7 @@ Package.onTest(api => {
|
||||
'oauth-encryption',
|
||||
'ddp',
|
||||
'accounts-password',
|
||||
'accounts-2fa',
|
||||
]);
|
||||
|
||||
api.addFiles('accounts_tests_setup.js', 'server');
|
||||
|
||||
@@ -71,15 +71,40 @@ Meteor.startup(() => {
|
||||
// Send an OAuth login method to the server. If the user authorized
|
||||
// access in the popup this should log the user in, otherwise
|
||||
// nothing should happen.
|
||||
Accounts.oauth.tryLoginAfterPopupClosed = (credentialToken, callback) => {
|
||||
const credentialSecret = OAuth._retrieveCredentialSecret(credentialToken) || null;
|
||||
Accounts.oauth.tryLoginAfterPopupClosed = (
|
||||
credentialToken,
|
||||
callback,
|
||||
shouldRetry = true
|
||||
) => {
|
||||
const credentialSecret =
|
||||
OAuth._retrieveCredentialSecret(credentialToken);
|
||||
|
||||
// In some case the function OAuth._retrieveCredentialSecret() can return null, because the local storage might not
|
||||
// be ready. So we retry after a timeout.
|
||||
|
||||
if (!credentialSecret) {
|
||||
if (!shouldRetry) {
|
||||
return;
|
||||
}
|
||||
Meteor.setTimeout(
|
||||
() =>
|
||||
Accounts.oauth.tryLoginAfterPopupClosed(
|
||||
credentialToken,
|
||||
callback,
|
||||
false
|
||||
),
|
||||
500
|
||||
);
|
||||
return;
|
||||
}
|
||||
// continue with the rest of the function
|
||||
Accounts.callLoginMethod({
|
||||
methodArguments: [{oauth: { credentialToken, credentialSecret }}],
|
||||
methodArguments: [{ oauth: { credentialToken, credentialSecret } }],
|
||||
userCallback: callback && (err => callback(convertError(err))),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Accounts.oauth.credentialRequestCompleteHandler = callback =>
|
||||
Accounts.oauth.credentialRequestCompleteHandler = callback =>
|
||||
credentialTokenOrError => {
|
||||
if(credentialTokenOrError && credentialTokenOrError instanceof Error) {
|
||||
callback && callback(credentialTokenOrError);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: "Common code for OAuth-based login services",
|
||||
version: "1.4.0",
|
||||
version: "1.4.1",
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
|
||||
@@ -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.1',
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
|
||||
@@ -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.
|
||||
|
||||
/**
|
||||
|
||||
@@ -169,7 +169,8 @@ Accounts.registerLoginHandler("password", options => {
|
||||
|
||||
check(options, {
|
||||
user: Accounts._userQueryValidator,
|
||||
password: passwordValidator
|
||||
password: passwordValidator,
|
||||
code: Match.Optional(NonEmptyString),
|
||||
});
|
||||
|
||||
|
||||
@@ -181,15 +182,33 @@ Accounts.registerLoginHandler("password", options => {
|
||||
Accounts._handleError("User not found");
|
||||
}
|
||||
|
||||
|
||||
if (!user.services || !user.services.password ||
|
||||
!user.services.password.bcrypt) {
|
||||
Accounts._handleError("User has no password set");
|
||||
}
|
||||
|
||||
return checkPassword(
|
||||
user,
|
||||
options.password
|
||||
);
|
||||
const result = checkPassword(user, options.password);
|
||||
// This method is added by the package accounts-2fa
|
||||
// First the login is validated, then the code situation is checked
|
||||
if (
|
||||
!result.error &&
|
||||
Accounts._check2faEnabled?.(user)
|
||||
) {
|
||||
if (!options.code) {
|
||||
Accounts._handleError('2FA code must be informed', true, 'no-2fa-code');
|
||||
}
|
||||
if (
|
||||
!Accounts._isTokenValid(
|
||||
user.services.twoFactorAuthentication.secret,
|
||||
options.code
|
||||
)
|
||||
) {
|
||||
Accounts._handleError('Invalid 2FA code', true, 'invalid-2fa-code');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
///
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'No-password login/sign-up support for accounts',
|
||||
version: '2.0.0',
|
||||
version: '2.1.1',
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
|
||||
@@ -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 });
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -87,6 +88,25 @@ Accounts.registerLoginHandler('passwordless', options => {
|
||||
const { verifiedEmail, error } = result;
|
||||
|
||||
if (!error && verifiedEmail) {
|
||||
// This method is added by the package accounts-2fa
|
||||
if (Accounts._check2faEnabled?.(user)) {
|
||||
if (!options.code) {
|
||||
Accounts._handleError('2FA code must be informed', true, 'no-2fa-code');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!Accounts._isTokenValid(
|
||||
user.services.twoFactorAuthentication.secret,
|
||||
options.code
|
||||
)
|
||||
) {
|
||||
Accounts._handleError('Invalid 2FA code', true, 'invalid-2fa-code');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// It's necessary to make sure we don't remove the token if the user has 2fa enabled
|
||||
// otherwise, it would be necessary to generate a new one if this method is called without
|
||||
// a 2fa code
|
||||
Meteor.users.update(
|
||||
{ _id: user._id, 'emails.address': verifiedEmail },
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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] =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'Unstyled version of login widgets',
|
||||
version: '1.6.0',
|
||||
version: '1.7.0',
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
|
||||
@@ -194,7 +194,10 @@ CollectionPrototype._defineMutationMethods = function(options) {
|
||||
} catch (e) {
|
||||
if (
|
||||
e.name === 'MongoError' ||
|
||||
// for old versions of MongoDB (probably not necessary but it's here just in case)
|
||||
e.name === 'BulkWriteError' ||
|
||||
// for newer versions of MongoDB (https://docs.mongodb.com/drivers/node/current/whats-new/#bulkwriteerror---mongobulkwriteerror)
|
||||
e.name === 'MongoBulkWriteError' ||
|
||||
e.name === 'MinimongoError'
|
||||
) {
|
||||
throw new Meteor.Error(409, e.toString());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
name: 'allow-deny',
|
||||
version: '1.1.0',
|
||||
version: '1.1.1',
|
||||
// Brief, one-line summary of the package.
|
||||
summary: 'Implements functionality for allow/deny and client-side db operations',
|
||||
// URL to the Git repository containing the source code for this package.
|
||||
|
||||
541
packages/babel-compiler/.npm/package/npm-shrinkwrap.json
generated
541
packages/babel-compiler/.npm/package/npm-shrinkwrap.json
generated
@@ -1,20 +1,25 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
|
||||
"integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg=="
|
||||
},
|
||||
"@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.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz",
|
||||
"integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==",
|
||||
"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.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz",
|
||||
"integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg=="
|
||||
},
|
||||
"@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.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz",
|
||||
"integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ=="
|
||||
},
|
||||
"@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.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz",
|
||||
"integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA=="
|
||||
},
|
||||
"@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.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz",
|
||||
"integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw=="
|
||||
},
|
||||
"@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.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz",
|
||||
"integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg=="
|
||||
},
|
||||
"@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.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz",
|
||||
"integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ=="
|
||||
},
|
||||
"@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.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
||||
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw=="
|
||||
},
|
||||
"@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.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
|
||||
"integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw=="
|
||||
},
|
||||
"@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.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew=="
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
|
||||
"integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg=="
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
|
||||
"integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ=="
|
||||
},
|
||||
"@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.1",
|
||||
"resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.16.0-beta.1.tgz",
|
||||
"integrity": "sha512-PSyp2+oO2nrGMBTXd3VAP0EzHLW4bFqRIzmbTfHnr/s0dGhb7XaaGg3sOGAInewrFNCWfMHNe3hSiyOvC9bS2A=="
|
||||
},
|
||||
"@meteorjs/reify": {
|
||||
"version": "0.23.0",
|
||||
@@ -416,9 +436,9 @@
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.50",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
|
||||
"integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw=="
|
||||
"version": "0.0.51",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
|
||||
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ=="
|
||||
},
|
||||
"acorn": {
|
||||
"version": "6.4.2",
|
||||
@@ -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",
|
||||
@@ -611,9 +631,9 @@
|
||||
"integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg=="
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
|
||||
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A=="
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.2.tgz",
|
||||
"integrity": "sha512-97XU1CTZ5TwU9Qy/Taj+RtiI6SQM1WIhZ9osT7EY0oO2aWXGABZT2OZeRL+6PfaQsiiMIjjwIoYFPq4APgspgQ=="
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
@@ -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.30001312",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
|
||||
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
|
||||
},
|
||||
"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.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz",
|
||||
"integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==",
|
||||
"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.71",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz",
|
||||
"integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw=="
|
||||
},
|
||||
"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",
|
||||
@@ -783,9 +803,9 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
|
||||
"integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
|
||||
"integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg=="
|
||||
},
|
||||
"object-keys": {
|
||||
"version": "1.1.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",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Package.describe({
|
||||
name: "babel-compiler",
|
||||
summary: "Parser/transpiler for ECMAScript 2015+ syntax",
|
||||
version: '7.8.0'
|
||||
version: '7.9.0'
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
'@meteorjs/babel': '7.15.0',
|
||||
'@meteorjs/babel': '7.16.0-beta.1',
|
||||
'json5': '2.1.1'
|
||||
});
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ export const Match = {
|
||||
_failIfArgumentsAreNotAllChecked(f, context, args, description) {
|
||||
const argChecker = new ArgumentChecker(args, description);
|
||||
const result = currentArgumentChecker.withValue(
|
||||
argChecker,
|
||||
argChecker,
|
||||
() => f.apply(context, args)
|
||||
);
|
||||
|
||||
@@ -261,7 +261,7 @@ const testSubtree = (value, pattern) => {
|
||||
if (typeof value === 'number' && (value | 0) === value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
message: `Expected Integer, got ${stringForErrorMessage(value)}`,
|
||||
path: '',
|
||||
@@ -296,7 +296,7 @@ const testSubtree = (value, pattern) => {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ const testSubtree = (value, pattern) => {
|
||||
if (!(err instanceof Match.Error)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
message: err.message,
|
||||
path: err.path
|
||||
|
||||
@@ -30,7 +30,7 @@ When using the sockjs transport, `ddp` has some special functionality to get aro
|
||||
|
||||
### Notable features
|
||||
|
||||
**Database driver integration.** `ddp` works well with the Meteor Project's [full-stack database drivers](https://www.meteor.com/full-stack-db-drivers). For example, if you are using the `mongo` package, then when you create a Mongo collection with `MyCollection = new Mongo.Collection("mycollection")` on the client, the Mongo driver will automatically register with `ddp` to receive incoming data for `mycollection` and use it to keep `MyCollection` up to date. In other words, it automatically wires up replication for all of your remote collections.
|
||||
**Database driver integration.** `ddp` works well with the Mongo [database drivers](https://docs.meteor.com/api/collections.html). For example, if you are using the `mongo` package, then when you create a Mongo collection with `MyCollection = new Mongo.Collection("mycollection")` on the client, the Mongo driver will automatically register with `ddp` to receive incoming data for `mycollection` and use it to keep `MyCollection` up to date. In other words, it automatically wires up replication for all of your remote collections.
|
||||
|
||||
**Automatic latency compensation.** `ddp` includes a full
|
||||
implementation of fine-grained latency compensation, so users see
|
||||
@@ -41,14 +41,14 @@ as necessary.
|
||||
|
||||
**Transparent reconnection.** If the DDP client loses its connection to the server, it will automatically reconnect, transparently to the application. Any subscriptions will be re-established and resynchronized without disturbing the application, and any outstanding method calls will be retried. However, this retrying could lead to duplicate method calls if the connection is lost after the server has received the method call, but before the client reads the result. This can be avoided just as it is with REST, by including a unique code as a parameter to the method. A future version of DDP will solve this on the protocol level (see Future Work).
|
||||
|
||||
**Authentication.** `ddp`'s authentication hooks work great with [Meteor Accounts](https://www.meteor.com/accounts), a set of packages which provides a full suite of authentication functionality, from password-based accounts with email verification and password recovery, to OAuth login using services like Facebook and Twitter.
|
||||
**Authentication.** `ddp`'s authentication hooks work great with [Meteor Accounts](https://docs.meteor.com/api/accounts.html), a set of packages which provides a full suite of authentication functionality, from password-based accounts with email verification and password recovery, to OAuth login using services like Facebook and Twitter.
|
||||
|
||||
**Input sanitization.** On the server, you can use the `check` function, provided by the [match](https://atmospherejs.com/meteor/match) package, to easily validate the types of arguments passed by the client. Using a simple pattern language, you can also `check` whether objects have the expected keps and array elements have the right type. In production code, add the [audit-argument-checks](https://atmospherejs.com/meteor/audit-argument-checks) package, and `ddp` will make sure that every value passed from the client is validated with `check`, and throw an exception if not. But be careful. The check only happens after the code has run, so while it will catch the vast majority of sanitization failures, it's not a perfect guarantee of safety.
|
||||
|
||||
**Tracker-aware.** `ddp` obeys the simple [Tracker](https://www.meteor.com/tracker) convention for transparent reactivity. Values such as the current connection status (are we online?), subscription readiness (is the `newsFeed` done loading or should we show a progress indicator?), and the currently logged-in user (what username should we show in the status area at the top of page?) all work as reactive variables.
|
||||
**Tracker-aware.** `ddp` obeys the simple [Tracker](https://docs.meteor.com/api/tracker.html) convention for transparent reactivity. Values such as the current connection status (are we online?), subscription readiness (is the `newsFeed` done loading or should we show a progress indicator?), and the currently logged-in user (what username should we show in the status area at the top of page?) all work as reactive variables.
|
||||
|
||||
**Default connection.** Normally you open a DDP connection with `myconn = DDP.connect(url)`, and then work with the connection with calls like `myconn.subscribe("newsFeed")` or `myconn.call("transferBalance")`. But if you build and deploy your app with the other Meteor tools, then a DDP server instance is automatically set up on the server, and each client is configured to automatically open a connection to that server on startup. You can work then with this "default connection" and "default server" with easy aliases like `Meteor.subscribe` and `Meteor.call`.
|
||||
|
||||
**Connection lifecycle hooks.** Servers can run code when connections are established or closed. This can be used to update the database to show which users are online, making it easily to create presence features like a live-updating "Friends Online Now" list.
|
||||
|
||||
**CRUD boilerplate and quickstart packages.** The [full-stack database drivers](https://www.meteor.com/full-stack-db-drivers) provide some helpful functionality that is worth mentioning here, even though it is actually part of those database packages, not `ddp`. They provide general-purpose `create`, `update`, and `delete` methods for each database collection, so that it is not necessary to write methods for basic CRUD operations. A system of `allow` and `deny` rules is used to control what each user can do. And two "quickstart" packages are provided, for quick prototyping and to help new developers learn Meteor. The `insecure` package turns off `allow`/`deny` rule checking for the generic `create`, `update`, and `delete` methods. The `autopublish` package automatically subscribes every connected client to the full contents of every database collection.
|
||||
**CRUD boilerplate and quickstart packages.** The [full-stack database drivers](https://docs.meteor.com/api/collections.html) provide some helpful functionality that is worth mentioning here, even though it is actually part of those database packages, not `ddp`. They provide general-purpose `create`, `update`, and `delete` methods for each database collection, so that it is not necessary to write methods for basic CRUD operations. A system of `allow` and `deny` rules is used to control what each user can do. And two "quickstart" packages are provided, for quick prototyping and to help new developers learn Meteor. The `insecure` package turns off `allow`/`deny` rule checking for the generic `create`, `update`, and `delete` methods. The `autopublish` package automatically subscribes every connected client to the full contents of every database collection.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
name: 'ecmascript',
|
||||
version: '0.16.1',
|
||||
version: '0.16.2',
|
||||
summary: 'Compiler plugin that supports ES2015+ in all .js files',
|
||||
documentation: 'README.md',
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'Extended and Extensible JSON library',
|
||||
version: '1.1.1'
|
||||
version: '1.1.2'
|
||||
});
|
||||
|
||||
Package.onUse(function onUse(api) {
|
||||
|
||||
@@ -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.
|
||||
@@ -57,7 +62,10 @@ const makeTransport = function (mailUrlString) {
|
||||
// More info: https://nodemailer.com/smtp/well-known/
|
||||
const knownHostsTransport = function(settings = undefined, url = undefined) {
|
||||
let service, user, password;
|
||||
if (url && !settings) {
|
||||
|
||||
const hasSettings = settings && Object.keys(settings).length;
|
||||
|
||||
if (url && !hasSettings) {
|
||||
let host = url.split(':')[0];
|
||||
const urlObject = new URL(url);
|
||||
if (host === 'http' || host === 'https') {
|
||||
@@ -84,15 +92,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 +116,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 +141,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 +186,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 +231,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 +249,19 @@ Email.send = function (options) {
|
||||
customTransport({ packageSettings, ...options });
|
||||
return;
|
||||
}
|
||||
if (Meteor.isProduction || process.env.MAIL_URL || Meteor.settings.packages?.email) {
|
||||
|
||||
const mailUrlEnv = process.env.MAIL_URL;
|
||||
const mailUrlSettings = Meteor.settings.packages?.email;
|
||||
|
||||
if (Meteor.isProduction && !mailUrlEnv && !mailUrlSettings) {
|
||||
// This check is mostly necessary when using the flag --production when running locally.
|
||||
// And it works as a reminder to properly set the mail URL when running locally.
|
||||
throw new Error(
|
||||
'You have not provided a mail URL. You can provide it by using the environment variable MAIL_URL or your settings. You can read more about it here: https://docs.meteor.com/api/email.html.'
|
||||
);
|
||||
}
|
||||
|
||||
if (mailUrlEnv || mailUrlSettings) {
|
||||
const transport = getTransport();
|
||||
smtpSend(transport, options);
|
||||
return;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
Package.describe({
|
||||
summary: "Send email messages",
|
||||
version: "2.2.0"
|
||||
summary: 'Send email messages',
|
||||
version: '2.2.1',
|
||||
});
|
||||
|
||||
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');
|
||||
|
||||
@@ -30,7 +30,7 @@ Facebook.requestCredential = (options, credentialRequestCompleteCallback) => {
|
||||
|
||||
const loginStyle = OAuth._loginStyle('facebook', config, options);
|
||||
|
||||
const API_VERSION = Meteor.settings?.public?.packages?.['facebook-oauth']?.apiVersion || '10.0';
|
||||
const API_VERSION = Meteor.settings?.public?.packages?.['facebook-oauth']?.apiVersion || '13.0';
|
||||
|
||||
let loginUrl =
|
||||
`https://www.facebook.com/v${API_VERSION}/dialog/oauth?client_id=${config.appId}` +
|
||||
|
||||
@@ -2,7 +2,7 @@ Facebook = {};
|
||||
import crypto from 'crypto';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
|
||||
const API_VERSION = Meteor.settings?.public?.packages?.['facebook-oauth']?.apiVersion || '10.0';
|
||||
const API_VERSION = Meteor.settings?.public?.packages?.['facebook-oauth']?.apiVersion || '13.0';
|
||||
|
||||
Facebook.handleAuthFromAccessToken = (accessToken, expiresAt) => {
|
||||
// include basic fields from facebook
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: "Facebook OAuth flow",
|
||||
version: "1.10.0"
|
||||
version: "1.11.0"
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
|
||||
@@ -25,12 +25,18 @@ Github.requestCredential = (options, credentialRequestCompleteCallback) => {
|
||||
|
||||
const loginStyle = OAuth._loginStyle('github', config, options);
|
||||
|
||||
let allowSignup = '';
|
||||
if (Accounts._options?.forbidClientAccountCreation) {
|
||||
allowSignup = '&allow_signup=false'; // https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps#parameters
|
||||
}
|
||||
|
||||
const loginUrl =
|
||||
'https://github.com/login/oauth/authorize' +
|
||||
`?client_id=${config.clientId}` +
|
||||
`&scope=${flatScope}` +
|
||||
`&redirect_uri=${OAuth._redirectUri('github', config)}` +
|
||||
`&state=${OAuth._stateParam(loginStyle, credentialToken, options && options.redirectUrl)}`;
|
||||
`&state=${OAuth._stateParam(loginStyle, credentialToken, options && options.redirectUrl)}` +
|
||||
allowSignup;
|
||||
|
||||
OAuth.launchLogin({
|
||||
loginService: "github",
|
||||
|
||||
@@ -15,6 +15,12 @@ OAuth.registerService('github', 2, null, (query) => {
|
||||
accessToken: OAuth.sealSecret(accessToken),
|
||||
email: identity.email || (primaryEmail && primaryEmail.email) || '',
|
||||
username: identity.login,
|
||||
name: identity.name,
|
||||
avatar: identity.avatar_url,
|
||||
company: identity.company,
|
||||
blog: identity.blog,
|
||||
location: identity.location,
|
||||
bio: identity.bio,
|
||||
emails
|
||||
},
|
||||
options: { profile: { name: identity.name } }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'GitHub OAuth flow',
|
||||
version: '1.3.2'
|
||||
version: '1.4.0'
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Google from './namespace.js';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { fetch } from 'meteor/fetch';
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
@@ -9,8 +10,26 @@ Google.whitelistedFields = ['id', 'email', 'verified_email', 'name', 'given_name
|
||||
|
||||
const getServiceDataFromTokens = tokens => {
|
||||
const { accessToken, idToken } = tokens;
|
||||
const scopes = getScopes(accessToken);
|
||||
const identity = getIdentity(accessToken);
|
||||
const scopesCall = Meteor.wrapAsync(getScopes);
|
||||
let scopes;
|
||||
try {
|
||||
scopes = scopesCall(accessToken);
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to fetch tokeninfo from Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
const identityCall = Meteor.wrapAsync(getIdentity);
|
||||
let identity;
|
||||
try {
|
||||
identity = identityCall(accessToken);
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to fetch identity from Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
const serviceData = {
|
||||
accessToken,
|
||||
idToken,
|
||||
@@ -46,7 +65,7 @@ const getServiceDataFromTokens = tokens => {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Accounts.registerLoginHandler(request => {
|
||||
if (request.googleSignIn !== true) {
|
||||
@@ -65,7 +84,15 @@ Accounts.registerLoginHandler(request => {
|
||||
}));
|
||||
}
|
||||
|
||||
const result = getServiceDataFromTokens(tokens);
|
||||
let result;
|
||||
try {
|
||||
result = getServiceDataFromTokens(tokens);
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to complete OAuth handshake with Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
|
||||
return Accounts.updateOrCreateUserFromExternalService("google", {
|
||||
id: request.userId,
|
||||
@@ -77,72 +104,89 @@ Accounts.registerLoginHandler(request => {
|
||||
}, result.options);
|
||||
});
|
||||
|
||||
const getServiceData = query => getServiceDataFromTokens(getTokens(query));
|
||||
|
||||
OAuth.registerService('google', 2, null, getServiceData);
|
||||
|
||||
// returns an object containing:
|
||||
// - accessToken
|
||||
// - expiresIn: lifetime of token in seconds
|
||||
// - refreshToken, if this is the first authorization request
|
||||
const getTokens = query => {
|
||||
const getTokens = async (query, callback) => {
|
||||
const config = ServiceConfiguration.configurations.findOne({service: 'google'});
|
||||
if (!config)
|
||||
throw new ServiceConfiguration.ConfigError();
|
||||
|
||||
const content = new URLSearchParams({
|
||||
code: query.code,
|
||||
client_id: config.clientId,
|
||||
client_secret: OAuth.openSecret(config.secret),
|
||||
redirect_uri: OAuth._redirectUri('google', config),
|
||||
grant_type: 'authorization_code'
|
||||
});
|
||||
const request = await fetch(
|
||||
"https://accounts.google.com/o/oauth2/token", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: content,
|
||||
});
|
||||
const response = await request.json();
|
||||
|
||||
if (response.error) { // if the http response was a json object with an error attribute
|
||||
callback(response.error);
|
||||
throw new Meteor.Error(`Failed to complete OAuth handshake with Google. ${response.error}`);
|
||||
} else {
|
||||
const data = {
|
||||
accessToken: response.access_token,
|
||||
refreshToken: response.refresh_token,
|
||||
expiresIn: response.expires_in,
|
||||
idToken: response.id_token
|
||||
};
|
||||
callback(undefined, data);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
const getTokensCall = Meteor.wrapAsync(getTokens);
|
||||
const getServiceData = query => getServiceDataFromTokens(getTokensCall(query));
|
||||
|
||||
OAuth.registerService('google', 2, null, getServiceData);
|
||||
|
||||
const getIdentity = async (accessToken, callback) => {
|
||||
const content = new URLSearchParams({ access_token: accessToken });
|
||||
let response;
|
||||
try {
|
||||
response = HTTP.post(
|
||||
"https://accounts.google.com/o/oauth2/token", {params: {
|
||||
code: query.code,
|
||||
client_id: config.clientId,
|
||||
client_secret: OAuth.openSecret(config.secret),
|
||||
redirect_uri: OAuth._redirectUri('google', config),
|
||||
grant_type: 'authorization_code'
|
||||
}});
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to complete OAuth handshake with Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
|
||||
if (response.data.error) { // if the http response was a json object with an error attribute
|
||||
throw new Error(`Failed to complete OAuth handshake with Google. ${response.data.error}`);
|
||||
} else {
|
||||
return {
|
||||
accessToken: response.data.access_token,
|
||||
refreshToken: response.data.refresh_token,
|
||||
expiresIn: response.data.expires_in,
|
||||
idToken: response.data.id_token
|
||||
};
|
||||
const request = await fetch(
|
||||
`https://www.googleapis.com/oauth2/v1/userinfo?${content.toString()}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: { Accept: 'application/json' }
|
||||
});
|
||||
response = await request.json();
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
throw new Meteor.Error(e.reason);
|
||||
}
|
||||
callback(undefined, response);
|
||||
return response;
|
||||
};
|
||||
|
||||
const getIdentity = accessToken => {
|
||||
const getScopes = async (accessToken, callback) => {
|
||||
const content = new URLSearchParams({ access_token: accessToken });
|
||||
let response;
|
||||
try {
|
||||
return HTTP.get(
|
||||
"https://www.googleapis.com/oauth2/v1/userinfo",
|
||||
{params: {access_token: accessToken}}).data;
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to fetch identity from Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getScopes = accessToken => {
|
||||
try {
|
||||
return HTTP.get(
|
||||
"https://www.googleapis.com/oauth2/v1/tokeninfo",
|
||||
{params: {access_token: accessToken}}).data.scope.split(' ');
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to fetch tokeninfo from Google. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
const request = await fetch(
|
||||
`https://www.googleapis.com/oauth2/v1/tokeninfo?${content.toString()}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: { Accept: 'application/json' }
|
||||
});
|
||||
response = await request.json();
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
throw new Meteor.Error(e.reason);
|
||||
}
|
||||
callback(undefined, response.scope.split(' '));
|
||||
return response.scope.split(' ');
|
||||
};
|
||||
|
||||
Google.retrieveCredential = (credentialToken, credentialSecret) =>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: "Google OAuth flow",
|
||||
version: "1.4.1",
|
||||
version: "1.4.2",
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
@@ -11,7 +11,7 @@ Package.onUse(api => {
|
||||
api.use("ecmascript");
|
||||
api.use('oauth2', ['client', 'server']);
|
||||
api.use('oauth', ['client', 'server']);
|
||||
api.use('http@1.4.4 || 2.0.0', ['server']);
|
||||
api.use('fetch', ['server']);
|
||||
api.use('service-configuration');
|
||||
api.use('random', 'client');
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# hot-module-replacement
|
||||
|
||||
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/hot-module-replacement) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/hot-module-replacement)
|
||||
***
|
||||
|
||||
Adds Hot Module Replacement.
|
||||
|
||||
Learn more about Hot Module Replacement in the [Meteor Guide](https://guide.meteor.com/build-tool.html#hot-module-replacement). Documentation of the package can be found in the [Meteor docs](https://docs.meteor.com/packages/hot-module-replacement.html).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
name: 'hot-module-replacement',
|
||||
version: '0.5.0',
|
||||
version: '0.5.1',
|
||||
summary: 'Update code in development without reloading the page',
|
||||
documentation: 'README.md',
|
||||
debugOnly: true,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
if (!process.env.METEOR_HMR_SECRET) {
|
||||
console.log('Restart Meteor to enable hot module replacement.');
|
||||
} else {
|
||||
// METEOR_PARENT_PID
|
||||
if (process.env.METEOR_HMR_SECRET) {
|
||||
__meteor_runtime_config__._hmrSecret = process.env.METEOR_HMR_SECRET;
|
||||
} else if (process.env.METEOR_PARENT_PID) {
|
||||
// if METEOR_PARENT_PID isn't set, then the app isn't being run by the meteor
|
||||
// tool and restarting won't enable HRM.
|
||||
console.log('Restart Meteor to enable hot module replacement.');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: 'The Meteor command-line tool',
|
||||
version: '2.5.2',
|
||||
version: '2.7.1',
|
||||
});
|
||||
|
||||
Package.includeTool();
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
|
||||
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
@@ -17,9 +22,9 @@
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.20",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz",
|
||||
"integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==",
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
@@ -29,9 +34,9 @@
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz",
|
||||
"integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ=="
|
||||
"version": "5.12.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz",
|
||||
"integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Package.describe({
|
||||
summary: "JavaScript minifier",
|
||||
version: "2.7.3"
|
||||
version: "2.7.4"
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
terser: "5.9.0"
|
||||
terser: "5.12.1"
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
@@ -857,7 +857,7 @@ export function isOperatorObject(valueSelector, inconsistentOK) {
|
||||
|
||||
let theseAreOperators = undefined;
|
||||
Object.keys(valueSelector).forEach(selKey => {
|
||||
const thisIsOperator = selKey.substr(0, 1) === '$';
|
||||
const thisIsOperator = selKey.substr(0, 1) === '$' || selKey === 'diff';
|
||||
|
||||
if (theseAreOperators === undefined) {
|
||||
theseAreOperators = thisIsOperator;
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class Cursor {
|
||||
|
||||
this.skip = options.skip || 0;
|
||||
this.limit = options.limit;
|
||||
this.fields = options.fields;
|
||||
this.fields = options.projection || options.fields;
|
||||
|
||||
this._projectionFn = LocalCollection._compileProjection(this.fields || {});
|
||||
|
||||
@@ -42,16 +42,11 @@ export default class Cursor {
|
||||
* @summary Returns the number of documents that match a query.
|
||||
* @memberOf Mongo.Cursor
|
||||
* @method count
|
||||
* @param {boolean} [applySkipLimit=true] If set to `false`, the value
|
||||
* returned will reflect the total
|
||||
* number of matching documents,
|
||||
* ignoring any value supplied for
|
||||
* limit
|
||||
* @instance
|
||||
* @locus Anywhere
|
||||
* @returns {Number}
|
||||
*/
|
||||
count(applySkipLimit = true) {
|
||||
count() {
|
||||
if (this.reactive) {
|
||||
// allow the observe to be unordered
|
||||
this._depend({added: true, removed: true}, true);
|
||||
@@ -59,7 +54,6 @@ export default class Cursor {
|
||||
|
||||
return this._getRawObjects({
|
||||
ordered: true,
|
||||
applySkipLimit
|
||||
}).length;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,46 +137,46 @@ Tinytest.add('minimongo - basics', test => {
|
||||
test.equal(c.find('abc').count(), 0);
|
||||
test.equal(c.find(undefined).count(), 0);
|
||||
test.equal(c.find().count(), 3);
|
||||
test.equal(c.find(1, {skip: 1}).count(false), 1);
|
||||
test.equal(c.find(1, {skip: 1}).count(false), 0);
|
||||
test.equal(c.find(1, {skip: 1}).count(), 0);
|
||||
test.equal(c.find({_id: 1}, {skip: 1}).count(false), 1);
|
||||
test.equal(c.find({_id: 1}, {skip: 1}).count(false), 0);
|
||||
test.equal(c.find({_id: 1}, {skip: 1}).count(), 0);
|
||||
test.equal(c.find({_id: undefined}).count(), 0);
|
||||
test.equal(c.find({_id: false}).count(), 0);
|
||||
test.equal(c.find({_id: null}).count(), 0);
|
||||
test.equal(c.find({_id: ''}).count(), 0);
|
||||
test.equal(c.find({_id: 0}).count(), 0);
|
||||
test.equal(c.find({}, {skip: 1}).count(false), 3);
|
||||
test.equal(c.find({}, {skip: 1}).count(false), 2);
|
||||
test.equal(c.find({}, {skip: 1}).count(), 2);
|
||||
test.equal(c.find({}, {skip: 2}).count(), 1);
|
||||
test.equal(c.find({}, {limit: 2}).count(false), 3);
|
||||
test.equal(c.find({}, {limit: 2}).count(false), 2);
|
||||
test.equal(c.find({}, {limit: 2}).count(), 2);
|
||||
test.equal(c.find({}, {limit: 1}).count(), 1);
|
||||
test.equal(c.find({}, {skip: 1, limit: 1}).count(false), 3);
|
||||
test.equal(c.find({}, {skip: 1, limit: 1}).count(false), 1);
|
||||
test.equal(c.find({}, {skip: 1, limit: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {limit: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {limit: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {limit: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1, limit: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1, limit: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {skip: 1, limit: 1}).count(), 1);
|
||||
test.equal(c.find(1, {sort: ['_id', 'desc'], skip: 1}).count(false), 1);
|
||||
test.equal(c.find(1, {sort: ['_id', 'desc'], skip: 1}).count(false), 0);
|
||||
test.equal(c.find(1, {sort: ['_id', 'desc'], skip: 1}).count(), 0);
|
||||
test.equal(c.find({_id: 1}, {sort: ['_id', 'desc'], skip: 1}).count(false), 1);
|
||||
test.equal(c.find({_id: 1}, {sort: ['_id', 'desc'], skip: 1}).count(false), 0);
|
||||
test.equal(c.find({_id: 1}, {sort: ['_id', 'desc'], skip: 1}).count(), 0);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1}).count(false), 3);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1}).count(false), 2);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1}).count(), 2);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 2}).count(), 1);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], limit: 2}).count(false), 3);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], limit: 2}).count(false), 2);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], limit: 2}).count(), 2);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], limit: 1}).count(), 1);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(false), 3);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(false), 1);
|
||||
test.equal(c.find({}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], limit: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], limit: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], limit: 1}).count(), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(false), 2);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(false), 1);
|
||||
test.equal(c.find({tags: 'fruit'}, {sort: ['_id', 'desc'], skip: 1, limit: 1}).count(), 1);
|
||||
|
||||
// Regression test for #455.
|
||||
@@ -3498,32 +3498,26 @@ Tinytest.add('minimongo - count on cursor with limit', test => {
|
||||
const c = Tracker.autorun(c => {
|
||||
const cursor = coll.find({_id: {$exists: true}}, {sort: {_id: 1}, limit: 3});
|
||||
count = cursor.count();
|
||||
unlimitedCount = cursor.count(false);
|
||||
});
|
||||
|
||||
test.equal(count, 3);
|
||||
test.equal(unlimitedCount, 4);
|
||||
|
||||
coll.remove('A'); // still 3 in the collection
|
||||
Tracker.flush();
|
||||
test.equal(count, 3);
|
||||
test.equal(unlimitedCount, 3);
|
||||
|
||||
coll.remove('B'); // expect count now 2
|
||||
Tracker.flush();
|
||||
test.equal(count, 2);
|
||||
test.equal(unlimitedCount, 2);
|
||||
|
||||
|
||||
coll.insert({_id: 'A'}); // now 3 again
|
||||
Tracker.flush();
|
||||
test.equal(count, 3);
|
||||
test.equal(unlimitedCount, 3);
|
||||
|
||||
coll.insert({_id: 'B'}); // now 4 entries, but count should be 3 still
|
||||
Tracker.flush();
|
||||
test.equal(count, 3);
|
||||
test.equal(unlimitedCount, 4); // unlimitedCount should be 4 now
|
||||
|
||||
c.stop();
|
||||
});
|
||||
@@ -3802,36 +3796,29 @@ Tinytest.add('minimongo - fine-grained reactivity of query with fields projectio
|
||||
Tinytest.add('minimongo - reactive skip/limit count while updating', test => {
|
||||
const X = new LocalCollection;
|
||||
let count = -1;
|
||||
let unlimitedCount = -1;
|
||||
|
||||
const c = Tracker.autorun(() => {
|
||||
count = X.find({}, {skip: 1, limit: 1}).count();
|
||||
unlimitedCount = X.find({}, {skip: 1, limit: 1}).count(false);
|
||||
});
|
||||
|
||||
test.equal(count, 0);
|
||||
test.equal(unlimitedCount, 0);
|
||||
|
||||
X.insert({});
|
||||
Tracker.flush({_throwFirstError: true});
|
||||
test.equal(count, 0);
|
||||
test.equal(unlimitedCount, 1);
|
||||
|
||||
X.insert({});
|
||||
Tracker.flush({_throwFirstError: true});
|
||||
test.equal(count, 1);
|
||||
test.equal(unlimitedCount, 2);
|
||||
|
||||
X.update({}, {$set: {foo: 1}});
|
||||
Tracker.flush({_throwFirstError: true});
|
||||
test.equal(count, 1);
|
||||
test.equal(unlimitedCount, 2);
|
||||
|
||||
// Make sure a second update also works
|
||||
X.update({}, {$set: {foo: 2}});
|
||||
Tracker.flush({_throwFirstError: true});
|
||||
test.equal(count, 1);
|
||||
test.equal(unlimitedCount, 2);
|
||||
|
||||
c.stop();
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
summary: "Meteor's client-side datastore: a port of MongoDB to Javascript",
|
||||
version: '1.7.0'
|
||||
version: '1.8.0'
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
## Remaining work
|
||||
|
||||
- [x] Come up with a system for constraining minimum browser versions.
|
||||
|
||||
- [x] Research minimum versions for key ECMAScript features.
|
||||
|
||||
- [x] Use the minimum versions in `webapp` to determine JS bundle.
|
||||
|
||||
- [x] Import different `core-js` polyfills in `ecmascript-runtime-client`
|
||||
depending on modern/legacy classification.
|
||||
|
||||
- [x] Really vet the set of imported `core-js` polyfills based on known
|
||||
minimum versions imposed by `setMinimumBrowserVersions`.
|
||||
|
||||
- [x] Make sure the new url prefixes aren't too disruptive for public
|
||||
assets like images.
|
||||
|
||||
- [x] Make sure Cordova isn't automatically treated as a modern
|
||||
environment.
|
||||
|
||||
- [ ] Create an `isobuild:web-browser-legacy` pseudopackage.
|
||||
|
||||
- [ ] Add tests to the `modules` test app.
|
||||
|
||||
- [x] Expose `Meteor.isModern` on both client and server.
|
||||
|
||||
- [ ] Make sure in-browser tests run with both `web.browser` and
|
||||
`web.browser.legacy`.
|
||||
|
||||
- [x] Use `web.browser.legacy` to handle `es5-shim` instead.
|
||||
|
||||
- [x] Use `web.browser.legacy` to handle SockJS instead.
|
||||
|
||||
- [x] Load `SockJS` using dynamic `import()` if necessary in modern
|
||||
`web.browser` clients.
|
||||
|
||||
- [x] Use different plugins in babel-compiler for `web.browser.legacy`.
|
||||
|
||||
- [x] Fix dynamic module source map URLs (prepend `/__arch`).
|
||||
|
||||
- [x] Fix tests failing because of changes to static resource URLs.
|
||||
|
||||
- [ ] In development, save time by only rebuilding `web.browser` (modern)?
|
||||
|
||||
- [ ] Try adding a `web.worker` platform and see if it works as expected.
|
||||
|
||||
- [ ] Update `History.md` to reflect all these changes.
|
||||
|
||||
- [ ] Write a blog post about the new modern/legacy system.
|
||||
|
||||
- [ ] Update `compiler.BUILT_BY` and `LINKER_CACHE_SALT` to force
|
||||
recompilation and relinking.
|
||||
@@ -1,6 +1,6 @@
|
||||
Package.describe({
|
||||
name: "modules-runtime",
|
||||
version: "0.12.0",
|
||||
version: "0.13.0",
|
||||
summary: "CommonJS module system",
|
||||
git: "https://github.com/benjamn/install",
|
||||
documentation: "README.md"
|
||||
|
||||
@@ -48,27 +48,16 @@ var Module = meteorInstall.Module;
|
||||
Module.prototype.useNode = function () {
|
||||
if (typeof npmRequire !== "function") {
|
||||
// Can't use Node if npmRequire is not defined.
|
||||
return false;
|
||||
}
|
||||
|
||||
var parts = this.id.split("/");
|
||||
var start = 0;
|
||||
if (parts[start] === "") ++start;
|
||||
if (parts[start] === "node_modules" &&
|
||||
parts[start + 1] === "meteor") {
|
||||
start += 2;
|
||||
}
|
||||
|
||||
if (parts.indexOf("node_modules", start) < 0) {
|
||||
// Don't try to use Node for modules that aren't in node_modules
|
||||
// directories.
|
||||
return false;
|
||||
throw new Error('npmRequire must be defined to use useNode');
|
||||
}
|
||||
|
||||
try {
|
||||
npmRequire.resolve(this.id);
|
||||
} catch (e) {
|
||||
return false;
|
||||
throw new Error(
|
||||
`Cannot find module "${this.id}". ` +
|
||||
`Try installing the npm package or make sure it is not a devDependency.`
|
||||
);
|
||||
}
|
||||
|
||||
// See tools/static-assets/server/npm-require.js for the implementation
|
||||
@@ -76,6 +65,4 @@ Module.prototype.useNode = function () {
|
||||
// modules (typically, a .js file in a package with "type": "module" in
|
||||
// its package.json), as of Node 12.16.0 (Meteor 1.9.1).
|
||||
this.exports = npmRequire(this.id);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user