diff --git a/.circleci/config.yml b/.circleci/config.yml index 00870d86f5..6736ff3860 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,24 @@ run_env_change: &run_env_change # Reload sysctl so these are in effect. # sudo sysctl -p +log_env: &log_env + name: Log Environment + command: | + echo "==> LBS Version" + lsb_release -a + echo "==> cat /etc/os-release" + cat /etc/os-release + echo "==> uname -srm" + uname -srm + echo "==> Node version: $(node --version)" + echo "==> NPM version: $(npm --version)" + echo "==> Meteor Node version: $(./meteor node --version)" + echo "==> Meteor NPM version: $(./meteor npm --version)" + echo "==> Dev bundle package.json:" + cat ./dev_bundle/lib/package.json + echo "==> Dev bundle node_modules:" + ls -l ./dev_bundle/lib/node_modules + # A reusable "run" snippet which enables the continued logging of memoryusage # to a file on disk which can be saved to build artifacts for later analysis. run_log_mem_use: &run_log_mem_use @@ -58,10 +76,10 @@ run_save_node_bin: &run_save_node_bin fi # This environment is set to every job (and the initial build). -build_machine_environment: &build_machine_environment - # Specify that we want an actual machine (ala Circle 1.0), not a Docker image. +build_machine_environment: + &build_machine_environment # Specify that we want an actual machine (ala Circle 1.0), not a Docker image. docker: - - image: meteor/circleci:android-30-node-14 + - image: meteor/circleci:2025.07.8-android-35-node-22 resource_class: large environment: # This multiplier scales the waitSecs for selftests. @@ -86,8 +104,8 @@ build_machine_environment: &build_machine_environment # These will be evaled before each command. PRE_TEST_COMMANDS: |- - ulimit -c unlimited; # Set core dump size as Ubuntu 14.04 lacks prlimit. - ulimit -a # Display all ulimit settings for transparency. + ulimit -c unlimited; # Set core dump size as Ubuntu 14.04 lacks prlimit. + ulimit -a # Display all ulimit settings for transparency. # This is only to make Meteor self-test not remind us that we can set # this argument for self-tests. @@ -97,29 +115,8 @@ build_machine_environment: &build_machine_environment NUM_GROUPS: 12 RUNNING_AVG_LENGTH: 6 -can_disable_fibers: &can_disable_fibers - parameters: - fibers: - type: boolean - default: true - -set_fibers_env: &set_fibers_env - name: "Disable Fibers" - command: | - if [ "<< parameters.fibers >>" == "false" ]; then - echo "Disabling Fibers" - echo 'export DISABLE_FIBERS=1' >> "$BASH_ENV" - source "$BASH_ENV" - fi - - -# Run tests with Fibers and then without. -matrix_for_fibers: &matrix_for_fibers - matrix: - parameters: - # If we want to run with Fibers and without, just append false here. - fibers: [true] - + # Force modern bundler test + METEOR_MODERN: true jobs: Get Ready: @@ -141,8 +138,16 @@ jobs: - run: name: Combine NPM Shrinkwrap Files command: | - for d in packages/*/.npm/package; do cat $d/npm-shrinkwrap.json >> shrinkwraps.txt; done - for d in packages/*/.npm/plugin/*; do cat $d/npm-shrinkwrap.json >> shrinkwraps.txt; done + for d in packages/*/.npm/package; do + if [ -f $d/npm-shrinkwrap.json ]; then + cat $d/npm-shrinkwrap.json >> shrinkwraps.txt; + fi + done + for d in packages/*/.npm/plugin/*; do + if [ -f $d/npm-shrinkwrap.json ]; then + cat $d/npm-shrinkwrap.json >> shrinkwraps.txt; + fi + done - restore_cache: keys: - package-npm-deps-cache-group1-v3-{{ checksum "shrinkwraps.txt" }} @@ -169,15 +174,19 @@ jobs: - run: name: Clear npm cache command: ./meteor npm cache clear --force + - run: + <<: *log_env - run: name: Get Ready command: | eval $PRE_TEST_COMMANDS; - pushd tools - npm install @types/node@14.17.6 --save-dev + cd dev_bundle/lib + ../../meteor npm install @types/node@22.7.4 --save-dev # Ensure that meteor/tools has no TypeScript errors. - ../meteor npx tsc --noEmit --skipLibCheck - popd + ../../meteor npm install -g typescript + cd ../../ + # tools/node_modules is a symlink, but starting on NPM 7, this symlinks are deleted https://github.com/npm/cli/issues/3669 + # so we are copying the node_modules to tools ./meteor --get-ready # shouldn't take longer than 60 minutes no_output_timeout: 60m @@ -192,7 +201,6 @@ jobs: path: /tmp/memuse.txt Isolated Tests: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -201,7 +209,6 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv @@ -214,6 +221,8 @@ jobs: --retries ${METEOR_SELF_TEST_RETRIES} \ --headless \ no_output_timeout: 20m + - run: + <<: *log_env - run: name: "Running self-test (Custom Warehouse Tests)" command: | @@ -236,7 +245,6 @@ jobs: path: /tmp/memuse.txt Test Group 0: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -245,10 +253,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 0)" command: | @@ -278,7 +287,6 @@ jobs: path: /tmp/memuse.txt Test Group 1: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -287,10 +295,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 1)" command: | @@ -320,7 +329,6 @@ jobs: path: /tmp/memuse.txt Test Group 2: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -329,7 +337,8 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env + - run: + <<: *log_env - run: name: "Print environment" command: printenv @@ -339,6 +348,9 @@ jobs: if [ -f ./tmp/test-groups/2.txt ]; then TEST_GROUP=$(<./tmp/test-groups/2.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^co[n-z]'; fi echo $TEST_GROUP; eval $PRE_TEST_COMMANDS; + export PATH="/home/circleci/.sdkman/candidates/gradle/8.7/bin:${PATH}" + java --version + gradle --version ./meteor self-test \ "$TEST_GROUP" \ --retries ${METEOR_SELF_TEST_RETRIES} \ @@ -362,7 +374,6 @@ jobs: path: /tmp/memuse.txt Test Group 3: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -371,7 +382,8 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env + - run: + <<: *log_env - run: name: "Print environment" command: printenv @@ -404,7 +416,6 @@ jobs: path: /tmp/memuse.txt Test Group 4: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -413,10 +424,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 4)" command: | @@ -446,7 +458,6 @@ jobs: path: /tmp/memuse.txt Test Group 5: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -455,10 +466,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 5)" command: | @@ -488,7 +500,6 @@ jobs: path: /tmp/memuse.txt Test Group 6: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -497,10 +508,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 6)" command: | @@ -530,7 +542,6 @@ jobs: path: /tmp/memuse.txt Test Group 7: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -539,10 +550,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 7)" command: | @@ -572,7 +584,6 @@ jobs: path: /tmp/memuse.txt Test Group 8: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -581,10 +592,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 8)" command: | @@ -614,7 +626,6 @@ jobs: path: /tmp/memuse.txt Test Group 9: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -623,10 +634,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 9)" command: | @@ -656,7 +668,6 @@ jobs: path: /tmp/memuse.txt Test Group 10: - <<: *can_disable_fibers <<: *build_machine_environment steps: - run: @@ -665,10 +676,11 @@ jobs: <<: *run_env_change - attach_workspace: at: . - - run: *set_fibers_env - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 10)" command: | @@ -709,6 +721,8 @@ jobs: - run: name: "Print environment" command: printenv + - run: + <<: *log_env - run: name: "Running self-test (Test Group 11)" command: | @@ -722,7 +736,7 @@ jobs: --headless \ --junit ./tmp/results/junit/11.xml \ --without-tag "custom-warehouse" - no_output_timeout: 30m + no_output_timeout: 35m - run: <<: *run_save_node_bin - store_test_results: @@ -737,47 +751,38 @@ jobs: - store_artifacts: path: /tmp/memuse.txt - # Test the JSDoc declarations which live within this codebase against the - # Meteor Docs (https://github.com/meteor/docs) repository, where they'll - # eventually be consumed. This test aims to provide an early warning of - # potentially breaking changes, so they aren't discovered when the docs are - # next updated, which generally occurs during major Meteor version releases - # (for example, 1.4 to 1.5, 1.5 to 1.6). + # Test the JSDoc declarations which live within this codebase. + # Now the docs live in this repo, we can test them here, every PR is tested. Docs: docker: # This Node version should match that in the meteor/docs CircleCI config. - - image: meteor/circleci:android-28-node-12 + - image: meteor/circleci:2025.07.8-android-35-node-22 resource_class: large environment: CHECKOUT_METEOR_DOCS: /home/circleci/test_docs + <<: *build_machine_environment steps: - run: - name: Cloning "meteor/docs" Repository's "update-to-meteor-1.9" branch + name: Cloning "meteor" Repository's current branch command: | - git clone --branch update-to-meteor-1.9 https://github.com/meteor/docs.git ${CHECKOUT_METEOR_DOCS} - # The "docs" repository normally brings in the Meteor code as a Git - # submodule checked out into the "code" directory. As the goal of this - # test is to run it against the _current_ repository's code, we'll move - # the "code" directory out of the way and move the checkout (of meteor) - # into that directory, rather than the default $CIRCLE_WORKING_DIRECTORY. - - checkout - - run: - name: Move Meteor checkout into docs repository's "code" directory - command: | - rmdir "${CHECKOUT_METEOR_DOCS}/code" - # $CIRCLE_WORKING_DIRECTORY uses a tilde, so expand it to $HOME. - mv "${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}" \ - "${CHECKOUT_METEOR_DOCS}/code" + if [[ -n "$CIRCLE_PULL_REQUEST" ]]; then + PR_NUMBER=$(echo $CIRCLE_PULL_REQUEST | sed 's|.*/pull/\([0-9]*\)|\1|') + PR_BRANCH=$(curl -s https://api.github.com/repos/meteor/meteor/pulls/$PR_NUMBER | jq -r .head.ref) + git clone https://github.com/meteor/meteor.git ${CHECKOUT_METEOR_DOCS} + cd ${CHECKOUT_METEOR_DOCS} + git fetch origin pull/$PR_NUMBER/head:$PR_BRANCH + else + git clone --branch $CIRCLE_BRANCH https://github.com/meteor/meteor.git ${CHECKOUT_METEOR_DOCS} + fi # Run almost the same steps the meteor/docs repository runs, minus deploy. - run: name: Generating Meteor documentation for JSDoc testing command: | - cd ${CHECKOUT_METEOR_DOCS} + cd ${CHECKOUT_METEOR_DOCS}/docs npm install npm test Clean Up: - <<: *can_disable_fibers <<: *build_machine_environment steps: - attach_workspace: @@ -860,58 +865,45 @@ workflows: - Docs - Get Ready - Isolated Tests: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 0: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 1: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 2: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 3: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 4: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 5: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 6: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 7: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 8: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 9: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 10: - <<: *matrix_for_fibers requires: - Get Ready - Test Group 11: requires: - Get Ready - Clean Up: - <<: *matrix_for_fibers requires: - Isolated Tests - Test Group 0 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..e023176dc5 --- /dev/null +++ b/.envrc @@ -0,0 +1,113 @@ +#!/bin/env zsh + +# +# Commands and shortcuts for Meteor core development, you can load these in your terminal by running `source .envrc`. +# Or by adding `[[ -s .envrc ]] && source .envrc` to your `.zshrc` or `.bashrc`. +# + +export ROOT_DIR=$(git rev-parse --show-toplevel) + +######## +# Core # +######## + +function @meteor { + "$ROOT_DIR/meteor" "$@" +} + +function @get-ready { + @meteor --get-ready +} + +function @test-packages { + TINYTEST_FILTER="$1" @meteor test-packages --exclude-archs=web.browser.legacy,web.cordova +} + +function @test-self { + @meteor self-test "$@" +} + +function @test-in-console { + "$ROOT_DIR/packages/test-in-console/run.sh" "$@" +} + +function @check-syntax { + node "$ROOT_DIR/scripts/admin/check-legacy-syntax/check-syntax.js" +} + +function @generate-dev-bundle { + rm -rf $ROOT_DIR/dev_bundle* + "$ROOT_DIR/scripts/generate-dev-bundle.sh" +} + +function @init-submodule { + git submodule update --init --recursive +} + +################# +# Documentation # +################# + +function @docs-start { + npm run docs:dev --prefix "$ROOT_DIR/v3-docs/docs" +} + +function @docs-migration-start { + npm run docs:dev --prefix "$ROOT_DIR/v3-docs/v3-migration-docs" +} + +function @get-changes { + git diff --numstat HEAD~1 HEAD | awk '($1 + $2) <= 5000 {print $3}' +} + +function @summarize-changes { + changes=$(@get-changes) + + if [ -n "$changes" ]; then + changes=$(git diff HEAD~1 HEAD -- $(echo "$changes" | tr '\n' ' ')) + else + changes=$(git diff HEAD~1 HEAD) + fi + + echo "$changes" | llm -s "Summarize the following changes in a few sentences:" +} + +function @packages-bumped { + git diff --name-only devel...$(git branch --show-current) | grep "packages/.*/package.js$" | while IFS= read -r file; do + if ! git show devel:$file > /dev/null 2>&1; then + continue + fi + + old=$(git show devel:$file | grep -o "version: *['\"][^'\"]*['\"]" | sed "s/version: *.['\"]//;s/['\"].*//") + version=$(grep -o "version: *['\"][^'\"]*['\"]" "$file" | sed "s/version: *.['\"]//;s/['\"].*//") + name=$(grep -o "name: *['\"][^'\"]*['\"]" "$file" | sed "s/name: *.['\"]//;s/['\"].*//") + + pkg_name=$(echo "$file" | sed -E 's|packages/([^/]*/)?([^/]*)/package\.js|\2|') + + version_in_red=$(tput setaf 1)$version$(tput sgr0) + + if [[ "$version" != "$old" ]]; then + echo "- $pkg_name@$version_in_red" + fi + done +} + +function @packages-bumped-npm { + git diff --name-only devel...$(git branch --show-current) | grep "npm-packages/.*/package.json$" | while IFS= read -r file; do + if ! git show devel:$file > /dev/null 2>&1; then + continue + fi + + old=$(git show devel:$file | grep -o "version: *['\"][^'\"]*['\"]" | sed "s/version: *.['\"]//;s/['\"].*//") + version=$(grep -o "\"version\": *['\"][^'\"]*['\"]" "$file" | sed "s/\"version\": *.['\"]//;s/['\"].*//") + name=$(grep -o "\"name\": *['\"][^'\"]*['\"]" "$file" | sed "s/\"name\": *.['\"]//;s/['\"].*//") + + pkg_name=$(echo "$file" | sed -E 's|npm-packages/([^/]*/)?([^/]*)/package\.json|\2|') + + version_in_red=$(tput setaf 1)$version$(tput sgr0) + + if [[ "$version" != "$old" ]]; then + echo "- $pkg_name@$version_in_red" + fi + done +} diff --git a/.eslintignore b/.eslintignore index 3653ab7c32..a62c426997 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,9 +2,7 @@ android_bundle/ dev_bundle/ docs/ examples/ -packages/ scripts/ -tools/ !tools/*.js !tools/isobuild/*.js !tools/catalog/*.js diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..ec54d801f0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@henriquealbert @denihs @fredmaiaarantes @nachocodoner @leonardoventurini diff --git a/.github/labeler.yml b/.github/labeler.yml index b99cd8fb97..343cc5ee6a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,120 +1,178 @@ Project:Accounts:Password: - - packages/accounts-password/**/* + - changed-files: + - any-glob-to-any-file: packages/accounts-password/**/* Project:Accounts:UI: - - packages/meteor-developer-config-ui/**/* - - packages/github-config-ui/**/* - - packages/google-config-ui/**/* - - packages/twitter-config-ui/**/* - - packages/facebook-config-ui/**/* - - packages/accounts-ui/**/* - - packages/accounts-ui-unstyled/**/* + - changed-files: + - any-glob-to-any-file: + - packages/meteor-developer-config-ui/**/* + - packages/github-config-ui/**/* + - packages/google-config-ui/**/* + - packages/twitter-config-ui/**/* + - packages/facebook-config-ui/**/* + - packages/accounts-ui/**/* + - packages/accounts-ui-unstyled/**/* Project:CSS: - - packages/non-core/less/**/* - - packages/minifier-css/**/* - - packages/standard-minifier-css/**/* + - changed-files: + - any-glob-to-any-file: + - packages/non-core/less/**/* + - packages/minifier-css/**/* + - packages/standard-minifier-css/**/* Project:DDP: - - packages/ddp-common/**/* - - packages/ddp-rate-limiter/**/* - - packages/ddp-server/**/* - - packages/ddp-client/**/* - - packages/ddp/**/* - - packages/socket-stream-client/**/* + - changed-files: + - any-glob-to-any-file: + - packages/ddp-common/**/* + - packages/ddp-rate-limiter/**/* + - packages/ddp-server/**/* + - packages/ddp-client/**/* + - packages/ddp/**/* + - packages/socket-stream-client/**/* Project:EJSON: - - packages/ejson/**/* + - changed-files: + - any-glob-to-any-file: packages/ejson/**/* Project:HMR: - - packages/hot-code-push/**/* - - packages/hot-module-replacement/**/* + - changed-files: + - any-glob-to-any-file: + - packages/hot-code-push/**/* + - packages/hot-module-replacement/**/* Project:Isobuild:Minifiers: - - packages/minifier-css/**/* - - packages/minifier-js/**/* - - packages/standard-minifier-js/**/* - - packages/standard-minifier-css/**/* - - packages/standard-minifiers/**/* + - changed-files: + - any-glob-to-any-file: + - packages/minifier-css/**/* + - packages/minifier-js/**/* + - packages/standard-minifier-js/**/* + - packages/standard-minifier-css/**/* + - packages/standard-minifiers/**/* Project:Isobuild: - - tools/isobuild/**/* + - changed-files: + - any-glob-to-any-file: + - tools/isobuild/**/* Project:JS Environment:Typescript: - - packages/typescript/**/* + - changed-files: + - any-glob-to-any-file: + - packages/typescript/**/* Project:JS Environment: - - packages/babel-compiler/**/* - - packages/babel-runtime/**/* - - packages/ecmascript/**/* - - packages/ecmascript-runtime/**/* - - packages/ecmascript-runtime-client/**/* - - packages/ecmascript-runtime-server/**/* - - packages/es5-shim/**/* - - packages/jshint/**/* + - changed-files: + - any-glob-to-any-file: + - packages/babel-compiler/**/* + - packages/babel-runtime/**/* + - packages/ecmascript/**/* + - packages/ecmascript-runtime/**/* + - packages/ecmascript-runtime-client/**/* + - packages/ecmascript-runtime-server/**/* + - packages/es5-shim/**/* + - packages/jshint/**/* Project:Livequery: - - packages/livedata/**/* + - changed-files: + - any-glob-to-any-file: + - packages/livedata/**/* Project:Minimongo: - - packages/minimongo + - changed-files: + - any-glob-to-any-file: + - packages/minimongo Project:Mobile: - - tools/cordova/**/* - - packages/launch-screen/**/* - - packages/mobile-experience/**/* - - packages/mobile-status-bar/**/* + - changed-files: + - any-glob-to-any-file: + - tools/cordova/**/* + - packages/launch-screen/**/* + - packages/mobile-experience/**/* + - packages/mobile-status-bar/**/* Project:Mongo Driver: - - packages/mongo/**/* - - packages/mongo-dev-server/**/* - - packages/mongo-id/**/* - - packages/mongo-livedata/**/* - - packages/disable-oplog/**/* - - packages/non-core/mongo-decimal/**/* + - changed-files: + - any-glob-to-any-file: + - packages/mongo/**/* + - packages/mongo-dev-server/**/* + - packages/mongo-id/**/* + - packages/mongo-livedata/**/* + - packages/disable-oplog/**/* + - packages/non-core/mongo-decimal/**/* Project:NPM: - - npm-packages/**/* + - changed-files: + - any-glob-to-any-file: + - npm-packages/**/* Project:Release Process: - - scripts/**/* + - changed-files: + - any-glob-to-any-file: + - scripts/**/* Project:Tool: - - tools/**/* - - packages/meteor-tool/**/* + - changed-files: + - any-glob-to-any-file: + - tools/**/* + - packages/meteor-tool/**/* Project:Tool:Shell: - - tools/console/**/* + - changed-files: + - any-glob-to-any-file: + - tools/console/**/* Project:Utilities:Email: - - packages/email/**/* + - changed-files: + - any-glob-to-any-file: + - packages/email/**/* Project:Utilities:HTTP: - - packages/deprecated/http/**/* - - packages/fetch/**/* - - packages/url/**/* + - changed-files: + - any-glob-to-any-file: + - packages/deprecated/http/**/* + - packages/fetch/**/* + - packages/url/**/* Project:Webapp: - - packages/webapp/**/* - - packages/webapp-hashing/**/* + - changed-files: + - any-glob-to-any-file: + - packages/webapp/**/* + - packages/webapp-hashing/**/* Project:Windows: - - scripts/windows/**/* + - changed-files: + - any-glob-to-any-file: + - scripts/windows/**/* Project:Webapp:Browser Policy: - - packages/browser-policy/**/* - - packages/browser-policy-common/**/* - - packages/browser-policy-content/**/* - - packages/browser-policy-framing/**/* + - changed-files: + - any-glob-to-any-file: + - packages/browser-policy/**/* + - packages/browser-policy-common/**/* + - packages/browser-policy-content/**/* + - packages/browser-policy-framing/**/* Project:Examples: - - tools/cli/example-repositories.js + - changed-files: + - any-glob-to-any-file: + - tools/cli/example-repositories.js Project:Dynamic Import: - - packages/dynamic-import/**/* + - changed-files: + - any-glob-to-any-file: + - packages/dynamic-import/**/* Project:Docs: - - docs/**/* + - changed-files: + - any-glob-to-any-file: + - docs/**/* + - v3-docs/**/* Project:Guide: - - guide/**/* + - changed-files: + - any-glob-to-any-file: + - guide/**/* + +github_actions: + - changed-files: + - any-glob-to-any-file: + - ./github/**/* diff --git a/.github/scripts/__tests__/inactive-issues.test.js b/.github/scripts/__tests__/inactive-issues.test.js new file mode 100644 index 0000000000..91f9ddf60f --- /dev/null +++ b/.github/scripts/__tests__/inactive-issues.test.js @@ -0,0 +1,198 @@ +// Tests for inactive-issues.js using Node's built-in test runner (node:test) +// We only care about the last comments (per user instruction), so we don't need pagination logic. + +const { test, beforeEach } = require('node:test'); +const assert = require('node:assert'); +const path = require('node:path'); + +// Load the script dynamically so we can pass mocks. +const scriptPath = path.join(__dirname, '..', 'inactive-issues.js'); + +// Helper to advance days +const daysAgo = (days) => { + const d = new Date(); + d.setUTCDate(d.getUTCDate() - days); + return d.toISOString(); +}; + +// Factory for github REST mock structure +function buildGithubMock({ issues, commentsByIssue }) { + return { + rest: { + issues: { + listForRepo: async ({ page, per_page }) => { + // simple pagination slice + const start = (page - 1) * per_page; + const end = start + per_page; + return { data: issues.slice(start, end) }; + }, + listComments: async ({ issue_number }) => { + return { data: commentsByIssue[issue_number] || [] }; + }, + createComment: async ({ issue_number, body }) => { + // push comment to structure to allow assertions on side effects if needed + const arr = commentsByIssue[issue_number] || (commentsByIssue[issue_number] = []); + arr.push({ + id: Math.random(), + body, + created_at: new Date().toISOString(), + user: { login: 'github-actions[bot]', type: 'Bot' } + }); + return {}; + }, + addLabels: async ({ issue_number, labels }) => { + const issue = issues.find(i => i.number === issue_number); + if (issue) { + (issue.labels || (issue.labels = [])).push(...labels.map(l => ({ name: l }))); + } + return {}; + } + } + } + }; +} + +// Wrap script invocation for reuse +async function runScript({ issues, commentsByIssue }) { + delete require.cache[require.resolve(scriptPath)]; + const fn = require(scriptPath); + const github = buildGithubMock({ issues, commentsByIssue }); + await fn({ github, context: { repo: { owner: 'meteor', repo: 'meteor' } } }); + return { issues, commentsByIssue }; +} + +let baseIssueNumber = 1000; +function makeIssue({ daysSinceHumanActivity, isPR = false, labels = [], user = 'user1' }) { + // We'll simulate by setting created_at to the human activity date if no comments. + const updated_at = daysAgo(daysSinceHumanActivity); + return { + number: baseIssueNumber++, + pull_request: isPR ? {} : undefined, + labels: labels.map(n => ({ name: n })), + user: { login: user }, + created_at: daysAgo(daysSinceHumanActivity), + updated_at + }; +} + +// TESTS + +beforeEach(() => { + baseIssueNumber = 1000; +}); + +test('60 days inactivity -> adds reminder comment (no prior reminder)', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 60 }); + const issues = [issue]; + const commentsByIssue = { [issue.number]: [] }; // no comments + + await runScript({ issues, commentsByIssue }); + + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 1, 'Should have 1 reminder comment'); + assert.match(botComments[0].body, /60 days/); + assert.ok(!issue.labels.some(l => l.name === 'idle'), 'Should not label yet'); +}); + +test('60 days inactivity but already reminded -> no duplicate comment', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 65 }); + const issues = [issue]; + const commentsByIssue = { + [issue.number]: [ + { + id: 1, + body: 'πŸ‘‹ @user1 This issue has been open with no human activity for 60 days. Is this issue still relevant? If there is no human response or activity within the next 30 days, this issue will be labeled as `idle`.', + created_at: daysAgo(5), // 5 days ago bot comment (means last human is 65 days, bot after human) + user: { login: 'github-actions[bot]', type: 'Bot' } + } + ] + }; + + await runScript({ issues, commentsByIssue }); + + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 1, 'Should still have only the existing reminder'); +}); + +test('90 days inactivity -> label + comment', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 95 }); + const issues = [issue]; + const commentsByIssue = { [issue.number]: [] }; + + await runScript({ issues, commentsByIssue }); + + assert.ok(issue.labels.some(l => l.name === 'idle'), 'Should add idle label'); + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 1, 'Should comment when labeling'); + assert.match(botComments[0].body, /90 days/i); +}); + +test('90 days inactivity but already labeled -> no action', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 100, labels: ['idle'] }); + const issues = [issue]; + const commentsByIssue = { [issue.number]: [] }; + + await runScript({ issues, commentsByIssue }); + + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 0, 'Should not comment again'); +}); + +test('90 days inactivity but already labeled `in-development` -> no action', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 100, labels: ['in-development'] }); + const issues = [issue]; + const commentsByIssue = { [issue.number]: [] }; + + await runScript({ issues, commentsByIssue }); + + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 0, 'Should not comment again'); +}); + + +test('Human reply after reminder resets cycle (no immediate labeling)', async () => { + // Scenario: last human activity 10 days ago, bot commented 40 days ago (which was 50 days after original). Should NOT comment again or label. + const issue = makeIssue({ daysSinceHumanActivity: 10 }); + const issues = [issue]; + const commentsByIssue = { + [issue.number]: [ + { + id: 1, + body: 'πŸ‘‹ @user1 This issue has been open with no human activity for 60 days... ', + created_at: daysAgo(50), + user: { login: 'github-actions[bot]', type: 'Bot' } + }, + { + id: 2, + body: 'I am still seeing this problem', + created_at: daysAgo(10), + user: { login: 'some-human', type: 'User' } + } + ] + }; + + await runScript({ issues, commentsByIssue }); + + const botComments = commentsByIssue[issue.number].filter(c => c.user.login === 'github-actions[bot]'); + assert.equal(botComments.length, 1, 'Should not add a new bot comment'); + assert.ok(!issue.labels.some(l => l.name === 'idle'), 'Should not label'); +}); + +test('Only bot comments (no human ever) counts from creation date', async () => { + const issue = makeIssue({ daysSinceHumanActivity: 61 }); + const issues = [issue]; + const commentsByIssue = { + [issue.number]: [ + { + id: 1, + body: 'Automated maintenance notice', + created_at: daysAgo(30), + user: { login: 'github-actions[bot]', type: 'Bot' } + } + ] + }; + + await runScript({ issues, commentsByIssue }); + const botComments = commentsByIssue[issue.number].filter(c => /60 days/.test(c.body)); + assert.equal(botComments.length, 1, 'Should add a 60-day reminder'); +}); diff --git a/.github/scripts/inactive-issues.js b/.github/scripts/inactive-issues.js new file mode 100644 index 0000000000..a75f5b81a1 --- /dev/null +++ b/.github/scripts/inactive-issues.js @@ -0,0 +1,200 @@ +/** +* Mark issues as idle after a period of inactivity +* and post reminders after a shorter period of inactivity. +* +* 1. Issues with no human activity for 60 days get a reminder comment. +* 2. Issues with no human activity for 90 days get labeled as "idle" and get a comment. +* +* Human activity is defined as any comment from a non-bot user. +* +* This script is intended to be run as a GitHub Action on a schedule (e.g., daily). + */ +module.exports = async ({ github, context }) => { + const daysToComment = 60; + const daysToLabel = 90; + + const idleTimeComment = daysToComment * 24 * 60 * 60 * 1000; + const idleTimeLabel = daysToLabel * 24 * 60 * 60 * 1000; + const now = new Date(); + + const BOT_LOGIN = 'github-actions[bot]'; + const REMINDER_PHRASE = 'Is this issue still relevant?'; + + const COMMENT_60_TEMPLATE = (login) => + `πŸ‘‹ @${login} This issue has been open with no human activity for ${daysToComment} days. Is this issue still relevant? If there is no human response or activity within the next ${daysToLabel - daysToComment} days, this issue will be labeled as \`idle\`.`; + + const COMMENT_90_TEXT = + 'This issue has been automatically labeled as `idle` due to 90 days of inactivity (no human interaction). If this is still relevant or if someone is working on it, please comment or add `in-development` label.'; + + // Fetch all open issues + async function fetchAllIssues() { + let page = 1; + const per_page = 100; + const results = []; + let keepGoing = true; + + while (keepGoing) { + const { data } = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page, + page, + sort: 'updated', + direction: 'asc' + }); + + if (!data.length) break; + results.push(...data); + + if (data.length < per_page) { + keepGoing = false; + } else { + page++; + await new Promise((r) => setTimeout(r, 120)); + } + } + return results; + } + // analyse comments to find last human activity and if a reminder was already posted after that + async function analyzeComments(issueNumber, issueCreatedAt) { + const commentsResp = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + per_page: 100 + }); + + const comments = commentsResp.data; + let lastHumanActivity = null; + + for (let i = comments.length - 1; i >= 0; i--) { + const c = comments[i]; + const isBot = c.user?.type === 'Bot' || c.user?.login === BOT_LOGIN; + if (!isBot) { + lastHumanActivity = new Date(c.created_at); + break; + } + } + + if (!lastHumanActivity) { + lastHumanActivity = new Date(issueCreatedAt); + } + + const hasReminderAfterLastHuman = comments.some( + (c) => + c.user?.login === BOT_LOGIN && + c.body?.includes(REMINDER_PHRASE) && + new Date(c.created_at) > lastHumanActivity + ); + + return { lastHumanActivity, hasReminderAfterLastHuman }; + } + + const issues = await fetchAllIssues(); + + let processed = 0; + let commented = 0; + let labeled = 0; + let skippedPR = 0; + + for (const issue of issues) { + processed++; + + if (issue.pull_request) { + skippedPR++; + continue; + } + + if (issue.labels.some((l) => l.name === 'idle' || l.name === 'in-development')) { + continue; + } + + let analysis; + try { + analysis = await analyzeComments(issue.number, issue.created_at); + } catch (err) { + continue; // fail to get comments, skip + } + + const { lastHumanActivity, hasReminderAfterLastHuman } = analysis; + const inactivityMs = now.getTime() - lastHumanActivity.getTime(); + + // 90+ days => label + comment + if (inactivityMs >= idleTimeLabel) { + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['idle'] + }); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: COMMENT_90_TEXT + }); + labeled++; + continue; + } catch (err) { + // retry simples + try { + await new Promise((r) => setTimeout(r, 5000)); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['idle'] + }); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: COMMENT_90_TEXT + }); + labeled++; + } catch {} + continue; + } + } + + // 60-89 days => comment (once) + if ( + inactivityMs >= idleTimeComment && + inactivityMs < idleTimeLabel && + !hasReminderAfterLastHuman + ) { + const body = COMMENT_60_TEMPLATE(issue.user.login); + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body + }); + commented++; + } catch (err) { + try { + await new Promise((r) => setTimeout(r, 5000)); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body + }); + commented++; + } catch {} + } + } + } + + // Log summary for CI + console.log( + JSON.stringify( + { processed, commented, labeled, skippedPR }, + null, + 2 + ) + ); +}; diff --git a/.github/workflows/check-code-style.yml b/.github/workflows/check-code-style.yml index 0a136db59a..8b24944b3f 100644 --- a/.github/workflows/check-code-style.yml +++ b/.github/workflows/check-code-style.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 14.x + node-version: 22.x - run: npm ci - name: Run ESLint@8 run: npx eslint@8 "./npm-packages/meteor-installer/**/*.js" diff --git a/.github/workflows/check-syntax.yml b/.github/workflows/check-syntax.yml index 91051b2789..a20bb011ca 100644 --- a/.github/workflows/check-syntax.yml +++ b/.github/workflows/check-syntax.yml @@ -1,15 +1,14 @@ name: Check legacy syntax on: - - push - pull_request jobs: check-code-style: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 22.x - run: cd scripts/admin/check-legacy-syntax && npm ci - name: Check syntax - run: cd scripts/admin/check-legacy-syntax && node check-syntax.js + run: cd scripts/admin/check-legacy-syntax && node check-syntax.js diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3c7f7d5ec9..dc85db922f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,13 +11,13 @@ jobs: working-directory: docs/ steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 12.x - name: Build the Docs run: npm ci && npm run build - name: Deploy to Netlify for preview - uses: nwtgck/actions-netlify@v1.2.4 + uses: nwtgck/actions-netlify@v2.1.0 with: publish-dir: './docs/public/' production-branch: devel diff --git a/.github/workflows/guide.yml b/.github/workflows/guide.yml index bbc5bbd023..bd3d801966 100644 --- a/.github/workflows/guide.yml +++ b/.github/workflows/guide.yml @@ -11,13 +11,13 @@ jobs: working-directory: guide/ steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 12.x + node-version: 22.x - name: Build the Guide run: npm ci && npm run build - name: Deploy to Netlify for preview - uses: nwtgck/actions-netlify@v1.2.4 + uses: nwtgck/actions-netlify@v2.1.0 with: publish-dir: './guide/public' production-branch: devel diff --git a/.github/workflows/inactive-issues.yml b/.github/workflows/inactive-issues.yml new file mode 100644 index 0000000000..2d8cba7a3f --- /dev/null +++ b/.github/workflows/inactive-issues.yml @@ -0,0 +1,24 @@ +name: Inactive Issues Management + +on: + schedule: + # β€œAt 01:00 on Saturday.” + - cron: '0 1 * * 6' + # Allows to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + manage-inactive-issues: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Manage inactive issues + uses: actions/github-script@v6 + with: + script: | + const script = require('./.github/scripts/inactive-issues.js') + await script({github, context}) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index a9d25b1e47..da6690818c 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -17,6 +17,6 @@ jobs: label: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/npm-eslint-plugin-meteor.yml b/.github/workflows/npm-eslint-plugin-meteor.yml index 15e48abf2c..ff51a2e847 100644 --- a/.github/workflows/npm-eslint-plugin-meteor.yml +++ b/.github/workflows/npm-eslint-plugin-meteor.yml @@ -16,15 +16,12 @@ jobs: defaults: run: working-directory: npm-packages/eslint-plugin-meteor - strategy: - matrix: - node-version: [12.x, 14.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 22.x cache: npm - run: npm ci - run: npm test diff --git a/.github/workflows/npm-meteor-babel.yml b/.github/workflows/npm-meteor-babel.yml index 6d65273cf3..61bb203ccb 100644 --- a/.github/workflows/npm-meteor-babel.yml +++ b/.github/workflows/npm-meteor-babel.yml @@ -16,15 +16,12 @@ jobs: defaults: run: working-directory: npm-packages/meteor-babel - strategy: - matrix: - node-version: [12.x, 14.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 14.x cache: npm - run: npm ci - run: npm run test diff --git a/.github/workflows/npm-meteor-promise.yml b/.github/workflows/npm-meteor-promise.yml index 4ad4f6df7c..4eb16400a1 100644 --- a/.github/workflows/npm-meteor-promise.yml +++ b/.github/workflows/npm-meteor-promise.yml @@ -18,11 +18,11 @@ jobs: working-directory: npm-packages/meteor-promise strategy: matrix: - node-version: [12.x, 14.x] + node-version: [14.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: npm diff --git a/.github/workflows/run-profiler.yml b/.github/workflows/run-profiler.yml new file mode 100644 index 0000000000..c19ff83a7d --- /dev/null +++ b/.github/workflows/run-profiler.yml @@ -0,0 +1,46 @@ +name: Run Profiler + +on: + issue_comment: + types: [created] + +jobs: + run-profiler: + if: github.event.issue.pull_request && contains(github.event.comment.body , '/profile') + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Checkout Pull Request + run: gh pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Set ENVs + run: | + value="VALUE" + echo "Key=$value" >> $GITHUB_ENV + + PR_NUMBER="${{ github.event.issue.number }}" + echo "PrNumber=$PR_NUMBER" >> $GITHUB_ENV + + - name: Run CI + run: | + echo "Running meteor profiler..." + echo $PR_NUMBER + git status + ls + + - name: Comment PR + uses: thollander/actions-comment-pull-request@v3 + with: + message: | + Hello world !!!! :wave: + this is pr number: #${{ env.PrNumber }} + testing value: ${{ env.Key }} + pr-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/test-deprecated-packages.yml b/.github/workflows/test-deprecated-packages.yml new file mode 100644 index 0000000000..e4ed12fe92 --- /dev/null +++ b/.github/workflows/test-deprecated-packages.yml @@ -0,0 +1,52 @@ +name: Test Deprecated Packages + +# Disabled until we figure out how to fix the error from puppeteer +# Runs on Travis CI for now +# +#on: +# push: +# branches: +# - main +# pull_request: + +jobs: + build: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.head_ref }}-test-deprecated-packages + cancel-in-progress: true + timeout-minutes: 60 + + env: + PUPPETEER_DOWNLOAD_PATH: /home/runner/.npm/chromium + + steps: + - name: Update and install dependencies + run: sudo apt-get update && sudo apt-get install -y libnss3 g++-12 + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 20.15.1 + + - name: Cache Node.js modules + uses: actions/cache@v3 + with: + path: | + ~/.npm + .meteor + .babel-cache + dev_bundle + /home/runner/.npm/chromium + key: ${{ runner.os }}-node-${{ hashFiles('meteor', '**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install dependencies + run: npm install + + - name: Run tests + run: ./packages/test-in-console/run.sh \ No newline at end of file diff --git a/.github/workflows/windows-selftest.yml b/.github/workflows/windows-selftest.yml new file mode 100644 index 0000000000..37d739d7c8 --- /dev/null +++ b/.github/workflows/windows-selftest.yml @@ -0,0 +1,81 @@ +name: Windows Selftest + +on: + pull_request: + types: + - opened + - reopened + - synchronize + paths: + - 'meteor' + - 'meteor.bat' + - 'tools/**' + - 'packages/babel-compiler/**' + - 'packages/dynamic-import/**' + - 'packages/meteor/**' + - 'packages/meteor-tool/**' + - '.github/workflows/windows-selftest.yml' + + push: + branches: + - devel + +env: + METEOR_PRETTY_OUTPUT: 0 + SELF_TEST_TOOL_NODE_FLAGS: ' ' + TOOL_NODE_FLAGS: --expose-gc + TIMEOUT_SCALE_FACTOR: 20 + METEOR_HEADLESS: true + SELF_TEST_EXCLUDE: '^NULL-LEAVE-THIS-HERE-NULL$' + METEOR_MODERN: true + +jobs: + test: + runs-on: windows-2019-meteor + concurrency: + group: ${{ github.head_ref }}-meteor-selftest-windows + cancel-in-progress: true + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 22.x + + - name: Cache dependencies + id: meteor-cache + uses: actions/cache@v4 + with: + path: | + dev_bundle/ + .babel-cache/ + .meteor/ + ~/.npm + node_modules/ + packages/**/.npm + key: ${{ runner.os }}-meteor-${{ hashFiles('**/package-lock.json', 'meteor', 'meteor.bat') }} + restore-keys: | + ${{ runner.os }}-meteor- + + - name: Install dependencies + shell: pwsh + run: | + $env:PATH = "C:\Program Files\7-Zip;$env:PATH" + .\scripts\windows\ci\install.ps1 + + # Run ONLY when the cache was NOT restored + - name: Prepare Meteor (cache miss) + if: steps.meteor-cache.outputs.cache-hit != 'true' + shell: pwsh + run: | + $env:PATH = "C:\Program Files\7-Zip;$env:PATH" + .\meteor.bat --get-ready + + - name: Run tests + shell: pwsh + run: | + $env:PATH = "C:\Program Files\7-Zip;$env:PATH" + .\scripts\windows\ci\test.ps1 diff --git a/.gitignore b/.gitignore index 35e2d8f2e7..4742e13056 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,13 @@ mongo-test-output # core packages shouldn't have .versions files packages/*/.versions + +# packages shouldn't have .npm on Git +packages/**/.npm + +# doc files should not be committed +packages/**/*.docs.js + +#cursor +.cursorignore +.cursorrules diff --git a/.gitmodules b/.gitmodules index 17644a42a4..59b70023f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "packages/non-core/blaze"] path = packages/non-core/blaze - url = https://github.com/meteor/blaze.git \ No newline at end of file + url = https://github.com/meteor/blaze.git +[submodule "npm-packages/cordova-plugin-meteor-webapp/src/ios/GCDWebServer"] + path = npm-packages/cordova-plugin-meteor-webapp/src/ios/GCDWebServer + url = https://github.com/meteor/GCDWebServer.git + branch = master diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000000..711f4c4f56 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 11 +} diff --git a/.travis.yml b/.travis.yml index 35e4e9f859..3e63726f4c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,10 @@ language: node_js os: linux -dist: xenial +dist: jammy +sudo: required +services: xvfb node_js: - - "14.17.6" + - "22.17.0" cache: directories: - ".meteor" @@ -11,17 +13,22 @@ script: - travis_retry ./packages/test-in-console/run.sh env: global: - - CXX=g++-4.8 + - CXX=g++-12 - phantom=false - PUPPETEER_DOWNLOAD_PATH=~/.npm/chromium - jobs: - # We don't want to run the tests without fibers anymore. - # - DISABLE_FIBERS=1 - # Use a different flag, since node would use false as a string. - - FIBERS_ENABLED=1 + - TEST_PACKAGES_EXCLUDE=stylus + - METEOR_MODERN=true addons: apt: sources: - ubuntu-toolchain-r-test packages: - - g++-4.8 + - g++-12 + - libnss3 + +before_install: + - cat /etc/apt/sources.list + - python3 --version + - echo "deb http://archive.ubuntu.com/ubuntu jammy main universe" | sudo tee -a /etc/apt/sources.list + - sudo apt-get update + - sudo apt-get install -y libnss3 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0c727908c2..fa910d2ee5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -8,18 +8,18 @@ All recipients of reports commit to maintain the confidentiality with regard to ## Report an issue -To report an issue in one of the projects listed below, please send an email to code-of-conduct@meteor.com. +To report an issue in one of the projects listed below, please email code-of-conduct@meteor.com. * [OSS Meteor Projects](https://github.com/meteor) * [Meteor Forum](https://forums.meteor.com/) +* [Meteor Lounge on Discord](https://discord.gg/hZkTCaVjmT) ## Code of Conduct panel The Code of Conduct panel is a moderation team that handle code of conduct issues. The makeup of this team is as follows: * CEO at Meteor Software - Frederico Maia Arantes -* DevRel Manager at Meteor Software - Tatiana Barros -* Software Engineer at Meteor Software - Denilson Silva +* CTO at Meteor Software - Henrique Albert * CEO at High Impact Tech - Alim S. Gafar Members of the CoCP team will be added for a 1-year term and will be re-confirmed on a yearly basis. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e27d3b550..c646fad457 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ There are many ways to contribute to the Meteor Project. Here’s a list of tech There are also several ways to contribute to the Meteor Project outside of GitHub, like organizing or speaking at [Meetups](https://forums.meteor.com/c/meetups) and events and helping to moderate our [forums](https://forums.meteor.com/). -If you can think of any changes to the project, [documentation](https://github.com/meteor/meteor/tree/devel/docs), or [guide](https://github.com/meteor/meteor/tree/devel/guide) that would improve the contributor experience, let us know by opening an issue! +If you can think of any changes to the project, [documentation](https://github.com/meteor/meteor/tree/devel/v3-docs), or [guide](https://github.com/meteor/meteor/tree/devel/guide) that would improve the contributor experience, let us know by opening an issue! ### Finding work @@ -43,15 +43,14 @@ Reviewers are members of the community who help with Pull Requests reviews. Current Reviewers: - [meteor](https://github.com/meteor/meteor) - - [@denihs](https://github.com/denihs) - [@fredmaiaarantes](https://github.com/fredmaiaarantes) - [@henriquealbert](https://github.com/henriquealbert) - [@aquinoit](https://github.com/aquinoit) - [@Grubba27](https://github.com/Grubba27) -- [@filipenevola](https://github.com/filipenevola) + - [@italojs](https://github.com/italojs) + - [@nachocodoner](https://github.com/nachocodoner) - [@StorytellerCZ](https://github.com/StorytellerCZ) - [@zodern](https://github.com/zodern) -- [@CaptainN](https://github.com/CaptainN) - [@radekmie](https://github.com/radekmie) #### Core Committer @@ -59,20 +58,19 @@ Current Reviewers: The contributors with commit access to meteor/meteor are employees of Meteor Software LP or community members who have distinguished themselves in other contribution areas or members of partner companies. If you want to become a core committer, please start writing PRs. Current Core Team: -- [@denihs](https://github.com/denihs) -- [@zodern](https://github.com/zodern) -- [@filipenevola](https://github.com/filipenevola) -- [@fredmaiaarantes](https://github.com/fredmaiaarantes) -- [@henriquealbert](https://github.com/henriquealbert) -- [@Grubba27](https://github.com/Grubba27) +- [meteor](https://github.com/meteor/meteor) + - [@fredmaiaarantes](https://github.com/fredmaiaarantes) + - [@henriquealbert](https://github.com/henriquealbert) + - [@Grubba27](https://github.com/Grubba27) + - [@italojs](https://github.com/italojs) + - [@nachocodoner](https://github.com/nachocodoner) - [@StorytellerCZ](https://github.com/StorytellerCZ) -- [@CaptainN](https://github.com/CaptainN) +- [@zodern](https://github.com/zodern) - [@radekmie](https://github.com/radekmie) -- [@matheusccastroo](https://github.com/matheusccastroo) ### 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](https://docs.meteor.com/roadmap.html) 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/about/roadmap.html) contains high-level information on the current priorities of the project. ## Reporting a bug in Meteor @@ -134,7 +132,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](https://docs.meteor.com/roadmap.html) 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/about/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 @@ -157,7 +155,7 @@ Learn how we use GitHub labels [here](LABELS.md) ## Documentation -If you'd like to contribute to Meteor's documentation, head over to https://docs.meteor.com or https://guide.meteor.com and if you find something that could be better click in "Edit on GitHub" footer to edit and submit a PR. +If you'd like to contribute to Meteor's documentation, head over to https://docs.meteor.com/about/contributing.html for guidelines. ## Blaze @@ -207,7 +205,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://docs.meteor.com/roadmap.html). 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/about/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. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index dbbdfefcdd..a34dd51841 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -43,13 +43,19 @@ can run Meteor directly from a Git checkout using these steps: $ /path/to/meteor-checkout/meteor run ``` - > _Tip:_ Consider making an easy-to-run alias for frequent use: + > _Tip 1:_ Consider making an easy-to-run alias for frequent use: > > alias mymeteor=/path/to-meteor-checkout/meteor > > This allows the use of `mymeteor` in place of `meteor`. To persist this > across shell logouts, simply add it to `~/.bashrc` or `.zshrc`. + > _Tip 2:_ When working with meteor tool, it may be helpful to use the debugger to check what's happening. You can do this using the following flag: + > + > TOOL_NODE_FLAGS="--inspect-brk" mymeteor + > + > Then you can use the chrome debugger inside `chrome://inspect`. + ### Notes when running from a checkout The following are some distinct differences you must pay attention to when running Meteor from a checkout: diff --git a/History.md b/History.md index 91b0003589..7b252eed31 100644 --- a/History.md +++ b/History.md @@ -2,4 +2,4 @@ This content was moved to [history.md](./docs/history.md). -Previously the changelog was available to be edited here but it was always published in [https://docs.meteor.com/changelog.html](https://docs.meteor.com/changelog.html). +Previously the changelog was available to be edited here but it was always published in [https://docs.meteor.com/history.html](https://docs.meteor.com/history.html). diff --git a/README.md b/README.md index 16f6d2fc29..11aa1c4c6c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,21 @@
- + + + + Meteor logo +
-
-
[![Travis CI Status](https://api.travis-ci.com/meteor/meteor.svg?branch=devel)](https://app.travis-ci.com/github/meteor/meteor) [![CircleCI Status](https://circleci.com/gh/meteor/meteor.svg?style=svg)](https://app.circleci.com/pipelines/github/meteor/meteor?branch=devel) -[![built with Meteor](https://img.shields.io/badge/Meteor-2.13.3-green?logo=meteor&logoColor=white)](https://meteor.com) +[![built with Meteor](https://img.shields.io/badge/Meteor-3.2.2-green?logo=meteor&logoColor=white)](https://meteor.com) +![node-current](https://img.shields.io/node/v/meteor) +![Discord](https://img.shields.io/discord/1247973371040239676) +![Twitter Follow](https://img.shields.io/twitter/follow/meteorjs?style=social)
@@ -21,7 +26,7 @@ Meteor is an **ultra-simple** environment for building **modern** web applicatio
- [Official Website](https://www.meteor.com) -- [Installation](https://www.meteor.com/developers/install) +- [Installation](https://docs.meteor.com/about/install.html) - [Documentation](https://docs.meteor.com/#/full/)
@@ -46,28 +51,25 @@ Use the same code whether you’re developing for web, iOS, Android, or desktop # πŸ”₯ Getting Started -How about trying a getting started tutorial in your favorite technology? +How about trying a tutorial to get started with your favorite technology? -| [ React](https://react-tutorial.meteor.com/) | +| [ React](https://docs.meteor.com/tutorials/react/) | | - | | [ Blaze](https://blaze-tutorial.meteor.com/) | -| [ Vue](https://vue-tutorial.meteor.com/) | -| [ Svelte](https://svelte-tutorial.meteor.com/) | - -Next, read the [documentation](https://docs.meteor.com/) and get some [examples](https://github.com/meteor/examples). +| [ Vue](https://docs.meteor.com/tutorials/vue/meteorjs3-vue3-vue-meteor-tracker.html) | # πŸš€ Quick Start On your platform, use this line: ```shell -> npm install -g meteor +> npx meteor ``` πŸš€ To create a project: ```shell -> meteor create my-app +> meteor create ``` β˜„οΈ Run it: @@ -81,10 +83,9 @@ meteor **Building an application with Meteor?** -* Deploy on [Meteor Cloud](https://www.meteor.com/cloud) -* Discussion [Forums](https://forums.meteor.com/) -* Join the Meteor community Slack by clicking this [invite link](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc). -* Announcement list. Subscribe in the [footer](https://www.meteor.com/). +* Deploy on [Galaxy](https://galaxycloud.app) +* Discuss on [Forums](https://forums.meteor.com/) +* Join the [Meteor Discord](https://discord.gg/hZkTCaVjmT) Interested in helping or contributing to Meteor? These resources will help: @@ -93,5 +94,3 @@ Interested in helping or contributing to Meteor? These resources will help: * [Contribution guidelines](CONTRIBUTING.md) * [Feature requests](https://github.com/meteor/meteor/discussions/) * [Issue tracker](https://github.com/meteor/meteor/issues) - -To uninstall Meteor [read here](https://docs.meteor.com/install.html#uninstall). diff --git a/SECURITY.md b/SECURITY.md index 3d2a49b445..aaf7b92c93 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,9 +4,9 @@ | Version | Support Status | ------- | -------------- -| 2.x.y | βœ… all security issues -| 1.12.x | 🚧 only critical security issues -| <= 1.11.x | ❌ no longer supportted +| 3.x.y | βœ… all security issues +| 2.x.y | ⚠️ only major security issues (Until 2025-07) +| <= 1.12.x | ❌ no longer supported ## Reporting a Vulnerability diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index de63e8fd72..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,47 +0,0 @@ -version: '{build}' - -branches: - except: - - /^dev-bundle-/ - -skip_branch_with_pr: true - -clone_folder: C:\projects\meteor -image: Visual Studio 2019 - -environment: - METEOR_PRETTY_OUTPUT: 0 - SELF_TEST_TOOL_NODE_FLAGS: " " - TOOL_NODE_FLAGS: --expose-gc - TIMEOUT_SCALE_FACTOR: 8 - METEOR_HEADLESS: true - SELF_TEST_EXCLUDE: "^NULL-LEAVE-THIS-HERE-NULL$" -platform: - - x64 - -matrix: - fast_finish: true - allow_failures: - - platform: x64 - -# We don't need the actual "build", just the tests. -build: off - -install: - - ps: C:\projects\meteor\scripts\windows\appveyor\install.ps1 - -test_script: - - ps: C:\projects\meteor\scripts\windows\appveyor\test.ps1 - -on_failure: - - ps: | - $npmLogsDir = "$($Env:AppData)\npm-cache\_logs" - If (Test-Path "$npmLogsDir") { - Get-ChildItem "${npmLogsDir}\*.log" | - % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - } - -cache: - - dev_bundle -> meteor - - .babel-cache -> meteor - - .meteor diff --git a/docs/_config.yml b/docs/_config.yml index b6b9dbd871..395aaca44c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,6 +1,8 @@ title: Meteor API Docs subtitle: API Docs versions: + - '2.16' + - '2.14' - '2.13' - '2.12' - '2.11' @@ -62,6 +64,7 @@ sidebar_categories: - api/packagejs - api/mobile-config - api/environment + - api/top-level-await Packages: - packages/accounts-ui - packages/accounts-passwordless @@ -85,9 +88,9 @@ sidebar_categories: - packages/server-render - packages/spacebars - packages/standard-minifier-css - - packages/underscore - packages/url - packages/webapp + - packages/packages-listing Command Line: - commandline - environment-variables @@ -210,6 +213,7 @@ redirects: /#/full/accounts-setusername: 'api/passwords.html#accounts-setusername' /#/full/accounts-addemail: 'api/passwords.html#accounts-addemail' /#/full/accounts-removeemail: 'api/passwords.html#accounts-removeemail' + /#/full/accounts_replaceemail: 'api/passwords.html#Accounts-replaceEmail' /#/full/accounts_verifyemail: 'api/passwords.html#Accounts-verifyEmail' /#/full/accounts-finduserbyusername: 'api/passwords.html#accounts-finduserbyusername' /#/full/accounts-finduserbyemail: 'api/passwords.html#accounts-finduserbyemail' @@ -389,7 +393,6 @@ redirects: /#/full/oauth-encryption: 'packages/oauth-encryption.html' /#/full/random: 'packages/random.html' /#/full/spiderable: 'packages/spiderable.html' - /#/full/underscore: 'packages/underscore.html' /#/full/webapp: 'packages/webapp.html' '#meteor_isclient': 'api/core.html#Meteor-isClient' '#meteor_isserver': 'api/core.html#Meteor-isServer' @@ -665,6 +668,5 @@ redirects: '#oauth-encryption': 'packages/oauth-encryption.html' '#random': 'packages/random.html' '#spiderable': 'packages/spiderable.html' - '#underscore': 'packages/underscore.html' '#webapp': 'packages/webapp.html' '#pkg_spacebars': 'packages/spacebars.html' diff --git a/docs/generators/changelog/EXAMPLE.MD b/docs/generators/changelog/EXAMPLE.MD index c2a7ff6989..dffc0f018c 100644 --- a/docs/generators/changelog/EXAMPLE.MD +++ b/docs/generators/changelog/EXAMPLE.MD @@ -1,36 +1,50 @@ ## vX.XX.X, 2023-XX-XX -### Highlights - +## Highlights +List the most important changes to catch people's attention. +Are there breaking changes? Mention it here and link them. +Are there exciting new features? Mention it here and link them. +For example: * MongoDB Server 6.x Support * Embedded Mongo now uses MongoDB 6.0.3 -* Some pr [GH someone] [PR #number] // this will become -> [someone](https://github.com/someone) [PR](https://github.com/meteor/meteor/pull/number) -#### Breaking Changes - -N/A - -#### Internal API changes - -N/A - -#### Migration Steps - -TODO - -#### Meteor Version Release -* `Command line`: - - Corrected typo in XX XX +## Migration Steps +Steps to migrate to this version. If it's a long one, we should have a migration guide page. -* `npm mongo @4.13.0`: // You can use @get-version to get the version of the package +## New Features +- Feature 1 description. PR Link. +- Feature 2 description. PR Link. +- Some feature. pr [GH someone] [PR #number] // this will become -> [someone](https://github.com/someone) [PR](https://github.com/meteor/meteor/pull/number) +- `Command line`: + - Added feature X +## Patch changes +- Patch Change 1 description. PR Link. +- Patch Change 2 description. PR Link. +- `npm mongo @4.13.0`: // You can use @get-version to get the version of the package - Updated MongoDB driver to version 4.13.0 -#### Special thanks to +## Breaking Changes +- Breaking change 1. +- Breaking change 1. +* `fetch@get-version`: + - X has changed + +## Docs +- Docs change 1. +- Docs change 2. + +## Core dependencies +Core dependency change 1. +Core dependency change 2. + +## Dependencies +Dependency change 1. +Dependency change 2. + +## Contributors +- Contributor 1. - [@XXX](https://github.com/XXXX). - For making this great framework even better! - - diff --git a/docs/generators/changelog/README.md b/docs/generators/changelog/README.md index 30a3780b8e..bd795db186 100644 --- a/docs/generators/changelog/README.md +++ b/docs/generators/changelog/README.md @@ -12,18 +12,37 @@ To get which branches were merged into release you can search in the GitHub repo by using this query: ``` - is:pr base: is:merged + is:pr base: is:merged ``` or in GH Cli: + ```bash gh pr list --state merged --base ``` note that it may not be as useful as the first one, since it will not show the Authors and other related information. + ## Why? Computers with lower memory/ IDEs with high memory usage can have problems with the changelog file(~10k lines). This is a way to reduce the memory usage of the changelog, also creating a more organized changelog, since all the files will be reflecting at least one version. + +## Update ordering. + +If you want to make sure that the changelog is correcly ordered, take a look at the `order-packages.js` file. +to use it, run the command below: + +```bash +node order-packages.js versions/3.0.md +``` + +or + +```bash +node order-packages.js versions/.md +``` + +it will update the file with the correct ordering(this will override the file). \ No newline at end of file diff --git a/docs/generators/changelog/order-packages.js b/docs/generators/changelog/order-packages.js new file mode 100644 index 0000000000..8af678af5e --- /dev/null +++ b/docs/generators/changelog/order-packages.js @@ -0,0 +1,81 @@ +const fs = require("fs").promises; + +// we want to get the strings that are between #### Breaking Changes and #### New Public API +// then we will create a map with the package name and the version for example: +// +// - `accounts-2fa@3.0.0`: + +// - Some methods are now async. See below: +// - `Accounts._is2faEnabledForUser` +// - `(Meteor Method) - generate2faActivationQrCode` +// - `(Meteor Method) - enableUser2fa` +// - `(Meteor Method) - disableUser2fa` +// - `(Meteor Method) - has2faEnabled` + +// will be converted to: +// {"accounts-2fa@3.0.0": ` - Some methods are now async. See below: +// - `Accounts._is2faEnabledForUser` +// - `(Meteor Method) - generate2faActivationQrCode` +// - `(Meteor Method) - enableUser2fa` +// - `(Meteor Method) - disableUser2fa` +// - `(Meteor Method) - has2faEnabled`` +// } + +// then we will iterate and order the packages in alphabetical order and write again to the file. + +/** + * + * @param {string} path + * @returns {Promise<[string, null] | ["", Error]>} + */ +async function getFile(path) { + try { + const data = await fs.readFile(path, "utf8"); + return [data, null]; + } catch (e) { + console.error(e); + return ["", new Error("could not read file")]; + } +} + +async function main() { + const [filePath] = process.argv.slice(2); + const [code, error] = await getFile(filePath); + if (error) throw error; + + const regex = /#### Breaking Changes([\s\S]*?)#### New Public API/gm; + const matches = code.match(regex).join("\n").split("\n"); + + let objectMap = {}; + let currentWorkingPackage = ""; + for (const line of matches) { + if (line.startsWith("-")) { + const packageName = line + .replace("-", "") + .replace("`:", "") + .replace("`", "") + .trim(); + objectMap[packageName] = ""; + currentWorkingPackage = packageName; + continue; + } + objectMap[currentWorkingPackage] += line + "\n"; + } + // sorting acc + const result = Object.keys(objectMap) + .reduce((acc, key) => { + if (key === "") return acc; + acc.push({ key, value: objectMap[key]}); + return acc; + }, []) + .sort((a, b) => a.key.localeCompare(b.key)) + .reduce((acc, { key, value }) => { + return acc + `- \`${key}\`:\n${value}`; + }, "") + + const newCode = code.replace(regex, `#### Breaking Changes\n\n${result}`); + + await fs.writeFile(filePath, newCode); +} + +main().then(() => console.log("done")); diff --git a/docs/generators/changelog/script.js b/docs/generators/changelog/script.js index d762fbb241..5050630dc8 100755 --- a/docs/generators/changelog/script.js +++ b/docs/generators/changelog/script.js @@ -1,56 +1,49 @@ -const _fs = require('fs'); +const _fs = require("fs"); const fs = _fs.promises; - function getPackageVersion(packageName) { function getFile(path) { try { - const data = _fs.readFileSync(path, 'utf8'); + const data = _fs.readFileSync(path, "utf8"); return [data, null]; } catch (e) { console.error(e); - return ['', e]; + return ["", e]; } - } - const [code, error] = getFile(`../packages/${ packageName }/package.js`); - if (error) return 'ERR_NO_VERSION'; + const [code, error] = getFile(`../packages/${packageName}/package.js`); + if (error) return ""; for (const line of code.split(/\n/)) { // verify if the line has a version - if (!line.includes('version:')) continue; + if (!line.includes("version:")) continue; //Package.describe({ // summary: 'some description.', // version: '1.2.3' <--- this is the line we want, we assure that it has a version in the previous if //}); - const [_, versionValue] = line.split(':'); + const [_, versionValue] = line.split(":"); if (!versionValue) continue; - const removeQuotes = - (v) => - v - .trim() - .replace(',', '') - .replace(/'/g, '') - .replace(/"/g, ''); - - if (versionValue.includes('-')) return removeQuotes(versionValue.split('-')[0]); + const removeQuotes = (v) => + v.trim().replace(",", "").replace(/'/g, "").replace(/"/g, ""); + if (versionValue.includes("-")) + return removeQuotes(versionValue.split("-")[0]); return removeQuotes(versionValue); } } const main = async () => { try { - console.log('started concatenating files'); - const files = await fs.readdir('./generators/changelog/versions', 'utf8'); + console.log("started concatenating files"); + const files = await fs.readdir("./generators/changelog/versions", "utf8"); const filesStream = files - .map(file => { - console.log(`reading file: ${ file }`); + .map((file) => { + console.log(`reading file: ${file}`); return { fileName: file, - buf : fs.readFile(`./generators/changelog/versions/${ file }`, 'utf8') + buf: fs.readFile(`./generators/changelog/versions/${file}`, "utf8"), }; }) - .map(async ({buf, fileName}, index) => { + .map(async ({ buf, fileName }, index) => { // first file we don't do anything // Big file and does not follow the new standard if (index === 0) return buf; @@ -58,52 +51,60 @@ const main = async () => { /** * @type {Set} */ - const contribuitors = new Set() + const contribuitors = new Set(); // DSL Replacers // [PR #123] -> [PR #123](https://github.com/meteor/meteor/pull/123) // [GH meteor/meteor] -> [meteor/meteor](https://github.com/meteor/meteor) // package-name@get-version -> package-name@1.3.3 - const file = content - .replace(/\[PR #(\d+)\]/g, (_, number) => `[PR](https://github.com/meteor/meteor/pull/${ number })`) + const file = content + .replace( + /\[PR #(\d+)\]/g, + (_, number) => + `[PR](https://github.com/meteor/meteor/pull/${number})` + ) .replace(/\[GH ([^\]]+)\]/g, (_, name) => { contribuitors.add(name); - return `[${ name }](https://github.com/${ name })` + return `[${name}](https://github.com/${name})`; }) - .replace(/([a-z0-9-]+)@get-version/g, (_, name) => `${ name }@${ getPackageVersion(name) }`); + .replace( + /([a-z0-9-]+)@get-version/g, + (_, name) => `${name}@${getPackageVersion(name)}` + ); // already have the contribuitors thanks in the file if ( - file.includes('#### Special thanks to') || - file.includes('[//]: # (Do not edit this file by hand.)') - ) return file; + file.includes('## Contributors') || + file.includes("#### Special thanks to") || // this must stay here for legacy reasons + file.includes("[//]: # (Do not edit this file by hand.)") + ) + return file; // add the contribuitors - const contribuitorsList = - Array - .from(contribuitors) - .map(name => `- [@${ name }](https://github.com/${ name }).`) - .join('\n'); + const contribuitorsList = Array.from(contribuitors) + .map((name) => `- [@${name}](https://github.com/${name}).`) + .join("\n"); - const doneFile = `${ file }\n\n#### Special thanks to\n\n${ contribuitorsList }\n\n`; + const doneFile = `${file}\n\n## Contributors\n\n${contribuitorsList}\n\n`; //SIDE EFFECTS // so that this is not ran every time, we will update the last file. // this is for the expensive part of the script - if (index === files.length - 2) await fs.writeFile(`./generators/changelog/versions/${fileName}`, doneFile); - + if (index === files.length - 2) + await fs.writeFile( + `./generators/changelog/versions/${fileName}`, + doneFile + ); return doneFile; }) .reverse(); - console.log('Giving some touches to the files'); + console.log("Giving some touches to the files"); const filesContent = await Promise.all(filesStream); - await fs.writeFile('./history.md', filesContent.join('')); - console.log('Finished :)'); - + await fs.writeFile("./history.md", filesContent.join("")); + console.log("Finished :)"); } catch (e) { console.log(e); } - -} -main().then(_ => _); +}; +main().then((_) => _); diff --git a/docs/generators/changelog/versions/0-before-2.10.md b/docs/generators/changelog/versions/0-before-2.10.md index 9ee0122e33..54c856eaa8 100644 --- a/docs/generators/changelog/versions/0-before-2.10.md +++ b/docs/generators/changelog/versions/0-before-2.10.md @@ -441,7 +441,7 @@ N/A * `mongo@1.15.0` - New option `Meteor.settings.packages.mongo.reCreateIndexOnOptionMismatch` for case when an index with the same name, but different options exists it will be re-created. - - If there is an error on index creation Meteor will output a better message naming the collection and index where the error occured. [PR](https://github.com/meteor/meteor/pull/11995). + - If there is an error on index creation Meteor will output a better message naming the collection and index where the error occurred. [PR](https://github.com/meteor/meteor/pull/11995). * `modern-browsers@0.1.8` - New api `getMinimumBrowserVersions` to access the `minimumBrowserVersions`. [PR](https://github.com/meteor/meteor/pull/11998). * `socket-stream-client@0.5.0` @@ -656,7 +656,7 @@ Read our [Migration Guide](https://guide.meteor.com/2.6-migration.html) for this - 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. + - fields option is deprecated, we are maintaining a translation layer to "projection" field (now preferred) 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. @@ -2935,6 +2935,7 @@ N/A setMinimumBrowserVersions({ chrome: 49, firefox: 45, + firefoxIOS: 100, edge: 12, ie: Infinity, // Sorry, IE11. mobile_safari: [9, 2], // 9.2.0+ diff --git a/docs/generators/changelog/versions/2.12.md b/docs/generators/changelog/versions/2.12.md index 35735edd74..f0b74d3533 100644 --- a/docs/generators/changelog/versions/2.12.md +++ b/docs/generators/changelog/versions/2.12.md @@ -148,4 +148,3 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. - [@zodern](https://github.com/zodern). - [@dmromanov](https://github.com/dmromanov). - [@matheusccastroo](https://github.com/matheusccastroo). - diff --git a/docs/generators/changelog/versions/2.14.md b/docs/generators/changelog/versions/2.14.md new file mode 100644 index 0000000000..486c8b57d1 --- /dev/null +++ b/docs/generators/changelog/versions/2.14.md @@ -0,0 +1,229 @@ +## v2.14.0, 2023-12-12 + +### Highlights + +Hacktoberfest release! πŸŽ‰ + +* MongoDB driver has been updated to v4.17.2. + +* You can now set `DISABLE_SOCKJS_CORS=1` if you want to prevent SockJS from setting CORS headers. Do not set this option if you will have DDP clients from other origins connecting to the DDP server. [PR #12789] + +* Added guide on [how to prepare for Meteor 3.0 migration](https://guide.meteor.com/prepare-meteor-3.0). + +* New DDP merge strategy `NO_MERGE_MULTI`, which is similar to `NO_MERGE`, but it does track whether a document is used by multiple publications. [PR #12742] + +* Appcache has been further deprecated and moved to the deprecated packages folder. + +* Added `Accounts.createUserAsync` into the client. + +* Many packages had their underscore dependency removed. + +* Cordova has been updated to v12.0.1 for Android and v7.0.1 for iOS, being able to build to SDK 33. + +* `meteor create` command is now interactive! + +* Added `firstRunPromise` property to `Tracker` autorun blocks, that forces autorun blocks to be executed in synchronous-looking order by storing the value autorun promise thus making it awaitable. + +#### Migration Steps + +##### Android splash screen +If you have been using `splash-screen` for Cordova, you need to update your code as Android changed their splash screen API, +the `cordova-plugin-splashscreen` is now on `cordova-android` core, so we have removed the dependency from the `splash-screen` +package. As a result we are dropping the support for dark mode splash screen on Android. + +To create this now you need to create two themes on your `config.xml` file. + +> Note that it's still possible to have it by adding the according themes with App.appendToConfig and App.addResourceFile - but this is not something Meteor will do automatically right now. + +For more information you can check our [Migration Guide](https://guide.meteor.com/2.14-migration.html) + +## Breaking Changes + +* `splash-screen` package has removed the `cordova-plugin-splashscreen` dependency. See migration steps for more info. + +## Docs + +- Added guide on [how to prepare for Meteor 3.0 migration](https://guide.meteor.com/prepare-meteor-3.0). +- Added guide on [performance improvements](https://guide.meteor.com/performance-improvement). +- Added FAQ about [Meteor 3](https://guide.meteor.com/3.0-migration). + +## Internal API changes + +* Tool + - Rename `EACCESS` to `EACCES` to follow the Windows spelling + - Fixed links in skeletons + - Fixed build issue in Vue skeleton + - Updated `source-map-support` + - Fixed bugs in negated β€œin” and β€œinstanceof” expressions + - Updated `semver` to v7.5.4 + - Updated `@meteorjs/babel` to v7.18.4 + - Cordova has been updated to v12.0.1 for Android and v7.0.1 for iOS, being able to build to SDK 33. + - `meteor create` command was re-made to be more interactive + +## Meteor Version Release + +* `accounts-base@get-version` + - Ensure that `onLogin` callback fires properly + - Indexes are now created asynchronously + +* `accounts-oauth@get-version` + - Indexes are now created asynchronously + +* `accounts-password@get-version` + - Add `Accounts.createUserAsync` to the client, a promise-based version of `Accounts.createUser` + - Indexes are now created asynchronously + +* `accounts-passwordless@get-version` + - Fix #12401, ensure that user is found with ID + - Indexes are now created asynchronously + +* `babel-compiler@get-version` + - Updated `@meteorjs/babel` to v7.18.4 + +* `boilerplate-generator@get-version` + - Removed Underscore dependency + +* `browser-policy-content@get-version` + - Removed Underscore dependency + +* `constraint-solver@get-version` + - Removed Underscore dependency + +* `crosswalk@get-version` + - Updated `cordova-plugin-crosswalk-webview` to v2.4.0 + - Deprecated the package + +* `ddp-rate-limiter@get-version` + - Removed Underscore dependency +* `ddp-server@get-version`: + - Allow setting `DISABLE_SOCKJS_CORS` to prevent SockJS from setting CORS headers + - Added new publication strategy `NO_MERGE_MULTI` + +* `ecmascript@get-version`: + - Bumped to get latest version of `@babel/compiler` + +* `facebook-oauth@get-version`: + - Updated default version of Facebook GraphAPI to v17 + +* `launch-screen@get-version` + - Removed `cordova-plugin-splashscreen` dependency + +* `fetch@get-version`: + - Update `node-fetch` to version 1.6.12 + - Update `whatwg-fetch` to version 3.6.17 + +* `logging@get-version`: + - Added TS types + - Updated `chalk` to v4.1.2 + +* `logic-solver@get-version` + - Removed Underscore dependency + +* `meteor@get-version`: + - Improve TS types + +* `mobile-experience@get-version`: + - Bumped to get latests version of `cordova` dependencies + +* `modern-browsers@get-version` + - Added `appleMail` user agent to allow modern bundle on iPads + +* `modules@get-version` + - Updated version of reify to v0.24.1 + +* `mongo@get-version` + - Added deprecation messages into type definitions + - Fix ObjectIDs handling in oplogV2V1Converter + +* `npm-mongo@get-version`: + - Bumped MongoDB driver to version 4.17.2 + +* `oauth@get-version` + - Indexes are now created asynchronously + - `remove` DB calls migrated to `removeAsync` + +* `package-version-parser@get-version` + - Updated `semver` to v7.5.4 + +* `react-fast-refresh@get-version`: + - Updated `semver` to version 7.5.4 + +* `service-configuration@get-version` + - Indexes are now created asynchronously + - Add types for ConfigError + +* `socket-stream-client@get-version` + - Removed Underscore dependency + +* `standard-minifier-css@get-version` + - Updated `@babel/runtime` to v7.23.5 + - Updated `minifier-css` to v1.6.4 + - Updated `logging` package to v1.3.2 + +* `test-server-tests-in-console-once@get-version` + - Removed Underscore dependency + +* `tinytest@get-version` + - Removed Underscore dependency + +* `tracker@get-version` + - Added `firstRunPromise` property, that forces autorun blocks to be executed + in synchronous-looking order by storing the value autorun promise + thus making it awaitable + +* `typescript@get-version`: + - Updated to 4.9.5 + +* `webapp@get-version` + - Updated `cordova-plugin-meteor-webapp` to v2.0.3 + - Updated `cookie-parser` to v1.4.6 + - Updated `send` to v0.18.0 + - Updated `stream-to-string` to v1.2.1 + - Updated `qs` to v6.11.2 + - Updated `@types/connect` to v3.4.38 + + +## Independent releases + +* `google-oauth@1.4.4`: + - Remove logging request/response in google_server + +* NPM `@meteorjs/babel@7.18.4` + - Updated `@meteorjs/reify` to v0.24.1 + +* NPM `@meteorjs/babel-preset-meteor@7.10.1` + - Add Facebook in-app browser + +* NPM `cordova-plugin-meteor-webapp@2.0.2` + - Fixed Android hot code push failing + +* NPM `cordova-plugin-meteor-webapp@2.0.3` + - Fix pull manifest from correct url if parameter are used in baseurl + +* NPM `meteor-node-stubs@1.2.6` + - Update dependencies + - Deep update dependencies that were highlighted by `npm audit` + +## Contributors + +- [@StorytellerCZ](https://github.com/sponsors/StorytellerCZ) +- [@Grubba27](https://github.com/sponsors/Grubba27) +- [@vit0rr](https://github.com/vit0rr) +- [@realyze](https://github.com/realyze) +- [@jamauro](https://github.com/jamauro) +- [@Torgen](https://github.com/Torgen) +- [@brucejo75](https://github.com/brucejo75) +- [@zodern](https://github.com/sponsors/zodern) +- [@alisnic](https://github.com/alisnic) +- [@ebroder](https://github.com/ebroder) +- [@BANSAL-NISHU](https://github.com/BANSAL-NISHU) +- [@salmanhasni](https://github.com/salmanhasni) +- [@jdgjsag67251](https://github.com/jdgjsag67251) +- [@guncebektas](https://github.com/guncebektas) +- [@harryadel](https://github.com/harryadel) +- [@dd137](https://github.com/dd137) +- [@matheusccastroo](https://github.com/matheusccastroo) +- [@mr-loop-1](https://github.com/mr-loop-1) + +For making this great framework even better! + diff --git a/docs/generators/changelog/versions/2.15.0.md b/docs/generators/changelog/versions/2.15.0.md new file mode 100644 index 0000000000..c1eca4ba44 --- /dev/null +++ b/docs/generators/changelog/versions/2.15.0.md @@ -0,0 +1,57 @@ +## v2.15.0, 2024-02-05 + +### Highlights + +* Bumps embedded MongoDB to 7.0.5. + +#### Breaking Changes + +N/A + +#### Internal API changes + +N/A + +#### Migration Steps + +In development, if you're using Linux, you might get an error like `version GLIBCXX_3.4.26 not found` or something related to g++. + +This is related to your g++ version. With MongoDB 7, you need to have g++ 11 or higher. So make sure to have this updated. + +This will happen only if you are trying to run your Meteor application with a MongoDB 7 version. If you run your app with a MONGO_URL pointing to a different MongoDB version, you won't have this issue. + +```bash + +meteor update --release 2.15 + +``` + + +#### Meteor Version Release + + +* `Command line`: + - The bundle version was changed to include embedded MongoDB to 7.0.5. + - Fix cordova launch screen warnings on 2.15 [PR #12971] +* `underscore@get-version`: + - A test related to [PR #12798] to see if the tests can manage the first update step. [PR #12912] +* `service-configuration@get-version`: + - added new types* [PR #12922] +* `meteor@get-version`: + - added new types [PR #12922] +* `accounts-base@get-version`: + - Added missing type for createUserVerifyingEmail [PR #12919] + +#### Special thanks to + +- [@Grubba27](https://github.com/Grubba27). +- [@denihs](https://github.com/denihs). +- [@mcorbelli](https://github.com/mcorbelli). +- [@matheusccastroo](https://github.com/matheusccastroo). +- [@StorytellerCZ](https://github.com/StorytellerCZ). +- [@ebroder](https://github.com/ebroder). +- [@nachocodoner](https://github.com/nachocodoner). + +For making this great framework even better! + + diff --git a/docs/generators/changelog/versions/2.16.md b/docs/generators/changelog/versions/2.16.md new file mode 100644 index 0000000000..0d847779df --- /dev/null +++ b/docs/generators/changelog/versions/2.16.md @@ -0,0 +1,102 @@ +## v2.16.0, 2024-05-14 + +### Highlights + +- Support observeChangesAsync and observeAsync. [PR](https://github.com/meteor/meteor/pull/13025) +- New mongo package options to optimize Oplog tailing performance to include/exclude certain collections [PR](https://github.com/meteor/meteor/pull/13009) + +#### Migration Steps + +To update from 2.15 to this one, you can run: + +``` +meteor update --release 2.16 +``` + +If you're coming from an older version, please check our [Migration Guides](https://guide.meteor.com/2.14-migration). + +#### Breaking Changes +N/A + +#### Internal API changes + +* Add method name to MethodInvocation in DDP messages + +#### Meteor Version Release + +* Meteor tool + - Updated Svelte skeleton + - Update tsconfig.json for Svelte skeleton + - Updated Solid skeleton NPM dependencies + +* Blaze + - Support of async dynamic attributes [PR](https://github.com/meteor/blaze/pull/460) + - Fix Blaze._expandAttributes returns empty object, if null. [PR](https://github.com/meteor/blaze/pull/458) + +* `accounts-base@get-version` + - Supported session storage to store accounts login token [PR #13046] + - Update config checking + - Added new types [PR #13042] + +* `accounts-oauth@get-version` + - Remove config checking as it is done in `accounts-base` + +* `accounts-ui-unstyled@get-version` + - `Connect with Twitter` is now `Connect with X/Twitter` + +* `check@get-version`: + - Added an optional flag to immediately throw error when all checks failed. [PR #12970] + +* `ddp-common@get-version` + - Add method name to MethodInvocation + +* `ddp-client@get-version` + - Add method name to MethodInvocation + +* `ddp-server@get-version` + - Add method name to MethodInvocation + +* `twitter-config-ui@get-version` + - Update setup instructions + +* `email@get-version` + - Nodemailer update to v6.9.10 + - `@types/nodemailer` updated to v6.4.14 + - Adds the ability to encrypt your emails using PGP [PR #12991] + +* `logging@get-version` + - Type update + +* `minimongo@get-version` + - Support observeChangesAsync and observeAsync [PR #13025] + - Report and extend test cases for the old async behaviors + +* `minifier-js@get-version` + - Update terser to v5.31.0 + +* `mongo@get-version` + - Support a new option to include/exclude certain collections for oplog tailing [PR #13009] + +* `reload-safetybelt@get-version` + - Remove underscore dependency + +* `service-configuration@get-version` + - Type update + +#### Independent releases + +* `mongo@1.16.9`: + - Set `minPoolSize` for oplog + +* `underscore@1.6.1` + - Fix bug in `_.intersection` + +#### Contributors + +- [GH nachocodoner] +- [GH StorytellerCZ] +- [GH jamauro] +- [GH Twisterking] +- [GH harryadel] + +Thanks for making this great framework even better! diff --git a/docs/generators/changelog/versions/3.0.0.md b/docs/generators/changelog/versions/3.0.0.md new file mode 100644 index 0000000000..4c863db6ad --- /dev/null +++ b/docs/generators/changelog/versions/3.0.0.md @@ -0,0 +1,743 @@ +## v3.0, 2024-07-15 + +### Highlights + +#### Breaking Changes + +- `accounts-2fa@3.0.0`: + + - Some methods are now async. See below: + - `Accounts._is2faEnabledForUser` + - `(Meteor Method) - generate2faActivationQrCode` + - `(Meteor Method) - enableUser2fa` + - `(Meteor Method) - disableUser2fa` + - `(Meteor Method) - has2faEnabled` + +- `accounts-base@3.0.0`: + + - `methods.removeOtherTokens` is now async + - `Accounts.destroyToken` is now async + - `Accounts.insertUserDoc` is now async + - `Accounts.updateOrCreateUserFromExternalService` is now async + - `Accounts.expirePasswordToken` is now async + - `Accounts.setupUsersCollection` is now async + - `Meteor.user` is now async in server + +- `accounts-facebook@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-github@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-google@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-meetup@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-meteor-developer@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-password@3.0.0`: + + - Some server methods are now async: + - `Accounts.sendResetPasswordEmail` + - `Accounts.sendEnrollmentEmail` + - `Accounts.sendVerificationEmail` + - `Accounts.addEmail` + - `Accounts.removeEmail` + - `Accounts.replaceEmailAsync` + - `Accounts.verifyEmail` + - `Accounts.createUserVerifyingEmail` + - `Accounts.createUser` + - `Accounts.generateVerificationToken` + - `Accounts.generateResetToken` + - `Accounts.forgotPassword` + - `Accounts.setPassword` + - `Accounts.changePassword` + - `Accounts.setUsername` + - `Accounts.findUserByEmail` + - `Accounts.findUserByUsername` + +- `accounts-passwordless@3.0.0`: + + - `Accounts.sendLoginTokenEmail` is now async. + +- `accounts-twitter@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-ui-unstyled@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-weibo@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `allow-deny@2.0.0`: + + - Updated to accept async functions. + +- `appcache@2.0.0`: + + - Updated internal api to use `handlers` + +- `audit-argument-checks@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `autopublish@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `autoupdate@2.0.0`: + + - Updated api to be async, with asyncronous queueing. + +- `babel-compiler@8.0.0`: + + - Add `Babel.compileForShell` + - Removed `Promise.await` default transform. + - Added top-level-await to packages. + +- `babel-runtime@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `base64@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `binary-heap@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `blaze@3.0.0`: + - Todo + +- `boilerplate-generator-tests@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `boilerplate-generator@2.0.0`: + + - `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead. + - Updated to use `handlers` + +- `browser-policy-common@2.0.0`: + + - Updated to use `handlers` + +- `browser-policy-content@2.0.0`: + + - Some methods are now async. See below: + - `BrowserPolicy.content.setPolicy` + - `BrowserPolicy.content.allowInlineScripts` + - `BrowserPolicy.content.disallowInlineScripts` + - `BrowserPolicy.content.disallowAll` + - `BrowserPolicy.setDefaultPolicy` + +- `browser-policy-framing@2.0.0`: + - Package was bumped due to a dependency update. No code changes were made. + +- `browser-policy@2.0.0`: + Updated to use async methods from `browser-policy-common` and `browser-policy-content`. + +- `caching-compiler@2.0.0`: + + - `afterLink` is now async. + - Updated to use now async API. + +- `callback-hook@2.0.0`: + + - Added `forEachAsync` method. + +- `check@2.0.0`: + + - Removed `fibers` related tests. + +- `constraint-solver@2.0.0`: + + - Some methods are now async. See below: + + - `ConstraintSolver.getVersionCostSteps` + - `ConstraintSolver.analyze` + - `ConstraintSolver.resolve` + + - Updated tests to be async. + - Removed a few underscore usage. + - Added updated to use async methods + +- `context@1.0.0`: + + - Removed `fibers` from package. + +- `core-runtime@2.0.0`: + + - Created package to load packages and the app. + - This is the pakcages that sets up the Runtime. + +- `crosswalk@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ddp-client@3.0.0`: + + - Added `isAsyncCall` method to know if call is being made by an async method. + - Removed `fibers` from package. + - Updated tests to use async methods. + - Now `stubPromise` is returned when calling `callAsync` or `applyAsync`. + +- `ddp-common@2.0.0`: + + - Added `.fence` option. + +- `ddp-rate-limiter@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ddp-server@3.0.0`: + + - Updated to use async methods. + - Removed `fibers` from package. + - Updated tests to use async methods. + - Turned server implementation to async. + +- `ddp@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `diff-sequence@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `disable-oplog@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime-client@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime-server@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime@1.0.0`: + + - Added dependency to `@babel/runtime`. + +- `ecmascript@1.0.0`: + + - `ECMAScript.compileForShell` was removed. Use `Babel.compileForShell` from + `babel-compiler` instead. This change makes some build plugins and apps that do not use `babel-compiler` 90mb smaller. + - Added dependency to `@babel/runtime`. + - Moved runtime tests. + +- `ejson@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `email@3.0.0`: + + - `Email.send` is no longer available. Use `Email.sendAsync` instead. + - Updated types to reflext async methods and `Email.send` depracation. + +- `es5-shim@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facebook-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facebook-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facts-base@2.0.0`: + + - turned unorderd deps on `ddp` to false. + +- `facts-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `fetch@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `force-ssl-common@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `force-ssl@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `geojson-utils@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `github-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `github-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `google-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `google-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `hot-code-push@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `http@`: + - Updated handlers to use `handlers` +- `id-map@2.0.0`: + + - Added `forEachAsync` method. + +- `insecure@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `inter-process-messaging@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `launch-screen@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `localstorage@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `logging@2.0.0`: + + - Added dependency to `@babel/runtime`. + +- `logic-solver@3.0.0`: + `Logic.disablingAssertions` is now async. + `minMaxWS` is now async. + +- `meetup-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meetup-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-base@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-developer-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-developer-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-tool@3.0.0`: + + - Changes to how meteor apps are being created [PR](https://github.com/meteor/meteor/pull/12697) + +- `meteor@2.0.0`: + + - Async local storage was added to help deal with async methods. + - Added `promiseEmmiter` to help with async methods. + - Removed `fibers` from package. + +- `minifier-css@2.0.0`: + + - `minifyCss` is now async. + - Removed `fibers` from package. + +- `minifier-js@3.0.0`: + + - `minifyJs` is now async. + - `terserMinify` no longer takes callbacks + - Removed `fibers` from package. + +* `minimongo@2.0.0`: + - `cursor.observe` now returns `isReady` and `isReadyPromise` wich indicates + if the cursor is ready and if the callbacks are have been called. + If you only use it in the `Client` or as a `LocalCollection` things have not + changed. + - `cursor.observeChangesAsync` and `cursor.observeAsync` are added and resolve as promises, returning results similar to their synchronous counterparts. + +- `mobile-experience@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mobile-status-bar@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modern-browsers@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modules-runtime@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modules@1.0.0`: + + - Updated `reify` version. + +- `mongo-decimal@`: + + - Updated to use `async` methods. + +- `mongo-dev-server@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo-id@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo-livedata@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo@2.0.0`: + + - Updated to unify methods, `update`,`insert`,`remove`, `fetch` are now async, they are + the same as their `*Async` counterpart. + - `ensureIndex` and `createIndex` are now async. + - `observeChangesAsync` and `observeAsync` are added and resolve as promises, returning results similar to their synchronous counterparts. + +- `npm-mongo@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth-encryption@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth@`: + + - `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before + - the following server methods are now async: + - `OAuth._renderOauthResults` + - `OAuth._endOfLoginResponse` + - `OAuth.renderEndOfLoginResponse` + - `OAuth._storePendingCredential` + - `OAuth._retrievePendingCredential` + - `ensureConfigured` + - `_cleanStaleResults` + +- `oauth@3.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth1@`: + + - the following server methods are now async: + - `OAuth._storeRequestToken` + - `OAuth._retrieveRequestToken` + +- `oauth1@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth2@`: + + - `OAuth._requestHandlers['2']` is now async. + +- `oauth2@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ordered-dict@2.0.0`: + + - Added `forEachAsync` method. + +- `package-stats-opt-out@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `package-version-parser@4.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `promise@1.0.0`: + + - Removed `fibers` usage + +- `random@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `rate-limit@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reactive-dict@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reactive-var@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reload-safetybelt@2.0.0`: + + - Added `ecmascript` package to `package.js` + +- `reload@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `retry@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `routepolicy@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `server-render@1.0.0`: + + - Updated usage with `getBoilerplate` that are now `async`. + +- `service-configuration@2.0.0`: + + - Updated to use `createIndexAsync`. + +- `session@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `sha@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `shell-server@1.0.0`: + + - Updated to handle promises results. + +- `socket-stream-client@1.0.0`: + + - Updated tests to handle `async` code. + +- `spiderable@`: + + - Updated handlers to use `handlers` that are now using express + - removed `fibers` usage if flag is set to `true` + +- `standard-minifier-css@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `standard-minifier-js@3.0.0`: + + - `processFilesForBundle` is now `async`. + +- `standard-minifiers@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `static-html@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `test-helpers@2.0.0`: + + - Updated to use `async` methods. + - Removed `fibers` usage. + - Added possibliy to use `async` tests. + +- `test-in-browser@2.0.0`: + + - Updated css to be in dark mode. + +- `test-in-console@2.0.0`: + + - Updated log identation. + +- `test-server-tests-in-console-once@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `tinytest-harness@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `tinytest@2.0.0`: + + - Added `test name` to logs. + - Removed `fibers` usage. + +- `twitter-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `twitter-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `typescript@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `underscore-tests@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `underscore@2.0.0`: + + - Removed dependency in meteor package. + +- `url@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `webapp-hashing@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `webapp@2.0.0`: + + - These methods are now async: + + - `WebAppInternals.reloadClientPrograms()` + - `WebAppInternals.pauseClient()` + - `WebAppInternals.generateClientProgram()` + - `WebAppInternals.generateBoilerplate()` + - `WebAppInternals.setInlineScriptsAllowed()` + - `WebAppInternals.enableSubresourceIntegrity()` + - `WebAppInternals.setBundledJsCssUrlRewriteHook()` + - `WebAppInternals.setBundledJsCssPrefix()` + - `WebAppInternals.getBoilerplate` + + - Changed engine from connect to express and changed api naming to match express. See below: + - `WebApp.connectHandlers.use(middleware)` is now `WebApp.handlers.use(middleware)` + - `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawHandlers.use(middleware)` + - `WebApp.connectApp` is now `WebApp.expressApp` + +- `weibo-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `weibo-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +#### New Public API + + + +- `accounts-base`: (2.9+) + + - `Meteor.userAsync()` + +- `callback-hook`:forEachAsync + + - `forEachAsync` + +- `ddp-server`: (2.8+) + + - `Meteor.callAsync()` + +- `meteor`: + - Added `Meteor.isDebug` to execute code in debug builds, activated with the --inspect mode. + +- `minifier-css`: (2.9+) + + - `CssTools.minifyCssAsync()` + +- `mongo`: + + - `Mongo.Collection`: (2.8+) + - `createCappedCollectionAsync` + - `createIndexAsync` + - `dropCollectionAsync` + - `dropIndexAsync` + - `findOneAsync` + - `insertAsync` + - `removeAsync` + - `updateAsync` + - `upsertAsync` + - `Collection.Cursor`: (2.8+) + - `countAsync` + - `fetchAsync` + - `forEachAsync` + - `mapAsync` + - `[Symbol.asyncIterator]` so this code should work: + ```js + for await (const document of collection.find(query, options)) /* ... */ + ``` + +#### Internal API changes + +`accounts-base`: + +- `_attemptLogin` +- `_loginMethod` +- `_runLoginHandlers` + +* Upgraded `node-gyp` to v9.4.0 +* Upgraded `node-pre-gyp` to `@mapbox/node-pre-gyp` v1.0.11 + +#### New Internal API + +`accounts-password`: + +- `Accounts._checkPasswordAsync` + +#### Special thanks to + +- [@denihs](https://github.com/denihs) +- [@Grubba27](https://github.com/Grubba27) +- [@nachocodoner](https://github.com/nachocodoner) +- [@fredmaiaarantes](https://github.com/fredmaiaarantes) +- [@vit0rr](https://github.com/vit0rr) +- [@filipenevola](https://github.com/filipenevola) +- [@zodern](https://github.com/zodern) +- [@radekmie](https://github.com/radekmie) +- [@StorytellerCZ](https://github.com/StorytellerCZ) +- [@gunnartorfis](https://github.com/gunnartorfis) +- [@xet7](https://github.com/xet7) +- [@harryadel](https://github.com/harryadel) +- [@simonwebs](https://github.com/simonwebs) +- [@TylerThompson](https://github.com/TylerThompson) +- [@rodrigok](https://github.com/rodrigok) +- [@zarvox](https://github.com/zarvox) +- [@srsgores](https://github.com/srsgores) +- [@tassoevan](https://github.com/tassoevan) +- [@Torgen](https://github.com/Torgen) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@vincentcarpentier](https://github.com/vincentcarpentier) +- [@ggazzo](https://github.com/ggazzo) +- [@StevenMia](https://github.com/StevenMia) +- [@acemtp](https://github.com/acemtp) + +And so many more people, for making this great framework even better! diff --git a/docs/generators/changelog/versions/3.0.1.md b/docs/generators/changelog/versions/3.0.1.md new file mode 100644 index 0000000000..045446db4e --- /dev/null +++ b/docs/generators/changelog/versions/3.0.1.md @@ -0,0 +1,45 @@ +## v3.0.1, 2024-07-16 + +### Highlights + +* Bump the patch for some packages, so we publish them using Meteor 3 tooling. [PR #13231] + +#### Breaking Changes + +N/A + +#### Internal API changes + +N/A + +#### Migration Steps + +Please run the following command to update your project: + +```bash + +meteor update --release 3.0.1 + +``` + + +#### Meteor Version Release + + +* `Bumped packages`: + - accounts-ui-unstyled@1.7.2 + - crosswalk@1.7.3 + - facebook-oauth@1.11.4 + - npm-mongo@4.17.3 + - package-version-parser@3.2.3 + - twitter-config-ui@1.0.2 + + +#### Special thanks to + +- [@denihs](https://github.com/denihs). + + +For making this great framework even better! + + diff --git a/docs/generators/packages-listing/README.md b/docs/generators/packages-listing/README.md new file mode 100644 index 0000000000..a87a3a8072 --- /dev/null +++ b/docs/generators/packages-listing/README.md @@ -0,0 +1,18 @@ +# Listing of all meteor core packages + +This is a script that will generate a list of all meteor core packages, being ran every build. +This ensures that we always have a list of core packages up to date with their correct links to GitHub. + + +We can always add packages to the list by adding them to the `script.js` constant `OUTSIDE_OF_CORE_PACKAGES`. + +Should follow the following format: + +```js +{ + name: 'package-name', + link: 'https://link-to-github.com/meteor/meteor/tree/devel/packages/package-name' +} +``` + +At the end, this script will update the file located in `docs/source/packages/packages-listing.md` with the new list of packages. diff --git a/docs/generators/packages-listing/script.js b/docs/generators/packages-listing/script.js new file mode 100644 index 0000000000..8101ff6166 --- /dev/null +++ b/docs/generators/packages-listing/script.js @@ -0,0 +1,68 @@ +const fs = require('fs').promises; +const HEADER_TEMPLATE = ` +--- +title: Core Package Listing +description: list of all Meteor core packages. +--- + +[//]: # (Do not edit this file by hand.) + +[//]: # (This is a generated file.) + +[//]: # (If you want to change something in this file) + +[//]: # (go to meteor/docs/generators/packages-listing) + +# Core Packages + + +` + +const OUTSIDE_OF_CORE_PACKAGES = [ + { + name: 'blaze', + link: 'https://github.com/meteor/blaze' + }, + { + name: 'react-packages', + link: 'https://github.com/meteor/react-packages' + } +]; + +const IGNORED = [ + 'depracated', + 'non-core' +]; +const getPackages = async () => { + const packages = + (await fs.readdir('../packages', { withFileTypes: true })) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name) + .filter(name => !IGNORED.includes(name)) + .map(name => { + return { + name, + link: `https://github.com/meteor/meteor/tree/devel/packages/${name}` + } + }); + return [...OUTSIDE_OF_CORE_PACKAGES, ...packages, ]; +} + +const generateMarkdown = (packages) => + packages + .map(({name, link}) => `- [${name}](${link})`) + .join('\n'); + + + +async function main() { + console.log("πŸš‚ Started listing πŸš‚"); + const packages = await getPackages(); + const markdown = generateMarkdown(packages); + const content = HEADER_TEMPLATE + markdown; + console.log("πŸ“ Writing to file πŸ“"); + await fs.writeFile('./source/packages/packages-listing.md', content); + console.log("πŸš€ Done πŸš€"); +} + +main(); diff --git a/docs/history.md b/docs/history.md index 14d85cbb00..3d5da68a9d 100644 --- a/docs/history.md +++ b/docs/history.md @@ -8,6 +8,1485 @@ [//]: # (go to meteor/docs/generators/changelog/docs) +## v3.3.2, 01-09-2025 + +### Highlights + +- Async-compatible account URLs and email-sending coverage [#13740](https://github.com/meteor/meteor/pull/13740) +- Move `findUserByEmail` method from `accounts-password` to `accounts-base` [#13859](https://github.com/meteor/meteor/pull/13859) +- Return `insertedId` on client `upsert` to match Meteor 2.x behavior [#13891](https://github.com/meteor/meteor/pull/13891) +- Unrecognized operator bug fixed [#13895](https://github.com/meteor/meteor/pull/13895) +- Security fix for `sha.js` [#13908](https://github.com/meteor/meteor/pull/13908) + + +All Merged PRs@[GitHub PRs 3.3.2](https://github.com/meteor/meteor/pulls?q=is%3Apr+is%3Amerged+base%3Arelease-3.3.2) + +#### Breaking Changes + +N/A + +##### Cordova Upgrade + +- Enable modern browser support for Cordova unless explicitly disabled [#13896](https://github.com/meteor/meteor/pull/13896) + +#### Internal API changes + +- lodash.template dependency was removed [#13898](https://github.com/meteor/meteor/pull/13898) + +#### Migration Steps + +Please run the following command to update your project: + +```bash +meteor update --release 3.3.2 +``` + +--- + +If you find any issues, please report them to the [Meteor issues tracker](https://github.com/meteor/meteor). + +#### Bumped Meteor Packages + +- accounts-base@3.1.2 +- accounts-password@3.2.1 +- accounts-passwordless@3.0.2 +- meteor-node-stubs@1.2.24 +- babel-compiler@7.12.2 +- boilerplate-generator@2.0.2 +- ecmascript@0.16.13 +- minifier@3.0.4 +- minimongo@2.0.4 +- mongo@2.1.4 +- coffeescript-compiler@2.4.3 +- npm-mongo@6.16.1 +- shell-server@0.6.2 +- typescript@5.6.6 + +#### Bumped NPM Packages + +- meteor-node-stubs@1.2.23 + +#### Special thanks to + +✨✨✨ + +- [@italojs](https://github.com/italojs) +- [@nachocodoner](https://github.com/nachocodoner) +- [@graemian](https://github.com/graemian) +- [@Grubba27](https://github.com/Grubba27) +- [@copleykj](https://github.com/copleykj) + +✨✨✨ + + +## v3.3.1, 05-08-2025 + +### Highlights + +- **MongoDB Driver Upgrades** + - Upgraded core MongoDB driver to `6.16.0` to address latest issues reported [#13710](https://github.com/meteor/meteor/pull/13710) + - Introduced `npm-mongo-legacy` to maintain compatibility with MongoDB 3.6 via `mongodb@6.9.0` [#13736](https://github.com/meteor/meteor/pull/13736) + - Mitigated a cursor leak issue by synchronizing `next()` and `close()` operations [#13786](https://github.com/meteor/meteor/pull/13786) + +- **Improved SWC integration** + - Fixed edge cases in config cache invalidation [#13809](https://github.com/meteor/meteor/pull/13809) + - Ensured `@swc/helpers` is consistently used for better bundle size and performance [#13820](https://github.com/meteor/meteor/pull/13820) + - Updated to SWC `1.12.14` [#13851](https://github.com/meteor/meteor/pull/13851) + +- **Tooling and Build System** + - Fixed regression affecting rebuild behavior [#13810](https://github.com/meteor/meteor/pull/13810) + - Addressed issues getting performance profiles in mounted volumes [#13827](https://github.com/meteor/meteor/pull/13827) + - Fallback to Babel parser when Acorn fails to parse source code [#13844](https://github.com/meteor/meteor/pull/13844) + +- **Mobile Support** + - Upgraded Cordova platform to version 14 [#13837](https://github.com/meteor/meteor/pull/13837) + +- **Developer Experience** + - Added TypeScript types for `isModern` and `getMinimumBrowserVersions` functions [#13704](https://github.com/meteor/meteor/pull/13704) + - Enhanced CLI help output and documented admin commands [#13826](https://github.com/meteor/meteor/pull/13826) + +- **Vite Tooling** + - Updated official Meteor + Vite skeletons [#13835](https://github.com/meteor/meteor/pull/13835) + +- **Runtime & Dependencies** + - Updated to Node.js `22.18.0` and NPM `10.9.3` [#13877](https://github.com/meteor/meteor/pull/13877) + - Bumped `meteor-node-stubs` to `1.2.21` [#13825](https://github.com/meteor/meteor/pull/13825) + +All Merged PRs@[GitHub PRs 3.3.1](https://github.com/meteor/meteor/pulls?q=is%3Apr+is%3Amerged+base%3Arelease-3.3.1) + +#### Breaking Changes + +##### MongoDB Driver Upgrades + +If you're using MongoDB 3.6 or earlier, install the new legacy package: + +```bash +meteor add npm-mongo-legacy +``` +This will pin the MongoDB driver to 6.9.0 for compatibility. + +If you’re on MongoDB 4+, the default [MongoDB driver 6.16.0](https://github.com/mongodb/node-mongodb-native/releases/tag/v6.16.0) is applied automatically. + +Please migrate your database as soon as possible to MongoDB 5 onward, as [MongoDB driver 6.17.0](https://github.com/mongodb/node-mongodb-native/releases/tag/v6.17.0) will drop MongoDB 4 support. We’ll keep offering `npm-mongo-legacy` so you can keep getting Meteor updates with your existing MongoDB legacy version. + +##### Cordova Upgrade + +The Cordova platform has been upgraded to version 14. Refer to the [Cordova Changelog](https://cordova.apache.org/announcements/2025/03/26/cordova-android-14.0.0.html) for more details on the changes and migration steps. + +#### Internal API changes + +N/A + +#### Migration Steps + +Please run the following command to update your project: + +```bash +meteor update --release 3.3.1 +``` + +--- + +While this is a patch release, Meteor 3.3, a recent minor update, introduced a modern build stack that’s now the default for new apps. Here’s how you can migrate to it. + +**Add this to your `package.json` to enable the new modern build stack:** + +```json +"meteor": { + "modern": true +} +``` + +Check the docs for help with the SWC migration, especially if your project uses many Babel plugins. + +[Modern Transpiler: SWC docs](https://docs.meteor.com/about/modern-build-stack/transpiler-swc.html) + +If you find any issues, please report them to the [Meteor issues tracker](https://github.com/meteor/meteor). + +#### Bumped Meteor Packages + +- babel-compiler@7.12.1 +- callback-hook@1.6.1 +- ecmascript@0.16.12 +- minifier-js@3.0.3 +- minimongo@2.0.3 +- modern-browsers@0.2.3 +- mongo@2.1.3 +- npm-mongo-legacy@6.9.0 +- npm-mongo@6.16.0 +- standard-minifier-js@3.1.1 +- tinytest@1.3.2 +- typescript@5.6.5 +- meteor-tool@3.3.1 + +#### Bumped NPM Packages + +- meteor-node-stubs@1.2.21 + +#### Special thanks to + +✨✨✨ + +- [@nachocodoner](https://github.com/nachocodoner) +- [@italojs](https://github.com/italojs) +- [@StorytellerCZ](https://github.com/StorytellerCZ) +- [@JorgenVatle](https://github.com/JorgenVatle) +- [@welkinwong](https://github.com/welkinwong) +- [@Saksham-Goel1107](https://github.com/Saksham-Goel1107) + +✨✨✨ + +## v3.3.0, 2025-06-11 + +### Highlights + +- Support SWC transpiler and minifier for faster dev and builds [PR#13657](https://github.com/meteor/meteor/pull/13657), [PR#13715](https://github.com/meteor/meteor/pull/13715) +- Switch to `@parcel/watcher` for improved native file watching [PR#13699](https://github.com/meteor/meteor/pull/13699), [#13707](https://github.com/meteor/meteor/pull/13707) +- Default to modern architecture, skip legacy processing [PR#13665](https://github.com/meteor/meteor/pull/13665), [PR#13698](https://github.com/meteor/meteor/pull/13698) +- Optimize SQLite for faster startup and better performance [PR#13702](https://github.com/meteor/meteor/pull/13702) +- Support CPU profiling in Meteor 3 bundler [PR#13650](https://github.com/meteor/meteor/pull/13650) +- Improve `meteor profile`: show rebuild steps and total, support `--build` [PR#16](https://github.com/meteor/performance/pull/16), [PR#13694](https://github.com/meteor/meteor/pull/13694) +- Improve `useFind` and `useSubscribe` React hooks +- Add `replaceEmailAsync` helper to Accounts [PR#13677](https://github.com/meteor/meteor/pull/13677) +- Fix user agent detection and oplog collection filtering +- Refine type definitions for Meteor methods and SSR's ServerSink +- Allow opting out of usage stats with `DO_NOT_TRACK` +- Update Node to 22.16.0 and Express to 5.1.0 + +All Merged PRs@[GitHub PRs 3.3](https://github.com/meteor/meteor/pulls?q=is%3Apr+is%3Amerged+base%3Arelease-3.3) + +React Packages Changelog: [react-meteor-data@4.0.0](https://github.com/meteor/react-packages/tree/master/packages/react-meteor-data/CHANGELOG.md#v400-2025-06-11) + +#### Breaking Changes + +- File watching strategy switched to `@parcel/watcher` + - Most setups should be fine, but if issues appear, like when using WSL with host, volumes, or remote setupsβ€”switch to polling. + - Set `METEOR_WATCH_FORCE_POLLING=true` to enable polling. + - Set `METEOR_WATCH_POLLING_INTERVAL_MS=1000` to adjust the interval. + +- `react-meteor-data@4.0.0` + - Independent from the core, only applies if upgraded manually. + - useFind describes no deps by default [PR#431](https://github.com/meteor/react-packages/pull/431) + +#### Internal API changes + +- `express@5.1.0` - Depends on Meteor’s `webapp` package. + - Deprecates non-native promise usage [#154](https://github.com/pillarjs/router/pull/154) + - Use `async/await` or `Promise.resolve` when defining endpoints to avoid deprecation warnings. + +#### Migration Steps + +Please run the following command to update your project: + +```bash +meteor update --release 3.3 +``` + +To apply react-meteor-data changes: + +```bash +meteor add react-meteor-data@4.0.0 +``` + +**Add this to your `package.json` to enable the new modern build stack:** + +```json +"meteor": { + "modern": true +} +``` + +> These settings are on by default for new apps. + +On activate `modern` your app will be updated to use SWC transpiler. It will automatically fallback to Babel if your code can't be transpiled with SWC. + +Check the docs for help with the SWC migration, especially if your project uses many Babel plugins. + +[Modern Transpiler: SWC docs](https://docs.meteor.com/about/modern-build-stack/transpiler-swc.html) + +If you find any issues, please report them to the [Meteor issues tracker](https://github.com/meteor/meteor). + +#### Bumped Meteor Packages + +- accounts-base@3.1.1 +- accounts-password@3.2.0 +- autoupdate@2.0.1 +- babel-compiler@7.12.0 +- boilerplate-generator@2.0.1 +- ddp-client@3.1.1 +- ecmascript@0.16.11 +- ejson@1.1.5 +- meteor@2.1.1 +- minifier-js@3.0.2 +- modern-browsers@0.2.2 +- mongo@2.1.2 +- server-render@0.4.3 +- socket-stream-client@0.6.1 +- standard-minifier-js@3.1.0 +- typescript@5.6.4 +- webapp@2.0.7 +- meteor-tool@3.3.0 + +#### Bumped NPM Packages + +- meteor-node-stubs@1.2.17 + +#### Special thanks to + +✨✨✨ + +- [@nachocodoner](https://github.com/nachocodoner) +- [@italojs](https://github.com/italojs) +- [@Grubba27](https://github.com/Grubba27) +- [@zodern](https://github.com/zodern) +- [@9Morello](https://github.com/9Morello) +- [@welkinwong](https://github.com/welkinwong) +- [@Poyoman39](https://github.com/Poyoman39) +- [@PedroMarianoAlmeida](https://github.com/PedroMarianoAlmeida) +- [@harryadel](https://github.com/harryadel) +- [@ericm546](https://github.com/ericm546) +- [@StorytellerCZ](https://github.com/StorytellerCZ) + +✨✨✨ + + +## v3.0.1, 2024-07-16 + +### Highlights + +* Bump the patch for some packages, so we publish them using Meteor 3 tooling. [PR](https://github.com/meteor/meteor/pull/13231) + +#### Breaking Changes + +N/A + +#### Internal API changes + +N/A + +#### Migration Steps + +Please run the following command to update your project: + +```bash + +meteor update --release 3.0.1 + +``` + + +#### Meteor Version Release + + +* `Bumped packages`: + - accounts-ui-unstyled@1.7.2 + - crosswalk@1.7.3 + - facebook-oauth@1.11.4 + - npm-mongo@4.17.3 + - package-version-parser@3.2.3 + - twitter-config-ui@1.0.2 + + +#### Special thanks to + +- [@denihs](https://github.com/denihs). + + +For making this great framework even better! + + +## v3.0, 2024-07-15 + +### Highlights + +#### Breaking Changes + +- `accounts-2fa@3.0.0`: + + - Some methods are now async. See below: + - `Accounts._is2faEnabledForUser` + - `(Meteor Method) - generate2faActivationQrCode` + - `(Meteor Method) - enableUser2fa` + - `(Meteor Method) - disableUser2fa` + - `(Meteor Method) - has2faEnabled` + +- `accounts-base@3.0.0`: + + - `methods.removeOtherTokens` is now async + - `Accounts.destroyToken` is now async + - `Accounts.insertUserDoc` is now async + - `Accounts.updateOrCreateUserFromExternalService` is now async + - `Accounts.expirePasswordToken` is now async + - `Accounts.setupUsersCollection` is now async + - `Meteor.user` is now async in server + +- `accounts-facebook@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-github@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-google@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-meetup@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-meteor-developer@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-password@3.0.0`: + + - Some server methods are now async: + - `Accounts.sendResetPasswordEmail` + - `Accounts.sendEnrollmentEmail` + - `Accounts.sendVerificationEmail` + - `Accounts.addEmail` + - `Accounts.removeEmail` + - `Accounts.verifyEmail` + - `Accounts.createUserVerifyingEmail` + - `Accounts.createUser` + - `Accounts.generateVerificationToken` + - `Accounts.generateResetToken` + - `Accounts.forgotPassword` + - `Accounts.setPassword` + - `Accounts.changePassword` + - `Accounts.setUsername` + - `Accounts.findUserByEmail` + - `Accounts.findUserByUsername` + +- `accounts-passwordless@3.0.0`: + + - `Accounts.sendLoginTokenEmail` is now async. + +- `accounts-twitter@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-ui-unstyled@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `accounts-weibo@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `allow-deny@2.0.0`: + + - Updated to accept async functions. + +- `appcache@2.0.0`: + + - Updated internal api to use `handlers` + +- `audit-argument-checks@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `autopublish@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `autoupdate@2.0.0`: + + - Updated api to be async, with asyncronous queueing. + +- `babel-compiler@8.0.0`: + + - Add `Babel.compileForShell` + - Removed `Promise.await` default transform. + - Added top-level-await to packages. + +- `babel-runtime@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `base64@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `binary-heap@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `blaze@3.0.0`: + - Todo + +- `boilerplate-generator-tests@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `boilerplate-generator@2.0.0`: + + - `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead. + - Updated to use `handlers` + +- `browser-policy-common@2.0.0`: + + - Updated to use `handlers` + +- `browser-policy-content@2.0.0`: + + - Some methods are now async. See below: + - `BrowserPolicy.content.setPolicy` + - `BrowserPolicy.content.allowInlineScripts` + - `BrowserPolicy.content.disallowInlineScripts` + - `BrowserPolicy.content.disallowAll` + - `BrowserPolicy.setDefaultPolicy` + +- `browser-policy-framing@2.0.0`: + - Package was bumped due to a dependency update. No code changes were made. + +- `browser-policy@2.0.0`: + Updated to use async methods from `browser-policy-common` and `browser-policy-content`. + +- `caching-compiler@2.0.0`: + + - `afterLink` is now async. + - Updated to use now async API. + +- `callback-hook@2.0.0`: + + - Added `forEachAsync` method. + +- `check@2.0.0`: + + - Removed `fibers` related tests. + +- `constraint-solver@2.0.0`: + + - Some methods are now async. See below: + + - `ConstraintSolver.getVersionCostSteps` + - `ConstraintSolver.analyze` + - `ConstraintSolver.resolve` + + - Updated tests to be async. + - Removed a few underscore usage. + - Added updated to use async methods + +- `context@1.0.0`: + + - Removed `fibers` from package. + +- `core-runtime@2.0.0`: + + - Created package to load packages and the app. + - This is the pakcages that sets up the Runtime. + +- `crosswalk@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ddp-client@3.0.0`: + + - Added `isAsyncCall` method to know if call is being made by an async method. + - Removed `fibers` from package. + - Updated tests to use async methods. + - Now `stubPromise` is returned when calling `callAsync` or `applyAsync`. + +- `ddp-common@2.0.0`: + + - Added `.fence` option. + +- `ddp-rate-limiter@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ddp-server@3.0.0`: + + - Updated to use async methods. + - Removed `fibers` from package. + - Updated tests to use async methods. + - Turned server implementation to async. + +- `ddp@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `diff-sequence@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `disable-oplog@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime-client@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime-server@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ecmascript-runtime@1.0.0`: + + - Added dependency to `@babel/runtime`. + +- `ecmascript@1.0.0`: + + - `ECMAScript.compileForShell` was removed. Use `Babel.compileForShell` from + `babel-compiler` instead. This change makes some build plugins and apps that do not use `babel-compiler` 90mb smaller. + - Added dependency to `@babel/runtime`. + - Moved runtime tests. + +- `ejson@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `email@3.0.0`: + + - `Email.send` is no longer available. Use `Email.sendAsync` instead. + - Updated types to reflext async methods and `Email.send` depracation. + +- `es5-shim@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facebook-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facebook-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `facts-base@2.0.0`: + + - turned unorderd deps on `ddp` to false. + +- `facts-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `fetch@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `force-ssl-common@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `force-ssl@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `geojson-utils@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `github-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `github-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `google-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `google-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `hot-code-push@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `http@`: + - Updated handlers to use `handlers` +- `id-map@2.0.0`: + + - Added `forEachAsync` method. + +- `insecure@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `inter-process-messaging@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `launch-screen@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `localstorage@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `logging@2.0.0`: + + - Added dependency to `@babel/runtime`. + +- `logic-solver@3.0.0`: + `Logic.disablingAssertions` is now async. + `minMaxWS` is now async. + +- `meetup-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meetup-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-base@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-developer-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-developer-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `meteor-tool@3.0.0`: + + - Changes to how meteor apps are being created [PR](https://github.com/meteor/meteor/pull/12697) + +- `meteor@2.0.0`: + + - Async local storage was added to help deal with async methods. + - Added `promiseEmmiter` to help with async methods. + - Removed `fibers` from package. + +- `minifier-css@2.0.0`: + + - `minifyCss` is now async. + - Removed `fibers` from package. + +- `minifier-js@3.0.0`: + + - `minifyJs` is now async. + - `terserMinify` no longer takes callbacks + - Removed `fibers` from package. + +* `minimongo@2.0.0`: + - `cursor.observe` now returns `isReady` and `isReadyPromise` wich indicates + if the cursor is ready and if the callbacks are have been called. + If you only use it in the `Client` or as a `LocalCollection` things have not + changed. + - `cursor.observeChangesAsync` and `cursor.observeAsync` are added and resolve as promises, returning results similar to their synchronous counterparts. + +- `mobile-experience@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mobile-status-bar@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modern-browsers@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modules-runtime@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `modules@1.0.0`: + + - Updated `reify` version. + - All modules are described as strict mode + +- `mongo-decimal@`: + + - Updated to use `async` methods. + +- `mongo-dev-server@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo-id@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo-livedata@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `mongo@2.0.0`: + + - Updated to unify methods, `update`,`insert`,`remove`, `fetch` are now async, they are + the same as their `*Async` counterpart. + - `ensureIndex` and `createIndex` are now async. + - `observeChangesAsync` and `observeAsync` are added and resolve as promises, returning results similar to their synchronous counterparts. + +- `npm-mongo@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth-encryption@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth@`: + + - `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before + - the following server methods are now async: + - `OAuth._renderOauthResults` + - `OAuth._endOfLoginResponse` + - `OAuth.renderEndOfLoginResponse` + - `OAuth._storePendingCredential` + - `OAuth._retrievePendingCredential` + - `ensureConfigured` + - `_cleanStaleResults` + +- `oauth@3.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth1@`: + + - the following server methods are now async: + - `OAuth._storeRequestToken` + - `OAuth._retrieveRequestToken` + +- `oauth1@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `oauth2@`: + + - `OAuth._requestHandlers['2']` is now async. + +- `oauth2@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `ordered-dict@2.0.0`: + + - Added `forEachAsync` method. + +- `package-stats-opt-out@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `package-version-parser@4.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `promise@1.0.0`: + + - Removed `fibers` usage + +- `random@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `rate-limit@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reactive-dict@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reactive-var@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `reload-safetybelt@2.0.0`: + + - Added `ecmascript` package to `package.js` + +- `reload@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `retry@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `routepolicy@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `server-render@1.0.0`: + + - Updated usage with `getBoilerplate` that are now `async`. + +- `service-configuration@2.0.0`: + + - Updated to use `createIndexAsync`. + +- `session@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `sha@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `shell-server@1.0.0`: + + - Updated to handle promises results. + +- `socket-stream-client@1.0.0`: + + - Updated tests to handle `async` code. + +- `spiderable@`: + + - Updated handlers to use `handlers` that are now using express + - removed `fibers` usage if flag is set to `true` + +- `standard-minifier-css@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `standard-minifier-js@3.0.0`: + + - `processFilesForBundle` is now `async`. + +- `standard-minifiers@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `static-html@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `test-helpers@2.0.0`: + + - Updated to use `async` methods. + - Removed `fibers` usage. + - Added possibliy to use `async` tests. + +- `test-in-browser@2.0.0`: + + - Updated css to be in dark mode. + +- `test-in-console@2.0.0`: + + - Updated log identation. + +- `test-server-tests-in-console-once@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `tinytest-harness@1.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `tinytest@2.0.0`: + + - Added `test name` to logs. + - Removed `fibers` usage. + +- `twitter-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `twitter-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `typescript@5.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `underscore-tests@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `underscore@2.0.0`: + + - Removed dependency in meteor package. + +- `url@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `webapp-hashing@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `webapp@2.0.0`: + + - These methods are now async: + + - `WebAppInternals.reloadClientPrograms()` + - `WebAppInternals.pauseClient()` + - `WebAppInternals.generateClientProgram()` + - `WebAppInternals.generateBoilerplate()` + - `WebAppInternals.setInlineScriptsAllowed()` + - `WebAppInternals.enableSubresourceIntegrity()` + - `WebAppInternals.setBundledJsCssUrlRewriteHook()` + - `WebAppInternals.setBundledJsCssPrefix()` + - `WebAppInternals.getBoilerplate` + + - Changed engine from connect to express and changed api naming to match express. See below: + - `WebApp.connectHandlers.use(middleware)` is now `WebApp.handlers.use(middleware)` + - `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawHandlers.use(middleware)` + - `WebApp.connectApp` is now `WebApp.expressApp` + +- `weibo-config-ui@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +- `weibo-oauth@2.0.0`: + + - Package was bumped due to a dependency update. No code changes were made. + +#### New Public API + + + +- `accounts-base`: (2.9+) + + - `Meteor.userAsync()` + +- `callback-hook`:forEachAsync + + - `forEachAsync` + +- `ddp-server`: (2.8+) + + - `Meteor.callAsync()` + +- `meteor`: + - Added `Meteor.isDebug` to execute code in debug builds, activated with the --inspect mode. + +- `minifier-css`: (2.9+) + + - `CssTools.minifyCssAsync()` + +- `mongo`: + + - `Mongo.Collection`: (2.8+) + - `createCappedCollectionAsync` + - `createIndexAsync` + - `dropCollectionAsync` + - `dropIndexAsync` + - `findOneAsync` + - `insertAsync` + - `removeAsync` + - `updateAsync` + - `upsertAsync` + - `Collection.Cursor`: (2.8+) + - `countAsync` + - `fetchAsync` + - `forEachAsync` + - `mapAsync` + - `[Symbol.asyncIterator]` so this code should work: + ```js + for await (const document of collection.find(query, options)) /* ... */ + ``` + +#### Internal API changes + +`accounts-base`: + +- `_attemptLogin` +- `_loginMethod` +- `_runLoginHandlers` + +* Upgraded `node-gyp` to v9.4.0 +* Upgraded `node-pre-gyp` to `@mapbox/node-pre-gyp` v1.0.11 + +#### New Internal API + +`accounts-password`: + +- `Accounts._checkPasswordAsync` + +#### Special thanks to + +- [@denihs](https://github.com/denihs) +- [@Grubba27](https://github.com/Grubba27) +- [@nachocodoner](https://github.com/nachocodoner) +- [@fredmaiaarantes](https://github.com/fredmaiaarantes) +- [@vit0rr](https://github.com/vit0rr) +- [@filipenevola](https://github.com/filipenevola) +- [@zodern](https://github.com/zodern) +- [@radekmie](https://github.com/radekmie) +- [@StorytellerCZ](https://github.com/StorytellerCZ) +- [@gunnartorfis](https://github.com/gunnartorfis) +- [@xet7](https://github.com/xet7) +- [@harryadel](https://github.com/harryadel) +- [@simonwebs](https://github.com/simonwebs) +- [@TylerThompson](https://github.com/TylerThompson) +- [@rodrigok](https://github.com/rodrigok) +- [@zarvox](https://github.com/zarvox) +- [@srsgores](https://github.com/srsgores) +- [@tassoevan](https://github.com/tassoevan) +- [@Torgen](https://github.com/Torgen) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@vincentcarpentier](https://github.com/vincentcarpentier) +- [@ggazzo](https://github.com/ggazzo) +- [@StevenMia](https://github.com/StevenMia) +- [@acemtp](https://github.com/acemtp) + +And so many more people, for making this great framework even better! +## v2.16.0, 2024-05-14 + +### Highlights + +- Support observeChangesAsync and observeAsync. [PR](https://github.com/meteor/meteor/pull/13025) +- New mongo package options to optimize Oplog tailing performance to include/exclude certain collections [PR](https://github.com/meteor/meteor/pull/13009) + +#### Migration Steps + +To update from 2.15 to this one, you can run: + +``` +meteor update --release 2.16 +``` + +If you're coming from an older version, please check our [Migration Guides](https://guide.meteor.com/2.14-migration). + +#### Breaking Changes +N/A + +#### Internal API changes + +* Add method name to MethodInvocation in DDP messages + +#### Meteor Version Release + +* Meteor tool + - Updated Svelte skeleton + - Update tsconfig.json for Svelte skeleton + - Updated Solid skeleton NPM dependencies + +* Blaze + - Support of async dynamic attributes [PR](https://github.com/meteor/blaze/pull/460) + - Fix Blaze._expandAttributes returns empty object, if null. [PR](https://github.com/meteor/blaze/pull/458) + +* `accounts-base@2.2.11` + - Supported session storage to store accounts login token [PR](https://github.com/meteor/meteor/pull/13046) + - Update config checking + - Added new types [PR](https://github.com/meteor/meteor/pull/13042) + +* `accounts-oauth@1.4.4` + - Remove config checking as it is done in `accounts-base` + +* `accounts-ui-unstyled@1.7.1` + - `Connect with Twitter` is now `Connect with X/Twitter` + +* `check@1.4.1`: + - Added an optional flag to immediately throw error when all checks failed. [PR](https://github.com/meteor/meteor/pull/12970) + +* `ddp-common@1.4.1` + - Add method name to MethodInvocation + +* `ddp-client@2.6.2` + - Add method name to MethodInvocation + +* `ddp-server@2.7.1` + - Add method name to MethodInvocation + +* `twitter-config-ui@1.0.2` + - Update setup instructions + +* `email@2.2.6` + - Nodemailer update to v6.9.10 + - `@types/nodemailer` updated to v6.4.14 + - Adds the ability to encrypt your emails using PGP [PR](https://github.com/meteor/meteor/pull/12991) + +* `logging@1.3.4` + - Type update + +* `minimongo@1.9.4` + - Support observeChangesAsync and observeAsync [PR](https://github.com/meteor/meteor/pull/13025) + - Report and extend test cases for the old async behaviors + +* `minifier-js@2.8.0` + - Update terser to v5.31.0 + +* `mongo@1.16.10` + - Support a new option to include/exclude certain collections for oplog tailing [PR](https://github.com/meteor/meteor/pull/13009) + +* `reload-safetybelt@1.0.13` + - Remove underscore dependency + +* `service-configuration@1.3.4` + - Type update + +#### Independent releases + +* `mongo@1.16.9`: + - Set `minPoolSize` for oplog + +* `underscore@1.6.1` + - Fix bug in `_.intersection` + +#### Contributors + +- [nachocodoner](https://github.com/nachocodoner) +- [StorytellerCZ](https://github.com/StorytellerCZ) +- [jamauro](https://github.com/jamauro) +- [Twisterking](https://github.com/Twisterking) +- [harryadel](https://github.com/harryadel) + +Thanks for making this great framework even better! + +## v2.15.0, 2024-02-05 + +### Highlights + +* Bumps embedded MongoDB to 7.0.5. + +#### Breaking Changes + +N/A + +#### Internal API changes + +N/A + +#### Migration Steps + +In development, if you're using Linux, you might get an error like `version GLIBCXX_3.4.26 not found` or something related to g++. + +This is related to your g++ version. With MongoDB 7, you need to have g++ 11 or higher. So make sure to have this updated. + +This will happen only if you are trying to run your Meteor application with a MongoDB 7 version. If you run your app with a MONGO_URL pointing to a different MongoDB version, you won't have this issue. + +```bash + +meteor update --release 2.15 + +``` + + +#### Meteor Version Release + + +* `Command line`: + - The bundle version was changed to include embedded MongoDB to 7.0.5. + - Fix cordova launch screen warnings on 2.15 [PR](https://github.com/meteor/meteor/pull/12971) +* `underscore@1.6.0`: + - A test related to [PR](https://github.com/meteor/meteor/pull/12798) to see if the tests can manage the first update step. [PR](https://github.com/meteor/meteor/pull/12912) +* `service-configuration@1.3.3`: + - added new types* [PR](https://github.com/meteor/meteor/pull/12922) +* `meteor@1.11.5`: + - added new types [PR](https://github.com/meteor/meteor/pull/12922) +* `accounts-base@2.2.10`: + - Added missing type for createUserVerifyingEmail [PR](https://github.com/meteor/meteor/pull/12919) + +#### Special thanks to + +- [@Grubba27](https://github.com/Grubba27). +- [@denihs](https://github.com/denihs). +- [@mcorbelli](https://github.com/mcorbelli). +- [@matheusccastroo](https://github.com/matheusccastroo). +- [@StorytellerCZ](https://github.com/StorytellerCZ). +- [@ebroder](https://github.com/ebroder). +- [@nachocodoner](https://github.com/nachocodoner). + +For making this great framework even better! + + +## v2.14.0, 2023-12-12 + + +### Highlights + +Hacktoberfest release! πŸŽ‰ + +* MongoDB driver has been updated to v4.17.2. + +* You can now set `DISABLE_SOCKJS_CORS=1` if you want to prevent SockJS from setting CORS headers. Do not set this option if you will have DDP clients from other origins connecting to the DDP server. [PR](https://github.com/meteor/meteor/pull/12789) + +* Added guide on [how to prepare for Meteor 3.0 migration](https://guide.meteor.com/prepare-meteor-3.0). + +* New DDP merge strategy `NO_MERGE_MULTI`, which is similar to `NO_MERGE`, but it does track whether a document is used by multiple publications. [PR](https://github.com/meteor/meteor/pull/12742) + +* Appcache has been further deprecated and moved to the deprecated packages folder. + +* Added `Accounts.createUserAsync` into the client. + +* Many packages had their underscore dependency removed. + +* Cordova has been updated to v12.0.1 for Android and v7.0.1 for iOS, being able to build to SDK 33. + +* `meteor create` command is now interactive! + +* Added `firstRunPromise` property to `Tracker` autorun blocks, that forces autorun blocks to be executed in synchronous-looking order by storing the value autorun promise thus making it awaitable. + +#### Migration Steps + +##### Android splash screen +If you have been using `splash-screen` for Cordova, you need to update your code as Android changed their splash screen API, +the `cordova-plugin-splashscreen` is now on `cordova-android` core, so we have removed the dependency from the `splash-screen` +package. As a result we are dropping the support for dark mode splash screen on Android. + +To create this now you need to create two themes on your `config.xml` file. + +> Note that it's still possible to have it by adding the according themes with App.appendToConfig and App.addResourceFile - but this is not something Meteor will do automatically right now. + +For more information you can check our [Migration Guide](https://guide.meteor.com/2.14-migration.html) + +## Breaking Changes + +* `splash-screen` package has removed the `cordova-plugin-splashscreen` dependency. See migration steps for more info. + +## Docs + +- Added guide on [how to prepare for Meteor 3.0 migration](https://guide.meteor.com/prepare-meteor-3.0). +- Added guide on [performance improvements](https://guide.meteor.com/performance-improvement). +- Added FAQ about [Meteor 3](https://guide.meteor.com/3.0-migration). + +## Internal API changes + +* Tool + - Rename `EACCESS` to `EACCES` to follow the Windows spelling + - Fixed links in skeletons + - Fixed build issue in Vue skeleton + - Updated `source-map-support` + - Fixed bugs in negated β€œin” and β€œinstanceof” expressions + - Updated `semver` to v7.5.4 + - Updated `@meteorjs/babel` to v7.18.4 + - Cordova has been updated to v12.0.1 for Android and v7.0.1 for iOS, being able to build to SDK 33. + - `meteor create` command was re-made to be more interactive + +## Meteor Version Release + +* `accounts-base@2.2.10` + - Ensure that `onLogin` callback fires properly + - Indexes are now created asynchronously + +* `accounts-oauth@1.4.3` + - Indexes are now created asynchronously + +* `accounts-password@2.4.0` + - Add `Accounts.createUserAsync` to the client, a promise-based version of `Accounts.createUser` + - Indexes are now created asynchronously + +* `accounts-passwordless@2.1.4` + - Fix #12401, ensure that user is found with ID + - Indexes are now created asynchronously + +* `babel-compiler@7.10.5` + - Updated `@meteorjs/babel` to v7.18.4 + +* `boilerplate-generator@1.7.2` + - Removed Underscore dependency + +* `browser-policy-content@1.1.3` + - Removed Underscore dependency + +* `constraint-solver@1.2.1` + - Removed Underscore dependency + +* `crosswalk@1.7.2` + - Updated `cordova-plugin-crosswalk-webview` to v2.4.0 + - Deprecated the package + +* `ddp-rate-limiter@1.2.1` + - Removed Underscore dependency +* `ddp-server@2.7.0`: + - Allow setting `DISABLE_SOCKJS_CORS` to prevent SockJS from setting CORS headers + - Added new publication strategy `NO_MERGE_MULTI` + +* `ecmascript@0.16.8`: + - Bumped to get latest version of `@babel/compiler` + +* `facebook-oauth@1.11.3`: + - Updated default version of Facebook GraphAPI to v17 + +* `launch-screen@2.0.0` + - Removed `cordova-plugin-splashscreen` dependency + +* `fetch@0.1.4`: + - Update `node-fetch` to version 1.6.12 + - Update `whatwg-fetch` to version 3.6.17 + +* `logging@1.3.3`: + - Added TS types + - Updated `chalk` to v4.1.2 + +* `logic-solver@2.0.9` + - Removed Underscore dependency + +* `meteor@1.11.5`: + - Improve TS types + +* `mobile-experience@1.1.1`: + - Bumped to get latests version of `cordova` dependencies + +* `modern-browsers@0.1.10` + - Added `appleMail` user agent to allow modern bundle on iPads + +* `modules@0.20.0` + - Updated version of reify to v0.24.1 + +* `mongo@1.16.8` + - Added deprecation messages into type definitions + - Fix ObjectIDs handling in oplogV2V1Converter + +* `npm-mongo@4.17.2`: + - Bumped MongoDB driver to version 4.17.2 + +* `oauth@2.2.1` + - Indexes are now created asynchronously + - `remove` DB calls migrated to `removeAsync` + +* `package-version-parser@3.2.2` + - Updated `semver` to v7.5.4 + +* `react-fast-refresh@0.2.8`: + - Updated `semver` to version 7.5.4 + +* `service-configuration@1.3.3` + - Indexes are now created asynchronously + - Add types for ConfigError + +* `socket-stream-client@0.5.2` + - Removed Underscore dependency + +* `standard-minifier-css@1.9.2` + - Updated `@babel/runtime` to v7.23.5 + - Updated `minifier-css` to v1.6.4 + - Updated `logging` package to v1.3.2 + +* `test-server-tests-in-console-once@1.0.12` + - Removed Underscore dependency + +* `tinytest@1.2.3` + - Removed Underscore dependency + +* `tracker@1.3.3` + - Added `firstRunPromise` property, that forces autorun blocks to be executed + in synchronous-looking order by storing the value autorun promise + thus making it awaitable + +* `typescript@4.9.5`: + - Updated to 4.9.5 + +* `webapp@1.13.8` + - Updated `cordova-plugin-meteor-webapp` to v2.0.3 + - Updated `cookie-parser` to v1.4.6 + - Updated `send` to v0.18.0 + - Updated `stream-to-string` to v1.2.1 + - Updated `qs` to v6.11.2 + - Updated `@types/connect` to v3.4.38 + + +## Independent releases + +* `google-oauth@1.4.4`: + - Remove logging request/response in google_server + +* NPM `@meteorjs/babel@7.18.4` + - Updated `@meteorjs/reify` to v0.24.1 + +* NPM `@meteorjs/babel-preset-meteor@7.10.1` + - Add Facebook in-app browser + +* NPM `cordova-plugin-meteor-webapp@2.0.2` + - Fixed Android hot code push failing + +* NPM `cordova-plugin-meteor-webapp@2.0.3` + - Fix pull manifest from correct url if parameter are used in baseurl + +* NPM `meteor-node-stubs@1.2.6` + - Update dependencies + - Deep update dependencies that were highlighted by `npm audit` + +## Contributors + +- [@StorytellerCZ](https://github.com/sponsors/StorytellerCZ) +- [@Grubba27](https://github.com/sponsors/Grubba27) +- [@vit0rr](https://github.com/vit0rr) +- [@realyze](https://github.com/realyze) +- [@jamauro](https://github.com/jamauro) +- [@Torgen](https://github.com/Torgen) +- [@brucejo75](https://github.com/brucejo75) +- [@zodern](https://github.com/sponsors/zodern) +- [@alisnic](https://github.com/alisnic) +- [@ebroder](https://github.com/ebroder) +- [@BANSAL-NISHU](https://github.com/BANSAL-NISHU) +- [@salmanhasni](https://github.com/salmanhasni) +- [@jdgjsag67251](https://github.com/jdgjsag67251) +- [@guncebektas](https://github.com/guncebektas) +- [@harryadel](https://github.com/harryadel) +- [@dd137](https://github.com/dd137) +- [@matheusccastroo](https://github.com/matheusccastroo) +- [@mr-loop-1](https://github.com/mr-loop-1) + +For making this great framework even better! ## v2.13.3, 2023-09-08 @@ -122,10 +1601,10 @@ for more information about the problems and issues you might find while migratin #### Internal changes -* `ddp-server@2.6.2`: +* `ddp-server@3.0.0`: - Updated livedata server test to be more easily debbuged. -* `mongo@1.16.7`: +* `mongo@2.0.0`: - Updated deprecated reference in Mongo package. #### Migration Steps @@ -199,7 +1678,7 @@ N/A #### Migration Steps -Now if you want to check where do you call old-style api methods +Now if you want to check where do you call old-style api methods you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. @@ -208,7 +1687,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `accounts-base@2.2.8`: - Added `loginServiceConfiguration` type. - Added the `collection` option property, in order to be able to set the collection for Accounts, - more can be seen in the [discussion](https://github.com/meteor/meteor/discussions/12544#discussioncomment-5240763) + more can be seen in the [discussion](https://github.com/meteor/meteor/discussions/12544#discussioncomment-5240763) and in the [related issue](https://github.com/meteor/meteor-feature-requests/issues/20). - `onCreateUserHook` now accept promises and wait if necessary. @@ -220,7 +1699,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `browser-policy-framing@1.1.2`: - Added `es5` compatible syntax. - + * `browser-policy@1.1.2`: - Updated test name. @@ -270,7 +1749,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `mongo@1.16.6`: - Added `countDocuments` and `estimatedDocumentCount` types. - - Added warning for when old style apis are being used, to use this feature, + - Added warning for when old style apis are being used, to use this feature, use the variable`WARN_WHEN_USING_OLD_API=true` before starting the Meteor process. - Oplog driver updated to not throw error when MongoDB server and Meteor client mismatch. [issue](https://github.com/meteor/meteor/issues/12516) @@ -316,7 +1795,6 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. - [@zodern](https://github.com/zodern). - [@dmromanov](https://github.com/dmromanov). - [@matheusccastroo](https://github.com/matheusccastroo). - ## v2.11.0, 2023-03-02 ### Highlights @@ -981,7 +2459,7 @@ N/A * `mongo@1.15.0` - New option `Meteor.settings.packages.mongo.reCreateIndexOnOptionMismatch` for case when an index with the same name, but different options exists it will be re-created. - - If there is an error on index creation Meteor will output a better message naming the collection and index where the error occured. [PR](https://github.com/meteor/meteor/pull/11995). + - If there is an error on index creation Meteor will output a better message naming the collection and index where the error occurred. [PR](https://github.com/meteor/meteor/pull/11995). * `modern-browsers@0.1.8` - New api `getMinimumBrowserVersions` to access the `minimumBrowserVersions`. [PR](https://github.com/meteor/meteor/pull/11998). * `socket-stream-client@0.5.0` @@ -1196,7 +2674,7 @@ Read our [Migration Guide](https://guide.meteor.com/2.6-migration.html) for this - 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. + - fields option is deprecated, we are maintaining a translation layer to "projection" field (now preferred) 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. @@ -3475,6 +4953,7 @@ N/A setMinimumBrowserVersions({ chrome: 49, firefox: 45, + firefoxIOS: 100, edge: 12, ie: Infinity, // Sorry, IE11. mobile_safari: [9, 2], // 9.2.0+ diff --git a/docs/jsdoc/jsdoc-conf.json b/docs/jsdoc/jsdoc-conf.json index 4f220413fb..4fd2956fc1 100644 --- a/docs/jsdoc/jsdoc-conf.json +++ b/docs/jsdoc/jsdoc-conf.json @@ -1,14 +1,9 @@ { - "plugins": ["plugins/markdown"], - "markdown": { - "parser": "gfm" - }, "source": { "exclude": [ "packages/ddp/sockjs-0.3.4.js", "packages/test-in-browser/diff_match_patch_uncompressed.js", "packages/jquery/jquery.js", - "packages/underscore/underscore.js", "packages/json/json2.js", "packages/minimongo/minimongo_tests.js", "tools/node_modules", @@ -18,5 +13,9 @@ "**/node_modules", "npm-packages" ] + }, + "plugins": [ "plugins/markdown"], + "markdown": { + "parser": "gfm" } } diff --git a/docs/long-form/oplog-observe-driver.md b/docs/long-form/oplog-observe-driver.md index a1ba8a1a38..25ded4c09e 100644 --- a/docs/long-form/oplog-observe-driver.md +++ b/docs/long-form/oplog-observe-driver.md @@ -8,7 +8,7 @@ Most users don't use `observeChanges` directly, but whenever you return a cursor Previous versions of Meteor only had one strategy for implementing `observeChanges`: the "poll-and-diff" algorithm, implemented by the `PollingObserveDriver` class. This approach re-runs the query frequently and calculates the difference between each set of results. This code is simple and has historically contained very few bugs. But the cost of the `PollingObserveDriver` is proportional to the poll frequency and to the size of each query result, and the time from database change to callback invocation depends on whether the write originated in the same Meteor server process (very fast) or in another process (up to 10 seconds). -Starting with Meteor 0.7.0, Meteor can use an additional strategy to implemnt `observeChanges`: **oplog tailing**, implemented by the `OplogObserveDriver` class. +Starting with Meteor 0.7.0, Meteor can use an additional strategy to implement `observeChanges`: **oplog tailing**, implemented by the `OplogObserveDriver` class. Meteor now knows how to read the MongoDB "operations log" --- a special collection that records all the write operations as they are applied to your database. This means changes to the database can be instantly noticed and reflected in Meteor, whether they originated from Meteor or from an external database client. Oplog tailing has different performance characteristics than "poll-and-diff" which are superior in many cases. `OplogObserveDriver` needs to understand the meaning of MongoDB [selectors](http://docs.meteor.com/#selectors), [field specifiers](http://docs.meteor.com/#fieldspecifiers), [modifiers](http://docs.meteor.com/#modifiers), and [sort specifiers](http://docs.meteor.com/#sortspecifiers) at a much deeper level than `PollingObserveDriver`. This is because it actually needs to understand how write operations that it sees in the oplog interact with queries, instead of just relying on the MongoDB server to repeatedly execute the query. To deal with these structures, `OplogObserveDriver` uses Meteor's implementation of the MongoDB query engine, [Minimongo](https://github.com/meteor/meteor/tree/master/packages/minimongo), which Meteor also uses as its client-side local database cache. diff --git a/docs/netlify.toml b/docs/netlify.toml index 391633b6f3..9af188b853 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -1,3 +1,3 @@ [build] publish = "public" - command = "npm install && npm run build" + command = "npm cache clear --force && npm install --legacy-peer-deps && npm run build" diff --git a/docs/package-lock.json b/docs/package-lock.json index c6866469f7..9d4a412012 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -4,6 +4,46 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true + }, + "@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "requires": { + "@babel/types": "^7.28.0" + } + }, + "@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + } + }, + "@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, "@meteorjs/meteor-hexo-config": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/@meteorjs/meteor-hexo-config/-/meteor-hexo-config-1.0.14.tgz", @@ -11,9 +51,31 @@ "dev": true }, "@meteorjs/meteor-theme-hexo": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@meteorjs/meteor-theme-hexo/-/meteor-theme-hexo-2.0.8.tgz", - "integrity": "sha512-LQIFN05wBMjX7SXgW5CFVTfolDWMuknoypwQ0czl/44LYRBR4/LYZUgX6c+1vLjloJb+5+2HTvMGlVN9Wo1MKA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@meteorjs/meteor-theme-hexo/-/meteor-theme-hexo-2.0.9.tgz", + "integrity": "sha512-8ncpsN8MAe1F7cJBtcPgH3JE36WV03oo5mPkA1yMdRmv2kq8AQpKnd4ok0U1cr5NIIBMupLtsHDLm8PhTQcUdw==", + "dev": true + }, + "@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "requires": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true }, "JSONStream": { @@ -38,37 +100,10 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "dependencies": { - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, - "requires": { - "mime-db": "1.40.0" - } - } - } - }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "ajv": { @@ -164,9 +199,9 @@ "dev": true }, "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "optional": true, "requires": { @@ -193,9 +228,9 @@ "dev": true }, "async-each": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz", - "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true }, "asynckit": { @@ -219,9 +254,9 @@ "optional": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "dev": true, "optional": true }, @@ -274,9 +309,9 @@ }, "dependencies": { "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true }, "regenerator-runtime": { @@ -298,9 +333,9 @@ }, "dependencies": { "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true } } @@ -354,9 +389,9 @@ "dev": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base": { @@ -383,33 +418,14 @@ "is-descriptor": "^1.0.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "isobject": { @@ -417,12 +433,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -462,9 +472,9 @@ } }, "bluebird": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", - "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "boolbase": { @@ -484,9 +494,9 @@ } }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -511,9 +521,9 @@ "dev": true }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true }, "cache-base": { @@ -541,6 +551,41 @@ } } }, + "call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "optional": true, + "requires": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "optional": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "optional": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + } + }, "camel-case": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", @@ -552,9 +597,9 @@ } }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", "dev": true }, "canonical-json": { @@ -571,12 +616,12 @@ "optional": true }, "catharsis": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", - "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, "requires": { - "lodash": "^4.17.14" + "lodash": "^4.17.15" } }, "center-align": { @@ -704,14 +749,22 @@ } }, "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "dev": true + } } }, "co": { @@ -721,12 +774,6 @@ "dev": true, "optional": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -753,9 +800,9 @@ "dev": true }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "optional": true, "requires": { @@ -763,47 +810,53 @@ } }, "command-exists": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", - "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "dev": true }, "compressible": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", - "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "requires": { - "mime-db": ">= 1.40.0 < 2" - }, - "dependencies": { - "mime-db": { - "version": "1.41.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.41.0.tgz", - "integrity": "sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw==", - "dev": true - } + "mime-db": ">= 1.43.0 < 2" } }, "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "concat-map": { @@ -843,9 +896,9 @@ "dev": true }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "cross-spawn": { @@ -932,11 +985,23 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "optional": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -947,33 +1012,14 @@ "isobject": "^3.0.1" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "isobject": { @@ -981,12 +1027,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -998,15 +1038,15 @@ "optional": true }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, "dom-serializer": { @@ -1044,6 +1084,18 @@ "domelementtype": "1" } }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "optional": true, + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1062,9 +1114,9 @@ "dev": true }, "ejs": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", - "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", "dev": true }, "emoji-regex": { @@ -1086,15 +1138,39 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "optional": true, "requires": { "prr": "~1.0.1" } }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "optional": true + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "optional": true + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "optional": true, + "requires": { + "es-errors": "^1.3.0" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1114,9 +1190,9 @@ "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "etag": { @@ -1297,12 +1373,48 @@ "nan": "^2.12.1" } }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "optional": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "optional": true, + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -1367,10 +1479,17 @@ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "optional": true + }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "handlebars": { @@ -1386,23 +1505,11 @@ "wordwrap": "^1.0.0" }, "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true } } }, @@ -1439,6 +1546,23 @@ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "optional": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "optional": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -1499,6 +1623,15 @@ } } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", @@ -1548,9 +1681,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "ansi-styles": { @@ -1636,9 +1769,9 @@ } }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -1688,62 +1821,15 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -1858,33 +1944,14 @@ "graceful-fs": "^4.1.11" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "is-extglob": { @@ -1894,9 +1961,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -1929,9 +1996,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "micromatch": { @@ -2120,9 +2187,9 @@ } }, "chokidar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", - "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -2172,62 +2239,15 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -2323,33 +2343,14 @@ "graceful-fs": "^4.1.11" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "is-extglob": { @@ -2359,9 +2360,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -2394,9 +2395,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "micromatch": { @@ -2458,9 +2459,9 @@ }, "dependencies": { "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -2484,12 +2485,6 @@ "striptags": "^3.1.1" } }, - "marked": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", - "dev": true - }, "strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -2500,9 +2495,9 @@ } }, "striptags": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.1.1.tgz", - "integrity": "sha1-yMPn/db7S7OjKjt1LltePjgJPr0=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", + "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==", "dev": true } } @@ -2532,12 +2527,6 @@ "color-convert": "^1.9.0" } }, - "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", - "dev": true - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2550,9 +2539,9 @@ } }, "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, "supports-color": { @@ -2603,9 +2592,9 @@ "optional": true }, "html-entities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", "dev": true }, "htmlparser2": { @@ -2623,9 +2612,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -2636,22 +2625,22 @@ } }, "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } @@ -2687,9 +2676,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "invariant": { @@ -2701,19 +2690,13 @@ "loose-envify": "^1.0.0" } }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, "requires": { - "kind-of": "^3.0.2" + "hasown": "^2.0.0" } }, "is-binary-path": { @@ -2731,32 +2714,32 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "requires": { - "kind-of": "^3.0.2" + "hasown": "^2.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" } }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "is-dotfile": { @@ -2787,13 +2770,10 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true }, "is-glob": { "version": "2.0.1", @@ -2896,9 +2876,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -2906,12 +2886,12 @@ } }, "js2xmlparser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", - "integrity": "sha512-CSOkdn0/GhRFwxnipmhXfqJ+FG6+wkWBi46kKSsPx6+j65176ZiQcrCYpg6K8x3iLbO4k3zScBnZ7I/L80dAtw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, "requires": { - "xmlcreate": "^1.0.1" + "xmlcreate": "^2.0.4" } }, "jsbn": { @@ -2922,54 +2902,82 @@ "optional": true }, "jsdoc": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", - "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", "dev": true, "requires": { - "babylon": "7.0.0-beta.19", - "bluebird": "~3.5.0", - "catharsis": "~0.8.9", - "escape-string-regexp": "~1.0.5", - "js2xmlparser": "~3.0.0", - "klaw": "~2.0.0", - "marked": "~0.3.6", - "mkdirp": "~0.5.1", - "requizzle": "~0.2.1", - "strip-json-comments": "~2.0.1", - "taffydb": "2.6.2", - "underscore": "~1.8.3" + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" }, "dependencies": { - "babylon": { - "version": "7.0.0-beta.19", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", - "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha512-5WsVTFcH1ut/kkhAaHf4PVgI8c7++GiVcpCGxPouI6ZVjsqPnSDf8h/8HtVqc0t4fzRXwnMK70EcZeAs3PIddg==", + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", "dev": true } } }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true, "optional": true }, "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", "dev": true, "optional": true, "requires": { - "jsonify": "~0.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "optional": true + } } }, "json-stringify-safe": { @@ -2980,9 +2988,9 @@ "optional": true }, "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", "dev": true, "optional": true }, @@ -2993,22 +3001,22 @@ "dev": true }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "optional": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "optional": true } @@ -3024,9 +3032,9 @@ } }, "klaw": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", - "integrity": "sha512-Hx5PvgJKTWpMkNJCYrBUNBLlxYIkxN4FVU/BnZP4CFh5BpiHOgujAPx7iFVz/phD0bP8rsqD48gtqcvNlUt0lQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, "requires": { "graceful-fs": "^4.1.9" @@ -3038,15 +3046,6 @@ "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", "dev": true }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, "less": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", @@ -3063,6 +3062,15 @@ "source-map": "^0.5.3" } }, + "linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "requires": { + "uc.micro": "^2.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -3122,9 +3130,9 @@ "dev": true }, "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.pick": { @@ -3206,18 +3214,65 @@ "nopt": "~2.1.1" } }, - "marked": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + } + } + }, + "markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "dev": true }, + "marked": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", + "dev": true + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "optional": true + }, "math-random": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", "dev": true }, + "mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -3246,41 +3301,40 @@ "dev": true }, "mime-db": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", - "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", - "dev": true, - "optional": true + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true }, "mime-types": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", - "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "optional": true, "requires": { - "mime-db": "~1.38.0" + "mime-db": "1.52.0" } }, "min-indent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", - "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "mixin-deep": { @@ -3305,48 +3359,41 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "optional": true, "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "minimist": "^1.2.6" } }, "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "dev": true }, "moment-timezone": { - "version": "0.5.25", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz", - "integrity": "sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==", + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", "dev": true, "requires": { - "moment": ">= 2.9.0" + "moment": "^2.29.4" } }, "morgan": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", - "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "dev": true, "requires": { - "basic-auth": "~2.0.0", + "basic-auth": "~2.0.1", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "on-headers": "~1.1.0" } }, "ms": { @@ -3368,9 +3415,9 @@ } }, "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", "dev": true, "optional": true }, @@ -3406,9 +3453,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } @@ -3421,9 +3468,9 @@ "optional": true }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true }, "neo-async": { @@ -3480,415 +3527,15 @@ "boolbase": "~1.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "nunjucks": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.0.tgz", - "integrity": "sha512-YS/qEQ6N7qCnUdm6EoYRBfJUdWNT0PpKbbRnogV2XyXbBm2STIP1O6yrdZHgwMVK7fIYUx7i8+yatEixnXSB1w==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "dev": true, "requires": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", - "chokidar": "^2.0.0", - "yargs": "^3.32.0" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "optional": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "optional": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "optional": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "optional": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "optional": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true, - "optional": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true - } + "commander": "^5.1.0" } }, "oauth-sign": { @@ -3926,6 +3573,13 @@ } } }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "optional": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -3980,9 +3634,9 @@ } }, "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true }, "once": { @@ -4019,6 +3673,12 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true } } }, @@ -4028,15 +3688,6 @@ "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "^1.0.0" - } - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -4141,9 +3792,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "promise": { @@ -4176,10 +3827,16 @@ "dev": true, "optional": true }, + "punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true + }, "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.1.tgz", + "integrity": "sha512-LQy1Q1fcva/UsnP/6Iaa4lVeM49WiOitu2T4hZCyA/elLKu37L99qcBJk4VCCk+rdLvnMzfKyiN3SZTqdAZGSQ==", "dev": true, "optional": true }, @@ -4201,9 +3858,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } @@ -4215,9 +3872,9 @@ "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -4314,62 +3971,15 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -4432,33 +4042,14 @@ } } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "is-number": { @@ -4488,9 +4079,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "micromatch": { @@ -4548,9 +4139,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -4612,12 +4203,14 @@ } }, "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-url": { @@ -4681,50 +4274,73 @@ "optional": true }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.19.0" + }, + "dependencies": { + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + } } }, "set-blocking": { @@ -4733,10 +4349,25 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "optional": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -4748,7 +4379,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -4757,9 +4388,9 @@ } }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, "shebang-command": { @@ -4787,20 +4418,11 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -4812,23 +4434,6 @@ "wrap-ansi": "^5.1.0" } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4838,23 +4443,6 @@ "ansi-regex": "^4.1.0" } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, "yargs": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", @@ -4932,33 +4520,14 @@ "is-descriptor": "^1.0.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" } }, "isobject": { @@ -4966,12 +4535,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -5001,12 +4564,12 @@ "dev": true }, "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "dev": true, "requires": { - "atob": "^2.1.1", + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -5014,9 +4577,9 @@ } }, "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "split-string": { @@ -5035,9 +4598,9 @@ "dev": true }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "optional": true, "requires": { @@ -5055,7 +4618,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "optional": true } @@ -5089,14 +4652,31 @@ "dev": true }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "string_decoder": { @@ -5131,9 +4711,9 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "striptags": { @@ -5148,6 +4728,12 @@ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, + "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==", + "dev": true + }, "swig-extras": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/swig-extras/-/swig-extras-0.0.1.tgz", @@ -5167,23 +4753,6 @@ "uglify-js": "2.6.0" }, "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, "uglify-js": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.0.tgz", @@ -5195,39 +4764,9 @@ "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } } } }, - "taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", - "dev": true - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5304,9 +4843,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, "tough-cookie": { @@ -5336,10 +4875,16 @@ "dev": true, "optional": true }, + "uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "uglify-js": { - "version": "3.13.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz", - "integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "optional": true }, @@ -5356,38 +4901,15 @@ "dev": true }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unpipe": { @@ -5443,9 +4965,9 @@ } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "upper-case": { @@ -5461,9 +4983,9 @@ "dev": true }, "url-join": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz", - "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, "use": { @@ -5485,9 +5007,9 @@ "dev": true }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true, "optional": true }, @@ -5515,6 +5037,13 @@ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "optional": true } } }, @@ -5542,31 +5071,58 @@ } }, "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, "window-size": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", - "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", "dev": true }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "wrappy": { @@ -5577,15 +5133,15 @@ "optional": true }, "xmlcreate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", - "integrity": "sha512-Mbe56Dvj00onbnSo9J0qj/XlY5bfN9KidsOnpd5tRCsR3ekB3hyyNU9fGrTdqNT5ZNvv4BsA2TcQlignsZyVcw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, "y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yallist": { @@ -5595,24 +5151,21 @@ "dev": true }, "yargs": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", - "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", "dev": true, "requires": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } }, "yargs-parser": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/docs/package.json b/docs/package.json index 0423e12344..f8aea85ac7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -6,6 +6,8 @@ "version": "3.9.0" }, "devDependencies": { + "@meteorjs/meteor-hexo-config": "1.0.14", + "@meteorjs/meteor-theme-hexo": "^2.0.9", "canonical-json": "0.0.4", "chexo": "1.0.7", "handlebars": "4.7.7", @@ -16,19 +18,21 @@ "hexo-renderer-marked": "2.0.0", "hexo-server": "1.0.0", "hexo-versioned-netlify-redirects": "1.1.0", - "jsdoc": "3.5.5", - "@meteorjs/meteor-hexo-config": "1.0.14", - "@meteorjs/meteor-theme-hexo": "2.0.8", + "jsdoc": "^4.0.2", "showdown": "1.9.1", "underscore": "1.13.1" }, "scripts": { + "list-core-packages": "node ./generators/packages-listing/script.js", "generate-history": "node ./generators/changelog/script.js", - "build": "npm run generate-history && jsdoc/jsdoc.sh && chexo @meteorjs/meteor-hexo-config -- generate", + "build": "npm run list-core-packages && jsdoc/jsdoc.sh && chexo @meteorjs/meteor-hexo-config -- generate", "clean": "hexo clean; rm data/data.js data/names.json", "test": "npm run clean; npm run build", "predeploy": "npm run build", "deploy": "hexo-s3-deploy", "start": "npm run build && chexo @meteorjs/meteor-hexo-config -- server" + }, + "volta": { + "node": "14.21.3" } } diff --git a/docs/scripts/legacy-warning.js b/docs/scripts/legacy-warning.js new file mode 100644 index 0000000000..3c54aadb33 --- /dev/null +++ b/docs/scripts/legacy-warning.js @@ -0,0 +1,35 @@ +/* global hexo */ + +hexo.extend.filter.register('after_render:html', function (str) { + const warningMessage = ` +
+

+ ⚠️ You're browsing the documentation for an old version of Meteor.js. + Check out the v3 docs and migration guide. +

+
+ `; + + const css = ` + + `; + + const injectedContent = css + warningMessage; + + return str.replace(/
/, `
${injectedContent}`); +}); \ No newline at end of file diff --git a/docs/source/api/accounts-multi.md b/docs/source/api/accounts-multi.md index f4c92218f4..a008b7d807 100644 --- a/docs/source/api/accounts-multi.md +++ b/docs/source/api/accounts-multi.md @@ -151,7 +151,8 @@ password-based users or from an external service login flow. `options` may come from an untrusted client so make sure to validate any values you read from it. The `user` argument is created on the server and contains a proposed user object with all the automatically generated fields -required for the user to log in, including the `_id`. +required for the user to log in, including a temporary `_id` (the final _id is +generated upon document insertion and not available in this function). The function should return the user document (either the one passed in or a newly-created object) with whatever modifications are desired. The returned @@ -297,7 +298,7 @@ The function will be called with a single argument, the info object: {% enddtdd %} {% dtdd name:"options" type:"Exception" %} - An optional arugment passed down from the oauth service that may contain + An optional argument passed down from the oauth service that may contain additional user profile information. As the data in `options` comes from an external source, make sure you validate any values you read from it. {% enddtdd %} diff --git a/docs/source/api/accounts.md b/docs/source/api/accounts.md index cf0cb7205a..f9429426e7 100644 --- a/docs/source/api/accounts.md +++ b/docs/source/api/accounts.md @@ -19,6 +19,24 @@ login provider packages: `accounts-password`, `accounts-facebook`, Read more about customizing user accounts in the [Accounts](http://guide.meteor.com/accounts.html) article in the Meteor Guide. +

Accounts with Session Storage

+ +By default, Meteor uses Local Storage to store, among other things, login tokens in your browser session. But, for some applications, it makes sense to use Session Storage instead. You can achieve this by adding this to your settings: + +```json +{ + // ... all other settings, + "public": { + // ... all your public settings + "packages": { + "accounts": { + "clientStorage": "session" + } + } + } +} +``` + {% apibox "Meteor.user" %} Retrieves the user record for the current user from @@ -338,3 +356,41 @@ Accounts.ui.config({ Since Meteor 2.7 you can configure these in your Meteor settings under `Meteor.settings.public.packages.accounts-ui-unstyled`. + +

Initialize with custom settings

+ +This feature allows users to specify custom configuration parameters for both client-side and server-side initialization. + +* Client + +{% apibox "AccountsClient" %} + +On the client-side, AccountsClient can be initialized with custom parameters provided through Meteor settings configuration. Below is an example of how to use this functionality: + +```json +{ + "public": { + "packages": { + "accounts": { + ...configParams + } + } + } +} +``` + +* Server + +{% apibox "AccountsServer" %} + +On the server-side, AccountsServer can also be initialized with custom parameters. Server-specific configuration may differ from the client and can also be specified through Meteor settings. Below is an example of how to do it: + +```json +{ + "packages": { + "accounts": { + ...configParams + } + } +} +``` diff --git a/docs/source/api/assets.md b/docs/source/api/assets.md index e748b5b49d..af4cd86124 100644 --- a/docs/source/api/assets.md +++ b/docs/source/api/assets.md @@ -10,8 +10,8 @@ assets, which are located in the `private` subdirectory of an application's tree. Assets are not processed as source files and are copied directly into your application's bundle. -{% apibox "Assets.getText" %} -{% apibox "Assets.getBinary" %} +{% apibox "Assets.getTextAsync" %} +{% apibox "Assets.getBinaryAsync" %} {% apibox "Assets.absoluteFilePath" %} Static server assets are included by placing them in the application's `private` @@ -20,7 +20,7 @@ directory called `nested` with a file called `data.txt` inside it, then server code can read `data.txt` by running: ```js -const data = Assets.getText('nested/data.txt'); +const data = await Assets.getTextAsync('nested/data.txt'); ``` Note: Packages can only access their own assets. If you need to read the assets of a different package, or of the enclosing app, you need to get a reference to that package's `Assets` object. diff --git a/docs/source/api/check.md b/docs/source/api/check.md index 7ecdcae7d8..107c3c865d 100644 --- a/docs/source/api/check.md +++ b/docs/source/api/check.md @@ -1,6 +1,6 @@ --- title: Check -desription: Documentation on how to use check, Meteor's type checking library. +description: Documentation on how to use check, Meteor's type checking library. --- The `check` package includes pattern checking functions useful for checking the types and structure @@ -46,6 +46,11 @@ this error gets sent over the wire to the client, it will appear only as `Meteor.Error(400, 'Match Failed')`. The failure details will be written to the server logs but not revealed to the client. +By default, `check` will throw immediately at the first error encountered. Pass in `{ throwAllErrors: true }` to throw an array of all errors. For example: +```js +check(message, {/* ... */}, {throwAllErrors: true}) +``` + {% apibox "Match.test" %} `Match.test` can be used to identify if a variable has a certain structure. diff --git a/docs/source/api/collections.md b/docs/source/api/collections.md index dfd14b8d18..355686e820 100644 --- a/docs/source/api/collections.md +++ b/docs/source/api/collections.md @@ -201,10 +201,10 @@ changes the documents in a cursor will trigger a recomputation. To disable this behavior, pass `{reactive: false}` as an option to `find`. -Note that when `fields` are specified, only changes to the included +Note that when `projection` are specified, only changes to the included fields will trigger callbacks in `observe`, `observeChanges` and invalidations in reactive computations using this cursor. Careful use -of `fields` allows for more fine-grained reactivity for computations +of `projection` allows for more fine-grained reactivity for computations that don't depend on an entire document. On the client, there will be a period of time between when the page loads and @@ -216,6 +216,8 @@ collections will be empty. Equivalent to [`find`](#find)`(selector, options).`[`fetch`](#fetch)`()[0]` with `options.limit = 1`. +> **Note**: The `fields` option is deprecated in favor of `projection`, which aligns with MongoDB's official terminology and driver. Using `projection` ensures consistency and clarity in specifying which fields to include or exclude in query results. + {% apibox "Mongo.Collection#findOneAsync" %} Async version of [`findOne`](#findOne) that return a `Promise`. @@ -837,6 +839,7 @@ const handle = cursor.observeChanges({ setTimeout(() => handle.stop(), 5000); ``` +{% apibox "Mongo.getCollection" %} {% apibox "Mongo.ObjectID" %} `Mongo.ObjectID` follows the same API as the [Node MongoDB driver @@ -949,30 +952,30 @@ document objects, and returns -1 if the first document comes first in order, 1 if the second document comes first, or 0 if neither document comes before the other. This is a Minimongo extension to MongoDB. -

Field Specifiers

+

Projection Specifiers

Queries can specify a particular set of fields to include or exclude from the -result object. +result object using the `projection` option. -To exclude specific fields from the result objects, the field specifier is a +To exclude specific fields from the result objects, the projection specifier is a dictionary whose keys are field names and whose values are `0`. All unspecified fields are included. ```js -Users.find({}, { fields: { password: 0, hash: 0 } }); +Users.find({}, { projection: { password: 0, hash: 0 } }); ``` To include only specific fields in the result documents, use `1` as the value. The `_id` field is still included in the result. ```js -Users.find({}, { fields: { firstname: 1, lastname: 1 } }); +Users.find({}, { projection: { firstname: 1, lastname: 1 } }); ``` With one exception, it is not possible to mix inclusion and exclusion styles: the keys must either be all 1 or all 0. The exception is that you may specify `_id: 0` in an inclusion specifier, which will leave `_id` out of the result -object as well. However, such field specifiers can not be used with +object as well. However, such projection specifiers can not be used with [`observeChanges`](#observe_changes), [`observe`](#observe), cursors returned from a [publish function](#meteor_publish), or cursors used in `{% raw %}{{#each}}{% endraw %}` in a template. They may be used with [`fetch`](#fetch), @@ -993,10 +996,12 @@ Users.insert({ name: 'Yagami Light', }); -Users.findOne({}, { fields: { 'alterEgos.name': 1, _id: 0 } }); +Users.findOne({}, { projection: { 'alterEgos.name': 1, _id: 0 } }); // Returns { alterEgos: [{ name: 'Kira' }, { name: 'L' }] } ``` +> Note: The `fields` option is deprecated in favor of `projection`, which is the standard term used by MongoDB. Using `projection` ensures compatibility with MongoDB's documentation and drivers. + See the MongoDB docs for details of the nested field rules and array behavior. @@ -1082,6 +1087,38 @@ option: You can pass any MongoDB valid option, these are just examples using certificates configurations. +

Mongo Oplog Options

+ +> Oplog options were introduced in Meteor 2.15.1 + +If you set the [`MONGO_OPLOG_URL`](https://docs.meteor.com/environment-variables.html#MONGO-OPLOG-URL) env var, Meteor will use MongoDB's Oplog to show efficient, real time updates to your users via your subscriptions. + +Due to how Meteor's Oplog implementation is built behind the scenes, if you have certain collections where you expect **big amounts of write operations**, this might lead to **big CPU spikes on your meteor app server, even if you have no publications/subscriptions on any data/documents of these collections**. For more information on this, please have a look into [this blog post from 2016](https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908), [this github discussion from 2022](https://github.com/meteor/meteor/discussions/11842) or [this meteor forums post from 2023](https://forums.meteor.com/t/cpu-spikes-due-to-oplog-updates-without-subscriptions/60028). + +To solve this, **2 Oplog settings** have been introduced **to tweak, which collections are *watched* or *ignored* in the oplog**. + +**Exclusion**: To *exclude* for example all updates/inserts of documents in the 2 collections called `products` and `prices`, you would need to set the following setting in your Meteor settings file: + +```json + "packages": { + "mongo": { + "oplogExcludeCollections": ["products", "prices"] + } + } +``` + +**Inclusion**: vice versa, if you only want to watch/*include* the oplog for changes on documents in the 2 collections `chats` and `messages`, you would use: + +```json + "packages": { + "mongo": { + "oplogIncludeCollections": ["chats", "messages"] + } + } +``` + +For obvious reasons, using both `oplogExcludeCollections` and `oplogIncludeCollections` at the same time is not possible and will result in an error. +

Mongo.setConnectionOptions

You can also call `Mongo.setConnectionOptions` to set the connection options but diff --git a/docs/source/api/core.md b/docs/source/api/core.md index 8909e93256..7edd43c60f 100644 --- a/docs/source/api/core.md +++ b/docs/source/api/core.md @@ -3,7 +3,7 @@ title: Core description: Documentation of core Meteor functions. --- -If you prefer to watch the video, click below. +If you prefer to watch the video, click below. {% youtube 6RRVU0-Vvm8 %} @@ -64,3 +64,5 @@ if (Meteor.isServer) { {% apibox "Meteor.isAppTest" %} {% apibox "Meteor.isPackageTest" %} + +{% apibox "Meteor.isFibersDisabled" %} diff --git a/docs/source/api/methods.md b/docs/source/api/methods.md index 03854c603d..a476e9dbc6 100644 --- a/docs/source/api/methods.md +++ b/docs/source/api/methods.md @@ -80,6 +80,12 @@ with this ID has already been made. Alternatively, you can use Read more about methods and how to use them in the [Methods](http://guide.meteor.com/methods.html) article in the Meteor Guide. +{% apibox "Meteor.isAsyncCall" %} + +This method can be used to determine if the current method invocation is +asynchronous. It returns true if the method is running on the server and came from +an async call(`Meteor.callAsync`) + {% apibox "DDPCommon.MethodInvocation#userId" %} The user id is an arbitrary string — typically the id of the user record diff --git a/docs/source/api/mobile-config.md b/docs/source/api/mobile-config.md index c32b33791a..c5202b57d7 100644 --- a/docs/source/api/mobile-config.md +++ b/docs/source/api/mobile-config.md @@ -54,16 +54,7 @@ App.launchScreens({ '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) + 'android_universal': 'splash/android_universal.png', // (320x480) }); // Set PhoneGap/Cordova preferences. diff --git a/docs/source/api/packagejs.md b/docs/source/api/packagejs.md index 7cc521073f..9feb02877f 100644 --- a/docs/source/api/packagejs.md +++ b/docs/source/api/packagejs.md @@ -80,7 +80,7 @@ package) so that Meteor will pick up the local dependency. > In a lifecycle of a package there might come time to end the development for various reasons, or it gets superseded. In either case Meteor allows you to easily notify the users of the package by setting the deprecated flag to true: `deprecated: true` in the package description. In addition, you -replace it with a string that tells the users where to find replacement or what to do. +replace it with a string that tells the users where to find replacement or what to do. Provide basic package information with `Package.describe(options)`. To publish a package, you must define `summary` and `version`. @@ -97,7 +97,7 @@ package is exported to. {% apibox "PackageAPI#versionsFrom" %} > Choose Meteor versions carefully. First determine the minimum version of Meteor you need for the API you use in your package. - This should be based on specific needs of your package like needed the *Async calls, which would require minimum version to be + This should be based on specific needs of your package like needed the *Async calls, which would require minimum version to be at least 2.8. Another example are where packages had a major version bump, for example this has happened with the accounts packages in Meteor 2.3. If you want to be backward and forward compatible it is good to include Meteor version before 2.3 and then 2.3.6 in the array. A general recommendation for most compatibility for accounts packages (unless you need API that was affected in Meteor 2.3) is to have the following @@ -315,7 +315,7 @@ methods are available: - `addAsset` - Add a file to serve as-is to the browser or to include on the browser, depending on the target. On the web, it will be served at the exact path requested. For server targets, it can be retrieved using - `Assets.getText` or `Assets.getBinary`. + `Assets.getTextAsync` or `Assets.getBinaryAsync`. - `addHtml` - Works in web targets only. Add markup to the `head` or `body` section of the document. - `hmrAvailable` - Returns true if the file can be updated with HMR. Among other things, diff --git a/docs/source/api/passwords.md b/docs/source/api/passwords.md index a1967e174e..908617aa3e 100644 --- a/docs/source/api/passwords.md +++ b/docs/source/api/passwords.md @@ -27,13 +27,17 @@ include a turn-key user interface for password-based sign-in. {% apibox "Accounts.createUser" %} +Or a promise based version of `Accounts.createUser`: + +{% apibox "Accounts.createUserAsync" %} + On the client, this function logs in as the newly created user on successful completion. On the server, it returns the newly created user id. On the client, you must pass `password` and at least one of `username` or `email` — enough information for the user to be able to log in again later. If there are existing users with a username or email only differing in case, `createUser` will fail. The callback's `error.reason` will be `'Username already exists.'` or `'Email already exists.'` In the latter case, the user can then either [login](accounts.html#Meteor-loginWithPassword) or [reset their password](#Accounts-resetPassword). -On the server, you do not need to specify `password`, but the user will not be able to log in until it has a password (eg, set with [`Accounts.setPassword`](#accounts_setpassword)). To create an account without a password on the server and still let the user pick their own password, call `createUser` with the `email` option and then call [`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail). This will send the user an email with a link to set their initial password. +On the server, you do not need to specify `password`, but the user will not be able to log in until it has a password (eg, set with [`Accounts.setPasswordAsync`](#accounts_setpasswordasync)). To create an account without a password on the server and still let the user pick their own password, call `createUser` with the `email` option and then call [`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail). This will send the user an email with a link to set their initial password. By default the `profile` option is added directly to the new user document. To override this behavior, use [`Accounts.onCreateUser`](#accounts_oncreateuser). @@ -49,18 +53,20 @@ insensitive duplicates before updates. {% apibox "Accounts.setUsername" %} -{% apibox "Accounts.addEmail" %} +{% apibox "Accounts.addEmailAsync" %} By default, an email address is added with `{ verified: false }`. Use [`Accounts.sendVerificationEmail`](#Accounts-sendVerificationEmail) to send an email with a link the user can use to verify their email address. +{% apibox "Accounts.replaceEmailAsync" %} + {% apibox "Accounts.removeEmail" %} {% apibox "Accounts.verifyEmail" %} If the user trying to verify the email has 2FA enabled, this error will be thrown: -* "Email verified, but user not logged in because 2FA is enabled [2fa-enabled]": No longer signing in the user automatically if the user has 2FA enabled. +* "Email verified, but user not logged in because 2FA is enabled [2fa-enabled]": No longer signing in the user automatically if the user has 2FA enabled. This function accepts tokens passed into the callback registered with @@ -96,7 +102,7 @@ This function accepts tokens passed into the callbacks registered with If the user trying to reset the password has 2FA enabled, this error will be thrown: * "Changed password, but user not logged in because 2FA is enabled [2fa-enabled]": No longer signing in the user automatically if the user has 2FA enabled. -{% apibox "Accounts.setPassword" %} +{% apibox "Accounts.setPasswordAsync" %} {% apibox "Accounts.sendResetPasswordEmail" %} diff --git a/docs/source/api/pubsub.md b/docs/source/api/pubsub.md index 76f1343952..6420455723 100644 --- a/docs/source/api/pubsub.md +++ b/docs/source/api/pubsub.md @@ -268,7 +268,7 @@ stay subscribed to your private messages. > The following features are available from Meteor 2.4 or `ddp-server@2.5.0` Once you start scaling your application you might want to have more control on how the data from publications is being handled on the client. -There are three publications strategies: +There are four publications strategies: #### SERVER_MERGE `SERVER_MERGE` is the default strategy. When using this strategy, the server maintains a copy of all data a connection is subscribed to. @@ -291,12 +291,17 @@ Specifically: * When we receive a change message for a document that is not in the client's collection, it will be added. * When we receive a removed message for a document that is not in the client's collection, nothing will happen. +#### NO_MERGE_MULTI +`NO_MERGE_MULTI` is similar to `NO_MERGE`, but it does track whether a document is used by multiple publications. +This has some memory overhead, but it still does not do diffing so it's faster and slimmer than +`SERVER_MERGE`. + You can import the publication strategies from `DDPServer`. ```js import { DDPServer } from 'meteor/ddp-server' -const { SERVER_MERGE, NO_MERGE_NO_HISTORY, NO_MERGE } = DDPServer.publicationStrategies +const { SERVER_MERGE, NO_MERGE_NO_HISTORY, NO_MERGE, NO_MERGE_MULTI } = DDPServer.publicationStrategies ``` You can use the following methods to set or get the publication strategy for publications: diff --git a/docs/source/api/top-level-await.md b/docs/source/api/top-level-await.md new file mode 100644 index 0000000000..accc3f84d7 --- /dev/null +++ b/docs/source/api/top-level-await.md @@ -0,0 +1,122 @@ +--- +title: Top Level Await +description: Documentation of how to use top level await in Meteor +--- + +[Top level await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await) (TLA) allows you to use `await` in the top level of a module or file instead of only in async functions. One way to view it as every file runs inside an `async` function. + +Here is an example of using top level await on the server. When this file is loaded, the `await` will cause the module to wait for the count before the code in the rest of the module is run. + +```js +const Links = new Mongo.Collection('links'); + +// Async code using top level await. +// The module waits for this to finish before continuing +const count = await Links.find().countAsync(); + +if (count === 0) { + await Links.insertAsync({ url: 'https://meteor.com' }); +} +``` + +In previous versions of Meteor, async code using fibers could be run in the top level of a module. Top level await allows writing similar code that works without fibers. There are a few differences that this article will cover. + +Meteor's implementation of top level await tries to closely follow the specification. There currently are some differences with how Meteor handles circular dependencies. + +## Using Top Level Await + +Top level await can be used in any app or package that uses the `ecmascript`, `typescript`, or `coffeescript` packages, or that uses any other build plugin that compiles top level await using reify. +Generally, if you can use ECMAScript modules, then you can also use top level await. + +There are some extra considerations when using top level await in packages. They are covered later in this article. + +Top level await is only enabled by default on the server. You can enable it for the client by setting the env var `METEOR_ENABLE_CLIENT_TOP_LEVEL_AWAIT` to `true`. There are a couple known issues with using TLA on the client: + +1. It breaks any files in `/client/compatibility` since it now wraps those files in a function +2. Hot module replacement has not been updated to work with TLA + +## Async Modules + +With top level await, some modules are considered async, which affects how they behave. There are two ways a module can become an async module: +1. It uses top level await +2. It imports a module that is async + +For example, this module (`setup.js`) would be async because it uses top level await: + +```js +await setupLanguages(); +``` + +This module (`main.js`) would be sync: + +```js +console.log('in main.js'); +``` + +However, if it imports `setup.js` which does use top level await, then `main.js` also becomes async. + +```js +import './setup.js'; + +console.log('in main.js'); +``` + +## Require + +When using `require` to load an async module, instead of directly returning a module's exports, it will return a promise that resolves to the module's exports. + +```js +// resolves to the exports of init.js +const promise = require('./init.js'); +``` + +If you are using `require`, this does mean you need to be careful when adding or removing top level await in a file since you also have to update where the module is required. +Since a module becomes async if it depends on an async module, this could affect more than just the individual modules using top level await. + +When possible, you can use ecmascript import syntax or dynamic imports instead so you don't have to worry about which modules are sync or async. + +## Nested Imports + +Nested imports refer to using `import ...` outside of the root of a module, for example in an if block or a function. + +```js +if (Meteor.isClient) { + import './init-client.js'; +} + +export function showNotification(message) { + import show from './notifications.js'; + + show(message); +} +``` + + This is a feature unique to Meteor, so the top level await specification wasn't written to work with nested imports. Using nested imports to import a sync module continues to work, but it will throw an error if used to import an async module. You can use `require` or dynamic imports for async modules in these situations. + +## Using in Packages + +Top level await is only supported starting in Meteor 3. Published build plugins are able to use top level await in older Meteor versions since the runtime is bundled when they are published, though in development they require Meteor 3. + +If you want to ensure your package only runs in versions of Meteor that support top level await, you can have your package use `isobuild:top-level-await`: + +```js +Package.onUse(function (api) { + // Do not allow this package to be used in pre-Meteor 3 apps. + api.use("isobuild:top-level-await@3.0.0"); +}); +``` + +When importing a package that does not have a lazy main module, it will work the same whether a package uses top level await or not. This is true even when using `require`. This allows packages to add or remove top level await without it being a breaking change. + +There are a couple cases where adding or removing top level await from a module in a package could be considered a breaking change: + +1. If specific modules are require'd from a package. For example: `require('meteor/zodern:aurorae/svelte.js')`. When importing a specific module from a package, `require` changes its behavior based on if the module is async or not. +2. If a package that has lazy main modules is require'd. Unlike normal packages, `require` will return a promise if the lazy main module is an async module. Changing if the lazy main module is async or not should be considered a breaking change for the package. + +## Module and Package Execution Order + +Normally, modules are run one at a time. This was even true when using async code with fibers in the root of a module. However, top level await is different - it allows siblings (modules that do not depend on each other) to sometimes run in parallel. This can allow the app to load faster, which is especially important on the client. However, this could cause code to run in an unexpected order if you are used to how Meteor worked with fibers. + +This is also applies to packages. Packages that do not directly or indirectly depend on each other are able to load in parallel if they use top level await. + +Modules that are eagerly evaluated (added in packages with `api.addFiles`, or outside of `imports` in apps that do not have a main module) and not directly imported continue to run one at a time, even if they use top level await, since it is common for these modules to implicitly depend on the previous modules. diff --git a/docs/source/api/tracker.md b/docs/source/api/tracker.md index ee1b7daae3..8701a3d466 100644 --- a/docs/source/api/tracker.md +++ b/docs/source/api/tracker.md @@ -80,7 +80,7 @@ If the initial run of an autorun throws an exception, the computation is automatically stopped and won't be rerun. ### Tracker.autorun and async callbacks -`Tracker.autorun` can accept an `async` callback function. +`Tracker.autorun` can accept an `async` callback function. To preserve reactivity for the reactive variables inside the async callback function, you must use a `Tracker.withComputation`Β call as described below: {% apibox "Tracker.withComputation" %} @@ -90,13 +90,13 @@ Tracker.autorun(async function example1(computation) { // Code before the first await will stay reactive. reactiveVar1.get(); // This will trigger a rerun. - let links = await LinksCollection.findAsync({}).fetch(); // First async call will stay reactive. + let links = await LinksCollection.find({}).fetchAsync(); // First async call will stay reactive. // Code after the first await looses Tracker.currentComputation: no reactivity. reactiveVar2.get(); // This won't trigger a rerun. - + // You can bring back reactivity with the Tracker.withCompuation wrapper: - let users = await Tracker.withComputation(computation, () => Meteor.users.findAsync({}).fetch()); + let users = await Tracker.withComputation(computation, () => Meteor.users.find({}).fetchAsync()); // Code below will again not be reactive, so you will need another Tracker.withComputation. const value = Tracker.withComputation(computation, () => reactiveVar3.get()); // This will trigger a rerun. @@ -112,7 +112,7 @@ The `react-meteor-data` package uses `Tracker.withComputation` to make the `useT More can be seen [here](https://github.com/meteor/react-packages/tree/master/packages/react-meteor-data#maintaining-the-reactive-context) ### Using async callbacks in versions of Meteor prior to 2.10 -`Tracker.autorun` can accept an `async` callback function. +`Tracker.autorun` can accept an `async` callback function. However, the async call back function will only be dependent on reactive functions called prior to any called functions that return a promise. Example 1 - autorun `example1()` **is not** dependent on reactive changes to the `Meteor.users` collection. Because it is dependent on nothing reactive it will run only once: @@ -302,6 +302,41 @@ recomputed at flush time. This property is a convenience to support the common pattern where a computation has logic specific to the first run. +{% apibox "Tracker.Computation#firstRunPromise" %} + +`Computation.firstRunPromise` will be set to the result of the call of the autorun function after the initial computation has been completed. If the autorun function is an async function, it'll then contain its promise, thus making the completion of the execution await-able. That allows us to manually synchronize autoruns like this: + +```js + +await Tracker.autorun(async () => { + await Meteor.userAsync(); + (...more async code...) +}).firstRunPromise; + +await Tracker.autorun(async () => { + await asyncSomeOrOther(); + (...more async code...) +}).firstRunPromise; + +``` + +For a better developer experience `firstRunPromise` is automatically appended to your async `autorun` calls so you don't have to write them yourself. Meaning this also works: + +```js + +await Tracker.autorun(async () => { + await Meteor.userAsync(); + (...more async code...) +}); + +await Tracker.autorun(async () => { + await asyncSomeOrOther(); + (...more async code...) +}); + +``` + +

Tracker.Dependency

A Dependency represents an atomic unit of reactive data that a diff --git a/docs/source/commandline.md b/docs/source/commandline.md index 10a36a8daf..e1494f5a7c 100644 --- a/docs/source/commandline.md +++ b/docs/source/commandline.md @@ -33,7 +33,7 @@ required. This is the default command. Simply running `meteor` is the same as `meteor run`. -To pass additional options to Node.js use the `SERVER_NODE_OPTIONS` environment variable. E.g. for Windows PowerShell: +To pass additional options to Node.js use the `SERVER_NODE_OPTIONS` environment variable. E.g. for Windows PowerShell: `$env:SERVER_NODE_OPTIONS = '--inspect' | meteor run`. Or for Linux: `SERVER_NODE_OPTIONS=--inspect-brk meteor run`. To specify a port to listen on (instead of the default 3000), use `--port [PORT]`. @@ -43,6 +43,9 @@ For example: `meteor run --port 4000` will run the development server on `http://localhost:4000` and the development MongoDB instance on `mongodb://localhost:4001`. +To open your default browser you can pass the `--open` flag. +For example: `meteor run --open` + Run `meteor help run` to see the full list of options.

meteor debug

@@ -83,21 +86,24 @@ option to other `meteor` tool commands, such as `meteor run` and `meteor test-pa

meteor create app-name

-The command `meteor create app-name` is the default command for creating a new Meteor project. It creates a subdirectory -named `app-name` and copies a template app into it. You can pass an absolute or relative path. If you pass a relative +The command `meteor create app-name` is the default command for creating a new Meteor project. It creates a subdirectory +named `app-name` and copies a template app into it. You can pass an absolute or relative path. If you pass a relative path, it will be resolved relative to the current working directory. By default, it generates a React project. See the flags below to learn how you can generate different types of apps. +Using only `meteor create` will create a promt to help you choose the type of app you want to create, +giving you the options with the flags below. +

--apollo

-The command `meteor create --apollo app-name` creates a Meteor app with [React](https://react.dev/), -[Apollo](https://www.apollographql.com/) (GraphQL), and [MongoDB](https://www.mongodb.com/). To create a complete app, -including testing and deployment, follow the [React tutorial](https://react-tutorial.meteor.com/). To learn how to use +The command `meteor create --apollo app-name` creates a Meteor app with [React](https://react.dev/), +[Apollo](https://www.apollographql.com/) (GraphQL), and [MongoDB](https://www.mongodb.com/). To create a complete app, +including testing and deployment, follow the [React tutorial](https://react-tutorial.meteor.com/). To learn how to use Apollo, refer to the [GraphQL section](https://react-tutorial.meteor.com/simple-todos-graphql/). -Npm packages included: `@apollo/client`, `@apollo/server`, `@babel/runtime`, `body-parser`, `express`, +Npm packages included: `@apollo/client`, `@apollo/server`, `@babel/runtime`, `body-parser`, `express`, `graphql` `meteor-node-stubs`, `react`, `react-dom`. Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive-var`, `standard-minifier-css`, @@ -107,7 +113,7 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--bare

-The command `meteor create --bare app-name` creates an empty Meteor app with [Blaze](https://blazejs.org) and +The command `meteor create --bare app-name` creates an empty Meteor app with [Blaze](https://blazejs.org) and [MongoDB](https://www.mongodb.com/). To create a complete app, including testing and deployment, follow the [Blaze tutorial](https://blaze-tutorial.meteor.com/). @@ -119,22 +125,22 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--blaze

-The command `meteor create --blaze app-name` creates a Meteor app with [Blaze](https://blazejs.org) and +The command `meteor create --blaze app-name` creates a Meteor app with [Blaze](https://blazejs.org) and [MongoDB](https://www.mongodb.com/). To create a complete app, including testing and deployment, follow the [Blaze tutorial](https://blaze-tutorial.meteor.com/). Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `jquery`. Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `blaze-html-templates`, `jquery`, `reactive-var`, -`tracker`, `standard-minifier-css`, `standard-minifier-js`, `es5-shim`, `ecmascript`, `typescript`, `shell-server`, +`tracker`, `standard-minifier-css`, `standard-minifier-js`, `es5-shim`, `ecmascript`, `typescript`, `shell-server`, `hot-module-replacement`, `blaze-hot`.

--chakra-ui

-The command `meteor create --chakra-ui app-name` creates a Meteor app with [React](https://react.dev/), -[Chakra-UI](https://chakra-ui.com/), and [MongoDB](https://www.mongodb.com/). To create a complete app, including -testing and deployment, follow the [React tutorial](https://react-tutorial.meteor.com/). To learn how to use Chakra-UI, +The command `meteor create --chakra-ui app-name` creates a Meteor app with [React](https://react.dev/), +[Chakra-UI](https://chakra-ui.com/), and [MongoDB](https://www.mongodb.com/). To create a complete app, including +testing and deployment, follow the [React tutorial](https://react-tutorial.meteor.com/). To learn how to use Chakra-UI, refer to the [Simple Tasks](https://github.com/fredmaiaarantes/simpletasks) example. Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `react`, `react-dom`, `@chakra-ui/icons`, `@chakra-ui/react`, `@emotion/react` @@ -147,10 +153,10 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--full

-The command `meteor create --full app-name` creates a Meteor app with [Blaze](https://blazejs.org) and +The command `meteor create --full app-name` creates a Meteor app with [Blaze](https://blazejs.org) and [MongoDB](https://www.mongodb.com/). It creates a more complete, imports-based project that closely matches the -[file structure](https://guide.meteor.com/structure.html#javascript-structure) recommended by the -[Meteor Guide](https://guide.meteor.com/). To create a complete app, including testing and deployment, follow the +[file structure](https://guide.meteor.com/structure.html#javascript-structure) recommended by the +[Meteor Guide](https://guide.meteor.com/). To create a complete app, including testing and deployment, follow the [Blaze tutorial](https://blaze-tutorial.meteor.com/). Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `jquery`, `chai`. @@ -172,7 +178,7 @@ Meteor packages included: `meteor`, `standard-minifier-css`, `standard-minifier-

--package

-The command `meteor create --package package-name` creates a new package. If used in an existing app, it will create a +The command `meteor create --package package-name` creates a new package. If used in an existing app, it will create a package in the `packages` directory. Check the [Meteor Guide](https://guide.meteor.com/writing-atmosphere-packages.html) for more information on how to get started writing packages. @@ -180,7 +186,7 @@ for more information on how to get started writing packages.

--prototype

The command `meteor create --prototype app-name` creates a project with the prototype purpose packages (`autopublish` -and `insecure`). If you use them, you can change your collections quickly and create prototype apps very quickly. +and `insecure`). If you use them, you can change your collections quickly and create prototype apps very quickly. However, these packages are not supposed to be used in production. For more information about security, you can read our [security checklist](https://guide.meteor.com/security.html#checklist). @@ -189,28 +195,28 @@ It can be used with other flags that create apps, such as `--react`, `blaze`, or

--react

-The command `meteor create --react app-name` creates a Meteor app with [React](https://react.dev/) and -[MongoDB](https://www.mongodb.com/). It functions in the same way as if you don't use any flags. To create a complete +The command `meteor create --react app-name` creates a Meteor app with [React](https://react.dev/) and +[MongoDB](https://www.mongodb.com/). It functions in the same way as if you don't use any flags. To create a complete app, including testing and deployment, follow the [React tutorial](https://react-tutorial.meteor.com/). Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `react`, `react-dom`. -Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive-var`, `standard-minifier-css`, +Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive-var`, `standard-minifier-css`, `standard-minifier-js`, `es5-shim`, `ecmascript`, `typescript`, `shell-server`, `hot-module-replacement`, `static-html`, `react-meteor-data`.

--release

-The command `meteor create app-name --release {meteor-version}` creates a Meteor app with the release specified in the -command. For instance, you can create a Meteor app with the `2.8` release using `meteor create app-name --release 2.8`. -By default, it generates a React app, but you can use it with other flags that create apps such as `--blaze`, +The command `meteor create app-name --release {meteor-version}` creates a Meteor app with the release specified in the +command. For instance, you can create a Meteor app with the `2.8` release using `meteor create app-name --release 2.8`. +By default, it generates a React app, but you can use it with other flags that create apps such as `--blaze`, `--svelte`, `--vue`, or `--typescript`.

--solid

-The command `meteor create --solid app-name` creates a Meteor app with [Solid](https://www.solidjs.com/), +The command `meteor create --solid app-name` creates a Meteor app with [Solid](https://www.solidjs.com/), [Vite](https://vitejs.dev/), and [MongoDB](https://www.mongodb.com/). You can see an example on the [meteor-solid-app](https://github.com/fredmaiaarantes/meteor-solid-app/releases/tag/milestone-2.0) repository. @@ -223,7 +229,7 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--svelte

-The command `meteor create --svelte app-name` creates a Meteor app with [Svelte](https://svelte.dev/) and +The command `meteor create --svelte app-name` creates a Meteor app with [Svelte](https://svelte.dev/) and [MongoDB](https://www.mongodb.com/). To create a complete app, including testing and deployment, follow the [Svelte tutorial](https://svelte-tutorial.meteor.com/). @@ -239,7 +245,7 @@ You can see an example on the [meteor-vite](https://github.com/JorgenVatle/meteo

--tailwind

-The command `meteor create --tailwind app-name` creates a Meteor app with [React](https://react.dev/), +The command `meteor create --tailwind app-name` creates a Meteor app with [React](https://react.dev/), [Tailwind CSS](https://tailwindcss.com), and [MongoDB](https://www.mongodb.com/). Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `react`, `react-dom`, `autoprefixer`, `postcss`, `postcss-load-config`, `tailwindcss`. @@ -251,9 +257,9 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--typescript

-The command `meteor create --typescript app-name` creates a Meteor app with [React](https://react.dev/), -[TypeScript](https://www.typescriptlang.org/), and [MongoDB](https://www.mongodb.com/). Check the -[Meteor Guide](https://guide.meteor.com/build-tool.html#typescript) for more information about TypeScript and how to +The command `meteor create --typescript app-name` creates a Meteor app with [React](https://react.dev/), +[TypeScript](https://www.typescriptlang.org/), and [MongoDB](https://www.mongodb.com/). Check the +[Meteor Guide](https://guide.meteor.com/build-tool.html#typescript) for more information about TypeScript and how to use it with other UI frameworks. Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `react`, `react-dom`, `@types/mocha`, `@types/node`, `@types/react`, `@types/react-dom`, `typescript`. @@ -265,8 +271,8 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive

--vue

-The command `meteor create --vue app-name` creates a Meteor app with [Vue 3](https://vuejs.org/), -[Tailwind CSS](https://tailwindcss.com), [Vite](https://vitejs.dev/), and [MongoDB](https://www.mongodb.com/). To +The command `meteor create --vue app-name` creates a Meteor app with [Vue 3](https://vuejs.org/), +[Tailwind CSS](https://tailwindcss.com), [Vite](https://vitejs.dev/), and [MongoDB](https://www.mongodb.com/). To create a complete app, including testing and deployment, follow the [Vue 3 tutorial](https://vue3-tutorial.meteor.com/). Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `vue`, `vue-meteor-tracker`, `vue-router`, `@types/meteor`, `@vitejs/plugin-vue`, `autoprefixer`, `postcss`, `tailwindcss`, `vite`. @@ -276,23 +282,9 @@ Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive `vite:bundler`. You can also use Vue 3 with Vite by using the [jorgenvatle:meteor-vite](https://github.com/JorgenVatle/meteor-vite) -package. You can see an example on the [meteor-vite](https://github.com/JorgenVatle/meteor-vite/tree/release/examples/vue) +package. You can see an example on the [meteor-vite](https://github.com/JorgenVatle/meteor-vite/tree/release/examples/vue) repository. - -

--vue-2

- -The command `meteor create --vue-2 app-name` creates a Meteor app with [Vue 2](https://v2.vuejs.org/) and -[MongoDB](https://www.mongodb.com/). To create a complete app, including testing and deployment, follow the -[Vue 2 tutorial](https://vue-tutorial.meteor.com/). - -Npm packages included: `@babel/runtime`, `meteor-node-stubs`, `vue`, `vue-meteor-tracker`. - -Meteor packages included: `meteor-base`, `mobile-experience`, `mongo`, `reactive-var`, `standard-minifier-css`, -`standard-minifier-js`, `es5-shim`, `ecmascript`, `typescript`, `shell-server`, `tracker`, `static-html`, `akryum:vue-component`, -`meteortesting:mocha`, `johanbrook:publication-collector`. - -

meteor generate

``meteor generate`` is a command for generating scaffolds for your current project. When ran without arguments, it will ask @@ -303,7 +295,7 @@ used as a command line only operation as well. > By default, the generator will use JavaScript but if it detects that you have a ``tsconfig.json`` file in your project, it will use TypeScript instead. -running +running ```bash meteor generate customer @@ -511,7 +503,7 @@ It will prompt the following questions. ---- +---

Using your own template

@@ -533,7 +525,7 @@ You can use your own templates for scaffolding your specific workloads. To do th Out of the box is provided a few functions such as replacing ``$$name$$``, ``$$PascalName$$`` and ``$$camelName$$`` these replacements come from this function: - + _Note that scaffoldName is the name that you have passed as argument_ ```js @@ -661,7 +653,7 @@ If you want to connect to your free MongoDB shared cluster using your on setting ``` packages: { mongo: { - options: { + options: { tlsAllowInvalidCertificates: true, }, }, @@ -685,7 +677,7 @@ Your project should be a git repository as the commit hash is going to be used t The `cache-build` option is available since Meteor 1.11. {% endpullquote %} -With the argument `--container-size` you can change your app's container size using the deploy command. The valid arguments are: `tiny`, `compact`, `standard`, `double`, `quad`, `octa`, and `dozen`. One more thing to note here is that the `--container-size` flag can only be used when the `--plan` option is already specified, otherwise using the `--container-size` option will throw an error with the message : `Error deploying application: Internal error`. To see more about the difference and prices of each one you can check [here](https://www.meteor.com/cloud#pricing-section). +With the argument `--container-size` you can change your app's container size using the deploy command. The valid arguments are: `tiny`, `compact`, `standard`, `double`, `quad`, `octa`, and `dozen`. One more thing to note here is that the `--container-size` flag can only be used when the `--plan` option is already specified, otherwise using the `--container-size` option will throw an error with the message : `Error deploying application: Internal error`. To see more about the difference and prices of each one you can check [here](https://galaxycloud.app/meteorjs/pricing). {% pullquote warning %} The `--container-size` option is available since Meteor 2.4.1. @@ -912,7 +904,7 @@ upload the build to the architecture that you were using to publish it. You can use `publish-for-arch` to upload a build to a different architecture from a different machine. -If you have already published a package but need to update it's metadata +If you have already published a package but need to update it's metadata (the content of `Package.describe`) or the README you can actually achieve this via `meteor publish --update`. diff --git a/docs/source/environment-variables.md b/docs/source/environment-variables.md index 807851ac47..4c8ebb8bf2 100644 --- a/docs/source/environment-variables.md +++ b/docs/source/environment-variables.md @@ -15,7 +15,7 @@ See also: [`PORT`](#PORT). > In development, this can be accomplished with `meteor run --port a.b.c.d:port`. ## DDP_DEFAULT_CONNECTION_URL -(_develoment, production_) +(_development, production_) There are some situations where it is valuable for the meteor client to use a different DDP server than the `ROOT_URL` server. @@ -33,6 +33,11 @@ In the event that your own deployment platform does not support WebSockets, or y Set `DISABLE_SOCKJS=1` if you want to use the native WebSocket implementation instead of SockJS on the client side, for example, if you want to use a custom WebSocket implementation (e.g. [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js/)) on the server side. +## DISABLE_SOCKJS_CORS +(_development, production_) + +Set `DISABLE_SOCKJS_CORS=1` if you want to prevent SockJS from setting CORS headers. Do not set this option if you will have DDP clients from other origins connecting to the DDP server. + ## HTTP_FORWARDED_COUNT (_production_) @@ -72,7 +77,7 @@ When running your bundled application in production mode, pass a string of JSON ## METEOR_SQLITE_JOURNAL_MODE (_development_) -The Meteor package catalog uses the `WAL` [SQLite Journal Mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) by default. The Journal mode for the package catalog can be modifed by setting `METEOR_SQLITE_JOURNAL_MODE`. +The Meteor package catalog uses the `WAL` [SQLite Journal Mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) by default. The Journal mode for the package catalog can be modified by setting `METEOR_SQLITE_JOURNAL_MODE`. When running multiple concurrent meteor servers on [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/) some meteor developers have seen issues with the package catalog. Setting the environment variable `METEOR_SQLITE_JOURNAL_MODE=TRUNCATE` can overcome the issue. diff --git a/docs/source/index.md b/docs/source/index.md index 6e196d5596..208309701d 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -2,7 +2,7 @@ title: Docs --- -> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3.0 is in progress, and it will run on the latest Node.js version. For more information, please consult our [migration guide](https://guide.meteor.com/3.0-migration.html). +> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://v3-docs.meteor.com).

What is Meteor?

@@ -24,11 +24,11 @@ Meteor is a full-stack JavaScript platform for developing modern web and mobile 1. The place to get started with Meteor is the [tutorials page](https://www.meteor.com/developers/tutorials). 1. [Meteor Examples](https://github.com/meteor/examples) is a list of examples using Meteor. You can also include your example with Meteor. - + 1. Once you are familiar with the basics, the [Meteor Guide](http://guide.meteor.com) covers intermediate material on how to use Meteor in a larger scale app. 1. Visit the [Meteor discussion forums](https://forums.meteor.com) to announce projects, get help, talk about the community, or discuss changes to core. - + 1. [Meteor Slack Community](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc) is the best place to ask (and answer!) technical questions and also meet Meteor developers. 1. [Atmosphere](https://atmospherejs.com) is the repository of community packages designed especially for Meteor. diff --git a/docs/source/install.md b/docs/source/install.md index 8f26fa65d3..6a58d65cfd 100644 --- a/docs/source/install.md +++ b/docs/source/install.md @@ -8,7 +8,7 @@ You need to install the Meteor command line tool to create, run, and manage your

Node.js version

-> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3.0 is in progress, and it will run on the latest Node.js version. For more information, please consult our [migration guide](https://guide.meteor.com/3.0-migration.html). +> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://v3-docs.meteor.com). - Node.js version >= 10 and <= 14 is required. - We recommend you using [nvm](https://github.com/nvm-sh/nvm) or [Volta](https://volta.sh/) for managing Node.js versions. @@ -30,10 +30,13 @@ You need to install the Meteor command line tool to create, run, and manage your Install the latest official version of Meteor.js from your terminal by running one of the commands below. You can check our [changelog](https://docs.meteor.com/changelog.html) for the release notes. -> Run `node -v` to ensure you are using Node.js 14. Meteor 3.0 is in progress, and it will run on the latest Node.js version. +> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 is released with support for the latest Node.js LTS version. +> For more information, please consult our [migration guide](https://guide.meteor.com/3.0-migration.html) and the [new docs](https://docs.meteor.com/). For Windows, Linux and OS X, you can run the following command: +> Preferably, do not use `sudo` to install Meteor. If you need to use `sudo`, please check the [troubleshooting section](#troubleshooting). + ```bash npm install -g meteor ``` @@ -67,6 +70,8 @@ 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`. +As a last resort you can delete the `.meteor` folder in your home directory and try to install Meteor again using the correct permissions. +

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: @@ -118,5 +123,4 @@ If you installed Meteor using npm, you can remove it by running: If you installed Meteor using curl, you can remove it by running: `rm -rf ~/.meteor` -`sudo rm /usr/local/bin/meteor`Β  - +`sudo rm /usr/local/bin/meteor` diff --git a/docs/source/packages/fetch.md b/docs/source/packages/fetch.md index 4f5176e374..016c0329f7 100644 --- a/docs/source/packages/fetch.md +++ b/docs/source/packages/fetch.md @@ -3,7 +3,7 @@ title: fetch description: Isomorphic modern/legacy/Node polyfill for WHATWG fetch(). --- -This package replaces the `http` package for HTTP calls. `fetch` package provides polyfill for the [WHATWG fetch specification](https://fetch.spec.whatwg.org/) for legacy browsers or defaults to the global class which is available in modern browsers and Node. It is recomended that you use this package for compatibility with non-modern browsers. +This package replaces the `http` package for HTTP calls. `fetch` package provides polyfill for the [WHATWG fetch specification](https://fetch.spec.whatwg.org/) for legacy browsers or defaults to the global class which is available in modern browsers and Node. It is recommended that you use this package for compatibility with non-modern browsers. For more information we recommend [reading the MDN articles](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) about it as this article covers only basic usage in Meteor. diff --git a/docs/source/packages/logging.md b/docs/source/packages/logging.md index 6c2013d7a2..8f3fa18338 100644 --- a/docs/source/packages/logging.md +++ b/docs/source/packages/logging.md @@ -3,7 +3,7 @@ title: logging description: Documentation of Meteor's logging utility --- -The `logging` package provides a standartised way for you to log and display in console various message from your application. +The `logging` package provides a standardised way for you to log and display in console various message from your application. The added benefit is that among other data it will show you the location where the log was fired, this is useful during debugging to quickly locate where the message is coming from. diff --git a/docs/source/packages/modules.md b/docs/source/packages/modules.md index 0f01c8ef6c..adc2b359c9 100644 --- a/docs/source/packages/modules.md +++ b/docs/source/packages/modules.md @@ -323,7 +323,7 @@ import { exportedPackageMethod } from "meteor/"; ``` > Note: Packages with `lazy` main modules cannot use `api.export` to export global -symbols to other packages/apps. Also, prior to Meteor 1.4.4.2 it is neccessary to explicitly name the file containing the module: `import "meteor//client.js"`. +symbols to other packages/apps. Also, prior to Meteor 1.4.4.2 it is necessary to explicitly name the file containing the module: `import "meteor//client.js"`. ## Local `node_modules` diff --git a/docs/source/packages/oauth-encryption.md b/docs/source/packages/oauth-encryption.md index 8b9e651ec4..bc78e63647 100644 --- a/docs/source/packages/oauth-encryption.md +++ b/docs/source/packages/oauth-encryption.md @@ -31,10 +31,16 @@ the top level of your source file), not called from inside of a `Meteor.startup` block. To avoid storing the secret key in your application's source code, you -can use [`Meteor.settings`](http://docs.meteor.com/#meteor_settings): +can provide the same value under [`Meteor.settings.packages.accounts-base.oauthSecretKey`](http://docs.meteor.com/#meteor_settings): -```js -Accounts.config({ oauthSecretKey: Meteor.settings.oauthSecretKey }); +```json +{ + "packages": { + "accounts-base": { + "oauthSecretKey": "onsqJ+1e4iGFlV0nhZYobg==" + } + } +} ``` diff --git a/docs/source/packages/packages-listing.md b/docs/source/packages/packages-listing.md new file mode 100644 index 0000000000..dca65fde57 --- /dev/null +++ b/docs/source/packages/packages-listing.md @@ -0,0 +1,158 @@ + +--- +title: Core Package Listing +description: list of all Meteor core packages. +--- + +[//]: # (Do not edit this file by hand.) + +[//]: # (This is a generated file.) + +[//]: # (If you want to change something in this file) + +[//]: # (go to meteor/docs/generators/packages-listing) + +# Core Packages + + +- [blaze](https://github.com/meteor/blaze) +- [react-packages](https://github.com/meteor/react-packages) +- [accounts-2fa](https://github.com/meteor/meteor/tree/devel/packages/accounts-2fa) +- [accounts-base](https://github.com/meteor/meteor/tree/devel/packages/accounts-base) +- [accounts-facebook](https://github.com/meteor/meteor/tree/devel/packages/accounts-facebook) +- [accounts-github](https://github.com/meteor/meteor/tree/devel/packages/accounts-github) +- [accounts-google](https://github.com/meteor/meteor/tree/devel/packages/accounts-google) +- [accounts-meetup](https://github.com/meteor/meteor/tree/devel/packages/accounts-meetup) +- [accounts-meteor-developer](https://github.com/meteor/meteor/tree/devel/packages/accounts-meteor-developer) +- [accounts-oauth](https://github.com/meteor/meteor/tree/devel/packages/accounts-oauth) +- [accounts-password](https://github.com/meteor/meteor/tree/devel/packages/accounts-password) +- [accounts-passwordless](https://github.com/meteor/meteor/tree/devel/packages/accounts-passwordless) +- [accounts-twitter](https://github.com/meteor/meteor/tree/devel/packages/accounts-twitter) +- [accounts-ui](https://github.com/meteor/meteor/tree/devel/packages/accounts-ui) +- [accounts-ui-unstyled](https://github.com/meteor/meteor/tree/devel/packages/accounts-ui-unstyled) +- [accounts-weibo](https://github.com/meteor/meteor/tree/devel/packages/accounts-weibo) +- [allow-deny](https://github.com/meteor/meteor/tree/devel/packages/allow-deny) +- [audit-argument-checks](https://github.com/meteor/meteor/tree/devel/packages/audit-argument-checks) +- [autopublish](https://github.com/meteor/meteor/tree/devel/packages/autopublish) +- [autoupdate](https://github.com/meteor/meteor/tree/devel/packages/autoupdate) +- [babel-compiler](https://github.com/meteor/meteor/tree/devel/packages/babel-compiler) +- [babel-runtime](https://github.com/meteor/meteor/tree/devel/packages/babel-runtime) +- [base64](https://github.com/meteor/meteor/tree/devel/packages/base64) +- [binary-heap](https://github.com/meteor/meteor/tree/devel/packages/binary-heap) +- [boilerplate-generator](https://github.com/meteor/meteor/tree/devel/packages/boilerplate-generator) +- [boilerplate-generator-tests](https://github.com/meteor/meteor/tree/devel/packages/boilerplate-generator-tests) +- [browser-policy](https://github.com/meteor/meteor/tree/devel/packages/browser-policy) +- [browser-policy-common](https://github.com/meteor/meteor/tree/devel/packages/browser-policy-common) +- [browser-policy-content](https://github.com/meteor/meteor/tree/devel/packages/browser-policy-content) +- [browser-policy-framing](https://github.com/meteor/meteor/tree/devel/packages/browser-policy-framing) +- [caching-compiler](https://github.com/meteor/meteor/tree/devel/packages/caching-compiler) +- [callback-hook](https://github.com/meteor/meteor/tree/devel/packages/callback-hook) +- [check](https://github.com/meteor/meteor/tree/devel/packages/check) +- [constraint-solver](https://github.com/meteor/meteor/tree/devel/packages/constraint-solver) +- [context](https://github.com/meteor/meteor/tree/devel/packages/context) +- [crosswalk](https://github.com/meteor/meteor/tree/devel/packages/crosswalk) +- [ddp](https://github.com/meteor/meteor/tree/devel/packages/ddp) +- [ddp-client](https://github.com/meteor/meteor/tree/devel/packages/ddp-client) +- [ddp-common](https://github.com/meteor/meteor/tree/devel/packages/ddp-common) +- [ddp-rate-limiter](https://github.com/meteor/meteor/tree/devel/packages/ddp-rate-limiter) +- [ddp-server](https://github.com/meteor/meteor/tree/devel/packages/ddp-server) +- [deprecated](https://github.com/meteor/meteor/tree/devel/packages/deprecated) +- [dev-error-overlay](https://github.com/meteor/meteor/tree/devel/packages/dev-error-overlay) +- [diff-sequence](https://github.com/meteor/meteor/tree/devel/packages/diff-sequence) +- [disable-oplog](https://github.com/meteor/meteor/tree/devel/packages/disable-oplog) +- [dynamic-import](https://github.com/meteor/meteor/tree/devel/packages/dynamic-import) +- [ecmascript](https://github.com/meteor/meteor/tree/devel/packages/ecmascript) +- [ecmascript-runtime](https://github.com/meteor/meteor/tree/devel/packages/ecmascript-runtime) +- [ecmascript-runtime-client](https://github.com/meteor/meteor/tree/devel/packages/ecmascript-runtime-client) +- [ecmascript-runtime-server](https://github.com/meteor/meteor/tree/devel/packages/ecmascript-runtime-server) +- [ejson](https://github.com/meteor/meteor/tree/devel/packages/ejson) +- [email](https://github.com/meteor/meteor/tree/devel/packages/email) +- [es5-shim](https://github.com/meteor/meteor/tree/devel/packages/es5-shim) +- [facebook-config-ui](https://github.com/meteor/meteor/tree/devel/packages/facebook-config-ui) +- [facebook-oauth](https://github.com/meteor/meteor/tree/devel/packages/facebook-oauth) +- [facts-base](https://github.com/meteor/meteor/tree/devel/packages/facts-base) +- [facts-ui](https://github.com/meteor/meteor/tree/devel/packages/facts-ui) +- [fetch](https://github.com/meteor/meteor/tree/devel/packages/fetch) +- [force-ssl](https://github.com/meteor/meteor/tree/devel/packages/force-ssl) +- [force-ssl-common](https://github.com/meteor/meteor/tree/devel/packages/force-ssl-common) +- [geojson-utils](https://github.com/meteor/meteor/tree/devel/packages/geojson-utils) +- [github-config-ui](https://github.com/meteor/meteor/tree/devel/packages/github-config-ui) +- [github-oauth](https://github.com/meteor/meteor/tree/devel/packages/github-oauth) +- [google-config-ui](https://github.com/meteor/meteor/tree/devel/packages/google-config-ui) +- [google-oauth](https://github.com/meteor/meteor/tree/devel/packages/google-oauth) +- [hot-code-push](https://github.com/meteor/meteor/tree/devel/packages/hot-code-push) +- [hot-module-replacement](https://github.com/meteor/meteor/tree/devel/packages/hot-module-replacement) +- [id-map](https://github.com/meteor/meteor/tree/devel/packages/id-map) +- [insecure](https://github.com/meteor/meteor/tree/devel/packages/insecure) +- [inter-process-messaging](https://github.com/meteor/meteor/tree/devel/packages/inter-process-messaging) +- [launch-screen](https://github.com/meteor/meteor/tree/devel/packages/launch-screen) +- [localstorage](https://github.com/meteor/meteor/tree/devel/packages/localstorage) +- [logging](https://github.com/meteor/meteor/tree/devel/packages/logging) +- [logic-solver](https://github.com/meteor/meteor/tree/devel/packages/logic-solver) +- [meetup-config-ui](https://github.com/meteor/meteor/tree/devel/packages/meetup-config-ui) +- [meetup-oauth](https://github.com/meteor/meteor/tree/devel/packages/meetup-oauth) +- [meteor](https://github.com/meteor/meteor/tree/devel/packages/meteor) +- [meteor-base](https://github.com/meteor/meteor/tree/devel/packages/meteor-base) +- [meteor-developer-config-ui](https://github.com/meteor/meteor/tree/devel/packages/meteor-developer-config-ui) +- [meteor-developer-oauth](https://github.com/meteor/meteor/tree/devel/packages/meteor-developer-oauth) +- [meteor-platform](https://github.com/meteor/meteor/tree/devel/packages/meteor-platform) +- [meteor-tool](https://github.com/meteor/meteor/tree/devel/packages/meteor-tool) +- [minifier-css](https://github.com/meteor/meteor/tree/devel/packages/minifier-css) +- [minifier-js](https://github.com/meteor/meteor/tree/devel/packages/minifier-js) +- [minimongo](https://github.com/meteor/meteor/tree/devel/packages/minimongo) +- [mobile-experience](https://github.com/meteor/meteor/tree/devel/packages/mobile-experience) +- [mobile-status-bar](https://github.com/meteor/meteor/tree/devel/packages/mobile-status-bar) +- [modern-browsers](https://github.com/meteor/meteor/tree/devel/packages/modern-browsers) +- [modules](https://github.com/meteor/meteor/tree/devel/packages/modules) +- [modules-runtime](https://github.com/meteor/meteor/tree/devel/packages/modules-runtime) +- [modules-runtime-hot](https://github.com/meteor/meteor/tree/devel/packages/modules-runtime-hot) +- [mongo](https://github.com/meteor/meteor/tree/devel/packages/mongo) +- [mongo-dev-server](https://github.com/meteor/meteor/tree/devel/packages/mongo-dev-server) +- [mongo-id](https://github.com/meteor/meteor/tree/devel/packages/mongo-id) +- [mongo-livedata](https://github.com/meteor/meteor/tree/devel/packages/mongo-livedata) +- [npm-mongo](https://github.com/meteor/meteor/tree/devel/packages/npm-mongo) +- [oauth](https://github.com/meteor/meteor/tree/devel/packages/oauth) +- [oauth-encryption](https://github.com/meteor/meteor/tree/devel/packages/oauth-encryption) +- [oauth1](https://github.com/meteor/meteor/tree/devel/packages/oauth1) +- [oauth2](https://github.com/meteor/meteor/tree/devel/packages/oauth2) +- [ordered-dict](https://github.com/meteor/meteor/tree/devel/packages/ordered-dict) +- [package-stats-opt-out](https://github.com/meteor/meteor/tree/devel/packages/package-stats-opt-out) +- [package-version-parser](https://github.com/meteor/meteor/tree/devel/packages/package-version-parser) +- [promise](https://github.com/meteor/meteor/tree/devel/packages/promise) +- [random](https://github.com/meteor/meteor/tree/devel/packages/random) +- [rate-limit](https://github.com/meteor/meteor/tree/devel/packages/rate-limit) +- [react-fast-refresh](https://github.com/meteor/meteor/tree/devel/packages/react-fast-refresh) +- [reactive-dict](https://github.com/meteor/meteor/tree/devel/packages/reactive-dict) +- [reactive-var](https://github.com/meteor/meteor/tree/devel/packages/reactive-var) +- [reload](https://github.com/meteor/meteor/tree/devel/packages/reload) +- [reload-safetybelt](https://github.com/meteor/meteor/tree/devel/packages/reload-safetybelt) +- [retry](https://github.com/meteor/meteor/tree/devel/packages/retry) +- [routepolicy](https://github.com/meteor/meteor/tree/devel/packages/routepolicy) +- [server-render](https://github.com/meteor/meteor/tree/devel/packages/server-render) +- [service-configuration](https://github.com/meteor/meteor/tree/devel/packages/service-configuration) +- [session](https://github.com/meteor/meteor/tree/devel/packages/session) +- [sha](https://github.com/meteor/meteor/tree/devel/packages/sha) +- [shell-server](https://github.com/meteor/meteor/tree/devel/packages/shell-server) +- [socket-stream-client](https://github.com/meteor/meteor/tree/devel/packages/socket-stream-client) +- [standard-app-packages](https://github.com/meteor/meteor/tree/devel/packages/standard-app-packages) +- [standard-minifier-css](https://github.com/meteor/meteor/tree/devel/packages/standard-minifier-css) +- [standard-minifier-js](https://github.com/meteor/meteor/tree/devel/packages/standard-minifier-js) +- [standard-minifiers](https://github.com/meteor/meteor/tree/devel/packages/standard-minifiers) +- [static-html](https://github.com/meteor/meteor/tree/devel/packages/static-html) +- [test-helpers](https://github.com/meteor/meteor/tree/devel/packages/test-helpers) +- [test-in-browser](https://github.com/meteor/meteor/tree/devel/packages/test-in-browser) +- [test-in-console](https://github.com/meteor/meteor/tree/devel/packages/test-in-console) +- [test-server-tests-in-console-once](https://github.com/meteor/meteor/tree/devel/packages/test-server-tests-in-console-once) +- [tinytest](https://github.com/meteor/meteor/tree/devel/packages/tinytest) +- [tinytest-harness](https://github.com/meteor/meteor/tree/devel/packages/tinytest-harness) +- [tracker](https://github.com/meteor/meteor/tree/devel/packages/tracker) +- [twitter-config-ui](https://github.com/meteor/meteor/tree/devel/packages/twitter-config-ui) +- [twitter-oauth](https://github.com/meteor/meteor/tree/devel/packages/twitter-oauth) +- [typescript](https://github.com/meteor/meteor/tree/devel/packages/typescript) +- [underscore](https://github.com/meteor/meteor/tree/devel/packages/underscore) +- [underscore-tests](https://github.com/meteor/meteor/tree/devel/packages/underscore-tests) +- [url](https://github.com/meteor/meteor/tree/devel/packages/url) +- [webapp](https://github.com/meteor/meteor/tree/devel/packages/webapp) +- [webapp-hashing](https://github.com/meteor/meteor/tree/devel/packages/webapp-hashing) +- [weibo-config-ui](https://github.com/meteor/meteor/tree/devel/packages/weibo-config-ui) +- [weibo-oauth](https://github.com/meteor/meteor/tree/devel/packages/weibo-oauth) \ No newline at end of file diff --git a/docs/source/packages/url.md b/docs/source/packages/url.md index a38971db91..4abeefcf5d 100644 --- a/docs/source/packages/url.md +++ b/docs/source/packages/url.md @@ -3,7 +3,7 @@ title: url description: Isomorphic modern/legacy/Node polyfill for WHATWG URL/URLSearchParams. --- -`url` package provides polyfill for the [WHATWG url specification](https://url.spec.whatwg.org/) for legacy browsers or defaults to the global class which is available in modern browsers and Node. It is recomended that you use this package for compatibility with non-modern browsers. +`url` package provides polyfill for the [WHATWG url specification](https://url.spec.whatwg.org/) for legacy browsers or defaults to the global class which is available in modern browsers and Node. It is recommended that you use this package for compatibility with non-modern browsers. For more information we recommend [reading the MDN articles](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) about it and looking over the [Node API documentation](https://nodejs.org/api/url.html#url_the_whatwg_url_api) for more details as this article covers only basic usage in Meteor. diff --git a/docs/source/packages/webapp.md b/docs/source/packages/webapp.md index b20d8a6edf..88d7574735 100644 --- a/docs/source/packages/webapp.md +++ b/docs/source/packages/webapp.md @@ -13,20 +13,20 @@ This package also allows you to add handlers for HTTP requests. This lets other services access your app's data through an HTTP API, allowing it to easily interoperate with tools and frameworks that don't yet support DDP. -`webapp` exposes the [connect](https://github.com/senchalabs/connect) API for -handling requests through `WebApp.connectHandlers`. +`webapp` exposes the [express](https://github.com/expressjs/express) API for +handling requests through `WebApp.handlers`. Here's an example that will let you handle a specific URL: ```js // Listen to incoming HTTP requests (can only be used on the server). -WebApp.connectHandlers.use('/hello', (req, res, next) => { +WebApp.handlers.use('/hello', (req, res, next) => { res.writeHead(200); res.end(`Hello world from: ${Meteor.release}`); }); ``` -{% apibox "WebApp.connectHandlers" %} -{% apibox "connectHandlersCallback(req, res, next)" %} +{% apibox "WebApp.handlers" %} +{% apibox "expressHandlersCallback(req, res, next)" %} ### Serving a Static Landing Page @@ -62,36 +62,38 @@ Here's a sample _index.html_ you might use to get started: ``` -Then using the connectHandlers method described above serve up your static HTML on app-root/ page load as shown below. +Then using the handlers method described above serve up your static HTML on app-root/ page load as shown below. ``` /* global WebApp Assets */ import crypto from 'crypto' -import connectRoute from 'connect-route' +import express from 'express' -WebApp.connectHandlers.use(connectRoute(function (router) { - router.get('/', function (req, res, next) { - const buf = Assets.getText('index.html') +const router = express.Router() - if (buf.length > 0) { - const eTag = crypto.createHash('md5').update(buf).digest('hex') +router.get('/', function (req, res, next) { + const buf = Assets.getText('index.html') - if (req.headers['if-none-match'] === eTag) { - res.writeHead(304, 'Not Modified') - return res.end() - } + if (buf.length > 0) { + const eTag = crypto.createHash('md5').update(buf).digest('hex') - res.writeHead(200, { - ETag: eTag, - 'Content-Type': 'text/html' - }) - - return res.end(buf); + if (req.headers['if-none-match'] === eTag) { + res.writeHead(304, 'Not Modified') + return res.end() } - return res.end('Index page not found!') - }) -})) + res.writeHead(200, { + ETag: eTag, + 'Content-Type': 'text/html' + }) + + return res.end(buf) + } + + return res.end('Index page not found!') +}) + +WebApp.handlers.use(router) ``` There are a couple things to think about with this approach. @@ -160,4 +162,4 @@ WebApp.addUpdatedNotifyHook(({arch, manifest, runtimeConfig}) => { {% apibox "WebApp.addUpdatedNotifyHook" %} {% apibox "addUpdatedNotifyHookCallback(options)" %} -{% apibox "main" %} \ No newline at end of file +{% apibox "main" %} diff --git a/docs/source/roadmap.md b/docs/source/roadmap.md index b04e4c7145..197d2eae96 100644 --- a/docs/source/roadmap.md +++ b/docs/source/roadmap.md @@ -66,7 +66,7 @@ We need to discuss further to decide whether or not to proceed with these implem - New Async Tracker; ([Blog Post](https://blog.meteor.com/new-meteor-js-2-10-and-the-async-tracker-feature-ffdbe817c801)) - New Suspense hooks for React + Meteor; ([Blog Post](https://blog.meteor.com/new-suspense-hooks-for-meteor-5391570b3007)) - Release Blaze 2.7 supporting async calls; ([Changelog](https://www.blazejs.org/changelog.html)) -- New Scaffold API / generate command; ([Blog Post](https://blog.meteor.com/new-meteor-2-9-and-the-scaffold-api-8b5b2b2b2b2b)) +- New Scaffold API / generate command; ([Blog Post](https://blog.meteor.com/new-meteorjs-2-9-and-the-new-scaffold-api-5fcc0f3b1ce5)) - Types added to the core; ([Blog Post](https://blog.meteor.com/new-meteor-2-8-1-and-adding-types-to-the-core-8a6ee56f0141)) - Update Apollo skeleton NPM dependencies; - MongoDB 6.0 Support; ([Discussion](https://github.com/meteor/meteor/discussions/12092) / [Blog Post](https://blog.meteor.com/new-meteor-2-11-and-the-new-embedded-mongodb-19767076961b)) diff --git a/docs/source/windows.md b/docs/source/windows.md index b576296d8a..b457cdeb0a 100644 --- a/docs/source/windows.md +++ b/docs/source/windows.md @@ -16,7 +16,7 @@ Unexpected mongo exit code 3221225781. Restarting. Can't start Mongo server. ``` -You [probably](https://github.com/meteor/meteor/issues/10036#issuecomment-416485306) need to install `Visual C++ Redistributable for Visual Studio`, depending on your Windows and Meteor embbeded version of MongoDB the version of Visual Studio could be different. You can check the version that we are using in our Windows test environment [here](https://github.com/meteor/meteor/blob/devel/appveyor.yml#L10) +You [probably](https://github.com/meteor/meteor/issues/10036#issuecomment-416485306) need to install `Visual C++ Redistributable for Visual Studio`, depending on your Windows and Meteor embedded version of MongoDB the version of Visual Studio could be different. You can check the version that we are using in our Windows test environment [here](https://github.com/meteor/meteor/blob/devel/appveyor.yml#L10) Starting from MongoDB 4.4.4 we started to use Visual Studio 2019. diff --git a/guide/_config.yml b/guide/_config.yml index 93800d42e0..0bac87bfcc 100644 --- a/guide/_config.yml +++ b/guide/_config.yml @@ -5,6 +5,9 @@ edit_branch: 'devel' edit_path: 'guide' content_root: 'source' versions: + - '2.16' + - '2.15' + - '2.14' - '2.13' - '2.12' - '2.11' @@ -42,7 +45,7 @@ sidebar_categories: - index - code-style - structure - - 2.13-migration + - 2.14-migration - 3.0-migration - prepare-meteor-3.0 Data: diff --git a/guide/package-lock.json b/guide/package-lock.json index 6cae1d4089..a72419e298 100644 --- a/guide/package-lock.json +++ b/guide/package-lock.json @@ -208,6 +208,134 @@ "dev": true, "optional": true }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-syntax-decorators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "integrity": "sha512-AWj19x2aDm8qFQ5O2JcD6pwJDW1YdcnO+1b81t7gxrGjz5VHiUqeYWAR4h7zueWMalRelrQDXprv2FrY1dbpbw==", + "dev": true + }, + "babel-plugin-transform-decorators-legacy": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz", + "integrity": "sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA==", + "dev": true, + "requires": { + "babel-plugin-syntax-decorators": "^6.1.18", + "babel-runtime": "^6.2.0", + "babel-template": "^6.3.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha512-F2rZGQnAdaHWQ8YAoeRbukc7HS9QgdgeyJ0rQDd485v9opwuPvjpPFcOOT/WmkKTdgy9ESgSPXDcTNpzrGr6iQ==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==", + "dev": true + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -657,6 +785,12 @@ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true }, + "core-decorators": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/core-decorators/-/core-decorators-0.11.2.tgz", + "integrity": "sha512-47n1NWwwc+qPmOMtY9zUKCM1cYfoxLvBRxKzirFrqhE61yqK+yZP/BOA3gjaBUVb9P46J1RyJjasrtqYoWCbvA==", + "dev": true + }, "core-js": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", @@ -915,6 +1049,12 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1161,6 +1301,12 @@ "is-glob": "^2.0.0" } }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -1760,6 +1906,19 @@ "sprintf-js": "^1.0.2" } }, + "hexo-inject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexo-inject/-/hexo-inject-1.0.0.tgz", + "integrity": "sha512-Ly0k7FO3G5+XNvFNE7yjSENSWy8QTnzl8cNFWYuMXRYMogbHd/Q0Ane8WCKYb5QD/A+WXC3rHb32wIGb0YAfVw==", + "dev": true, + "requires": { + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-polyfill": "^6.7.2", + "bluebird": "^3.3.4", + "core-decorators": "^0.11.0", + "underscore": "^1.8.3" + } + }, "hexo-log": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/hexo-log/-/hexo-log-0.2.0.tgz", @@ -1782,18 +1941,6 @@ "lodash": "^4.17.11" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true - }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -1821,228 +1968,12 @@ "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "dev": true - }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "dev": true - }, - "async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-syntax-decorators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha512-AWj19x2aDm8qFQ5O2JcD6pwJDW1YdcnO+1b81t7gxrGjz5VHiUqeYWAR4h7zueWMalRelrQDXprv2FrY1dbpbw==", - "dev": true - }, - "babel-plugin-transform-decorators-legacy": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz", - "integrity": "sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA==", - "dev": true, - "requires": { - "babel-plugin-syntax-decorators": "^6.1.18", - "babel-runtime": "^6.2.0", - "babel-template": "^6.3.0" - } - }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", - "integrity": "sha512-F2rZGQnAdaHWQ8YAoeRbukc7HS9QgdgeyJ0rQDd485v9opwuPvjpPFcOOT/WmkKTdgy9ESgSPXDcTNpzrGr6iQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==", - "dev": true - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", @@ -2072,36 +2003,6 @@ } } }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -2122,116 +2023,6 @@ "upath": "^1.1.1" } }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - } - } - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "dev": true - }, - "core-decorators": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/core-decorators/-/core-decorators-0.11.2.tgz", - "integrity": "sha512-47n1NWwwc+qPmOMtY9zUKCM1cYfoxLvBRxKzirFrqhE61yqK+yZP/BOA3gjaBUVb9P46J1RyJjasrtqYoWCbvA==", - "dev": true - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -2277,27 +2068,6 @@ } } }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -2334,13 +2104,6 @@ } } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2364,44 +2127,6 @@ } } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "dev": true - }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -2423,68 +2148,6 @@ } } }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2" - } - }, "hexo-fs": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-1.0.2.tgz", @@ -2497,67 +2160,6 @@ "graceful-fs": "^4.1.11" } }, - "hexo-inject": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexo-inject/-/hexo-inject-1.0.0.tgz", - "integrity": "sha512-Ly0k7FO3G5+XNvFNE7yjSENSWy8QTnzl8cNFWYuMXRYMogbHd/Q0Ane8WCKYb5QD/A+WXC3rHb32wIGb0YAfVw==", - "dev": true, - "requires": { - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-polyfill": "^6.7.2", - "bluebird": "^3.3.4", - "core-decorators": "^0.11.0", - "underscore": "^1.8.3" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, "is-descriptor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", @@ -2568,12 +2170,6 @@ "is-data-descriptor": "^1.0.1" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2609,69 +2205,18 @@ } } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", - "dev": true - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -2693,570 +2238,11 @@ "to-regex": "^3.0.2" } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "nan": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", - "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true } } }, @@ -3512,6 +2498,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, "is-accessor-descriptor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", @@ -3685,6 +2680,12 @@ "dev": true, "optional": true }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -3888,6 +2889,15 @@ "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", @@ -4725,6 +3735,12 @@ } } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", @@ -5265,6 +4281,12 @@ "integrity": "sha512-pQX4oiemzjBEELPqgK4WE+q0yhAqjp/yzusGtlSJsOuiDys0RQxggepYmo0BuegIDppYS3b3cpdegRwkpyN3hw==", "dev": true }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -5358,6 +4380,12 @@ "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", "dev": true }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/guide/package.json b/guide/package.json index b9798b0200..cc6e1a248d 100644 --- a/guide/package.json +++ b/guide/package.json @@ -22,5 +22,8 @@ "clean": "hexo clean", "test": "npm run clean; npm run build", "start": "npm run build && chexo @meteorjs/meteor-hexo-config -- server" + }, + "volta": { + "node": "14.21.3" } } diff --git a/guide/source/2.14-migration.md b/guide/source/2.14-migration.md new file mode 100644 index 0000000000..8dd7cd9848 --- /dev/null +++ b/guide/source/2.14-migration.md @@ -0,0 +1,67 @@ +--- +title: Migrating to Meteor 2.14 +description: How to migrate your application to Meteor 2.14. +--- + +Most of the new features in Meteor 2.14 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). + + +

Changes in Meteor 2.14

+ +

Cordova Package

+ +Cordova has been updated to v12.0.1 for Android and v7.0.1 for iOS. This +requires a few changes to your Cordova project: + + - The `splash-screen` package has removed the `cordova-plugin-splashscreen` + is now on `cordova-android` core, so we have removed the dependency from the + `splash-screen` package. + As a result we are dropping the support for dark mode splash screen on Android. + To create this now you need to create two themes on your `config.xml` file. + You can follow in their [docs](https://cordova.apache.org/docs/en/latest/core/features/splashscreen/index.html) how to update your splash screen + + +Your `.mobile-config.js` file should have the following preferences: + +```js + +App.setPreference('android-targetSdkVersion', '33') +App.setPreference('android-minSdkVersion', '28') + +``` + +

Migrating from a version older than 2.13?

+ +If you're migrating from a version of Meteor older than Meteor 2.13, there may +be important considerations not listed in this guide. + Please review the older migration guides for details: + +* [Migrating to Meteor 2.13](2.13-migration.html) (from 2.12) +* [Migrating to Meteor 2.12](2.12-migration.html) (from 2.11) +* [Migrating to Meteor 2.11](2.11-migration.html) (from 2.10) +* [Migrating to Meteor 2.10](2.10-migration.html) (from 2.9) +* [Migrating to Meteor 2.9](2.9-migration.html) (from 2.8) +* [Migrating to Meteor 2.8](2.8-migration.html) (from 2.7) +* [Migrating to Meteor 2.7](2.7-migration.html) (from 2.6) +* [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) diff --git a/guide/source/3.0-migration.md b/guide/source/3.0-migration.md index 8c33d97297..4fced532f6 100644 --- a/guide/source/3.0-migration.md +++ b/guide/source/3.0-migration.md @@ -3,41 +3,4 @@ title: Migrating to Meteor 3.0 description: How to migrate your application to Meteor 3.0. --- -> **This guide will be created as we get closer to the Meteor 3.0 beta release.** We are also evaluating new documentation platforms to improve our users' experience. - -## What's the status of version 3.0? - -**Latest version:** `3.0-alpha.19`
-**Node.js version:** `20.9.0 LTS` - -Meteor 3.0 is in alpha and not recommended for production. You can check the "[Release 3.0 Pull Request](https://github.com/meteor/meteor/pull/12359)" to see what is being changed. - -## How to prepare for version 3.0? - -You can follow the guide "[How to migrate to Meteor Async in Meteor 2.x](/prepare-meteor-3.0.html)" to help you prepare your application for the new version by starting to use async methods. - -## Frequently Asked Questions - -### How to test Meteor 3.0? - -You can create a new Meteor 3.0 project by running the command below: - -```bash -meteor create my-new-project --release 3.0-alpha.19 -``` - -### How to update from version 2? - -You can update your Meteor 2.x project by running the command below inside your project folder: - -```bash -meteor update --release 3.0-alpha.19 -``` - -### How to follow the progress on version 3? - -The best way to follow the progress is by checking the "[What's left until an official Meteor 3.0?](https://github.com/meteor/meteor/discussions/12865)" discussion. We have also been sharing constant updates on [this topic](https://forums.meteor.com/t/fibers-public-roadmap-and-meteor-3-0/59627/84) in our forum. - -### When will Meteor 3.0 be ready? - -Our plan is to release the beta version by the end of Q4 2023. An official version will depend a lot on user feedback, but we aim to release it by the end of Q1 2024. +Please visit [Meteor 3.0 Migration Guide](https://v3-migration-docs.meteor.com/) for our most up-to-date migration guide. diff --git a/guide/source/build-tool.md b/guide/source/build-tool.md index 46820815bd..1bb7d892f3 100644 --- a/guide/source/build-tool.md +++ b/guide/source/build-tool.md @@ -4,7 +4,7 @@ description: How to use Meteor's build system to compile your app. discourseTopicId: 19669 --- -The Meteor build system is the actual command line tool that you get when you install Meteor. You run it by typing the `meteor` command in your terminal, possibly followed by a set of arguments. Read the [docs about the command line tool](https://docs.meteor.com/commandline.html) or type `meteor help` in your terminal to learn about all of the commands. +The Meteor build system is the actual command line tool that you get when you install Meteor. You run it by typing the `meteor` command in your terminal, possibly followed by a set of arguments. Read the [docs about the command line tool](https://docs.meteor.com/cli/) or type `meteor help` in your terminal to learn about all of the commands.

What does it do?

@@ -16,7 +16,7 @@ After executing the `meteor` command to start the build tool you should leave it

Compiles files with build plugins

-The main function of the Meteor build tool is to run "build plugins". These plugins define different parts of your app build process. Meteor puts heavy emphasis on reducing or removing build configuration files, so you won't see any large build process config files like you would in Gulp or Webpack. The Meteor build process is configured almost entirely through adding and removing packages to your app and putting files in specially named directories. For example, to get all of the newest stable ES2015 JavaScript features in your app, you add the [`ecmascript` package](http://docs.meteor.com/#/full/ecmascript). This package provides support for ES2015 modules, which gives you even more fine grained control over file load order using ES2015 `import` and `export`. As new Meteor releases add new features to this package you get them for free. +The main function of the Meteor build tool is to run "build plugins". These plugins define different parts of your app build process. Meteor puts heavy emphasis on reducing or removing build configuration files, so you won't see any large build process config files like you would in Gulp or Webpack. The Meteor build process is configured almost entirely through adding and removing packages to your app and putting files in specially named directories. For example, to get all of the newest stable ES2015 JavaScript features in your app, you add the [`ecmascript` package](https://docs.meteor.com/packages/ecmascript.html). This package provides support for ES2015 modules, which gives you even more fine grained control over file load order using ES2015 `import` and `export`. As new Meteor releases add new features to this package you get them for free.

Controlling which files to build

@@ -224,7 +224,7 @@ For more examples and details on importing styles and using `@imports` with pack

Sass

-The best Sass build plugin for Meteor is [`fourseven:scss`](https://atmospherejs.com/fourseven/scss). +The best Sass build plugin for Meteor is [`leonardoventurini:scss`](https://atmospherejs.com/leonardoventurini/scss). An alternative to the previous recommended [`fourseven:scss`](https://atmospherejs.com/fourseven/scss) package.

Less

diff --git a/guide/source/collections.md b/guide/source/collections.md index c4b126787b..edb0ad3132 100644 --- a/guide/source/collections.md +++ b/guide/source/collections.md @@ -104,7 +104,7 @@ This example from the Todos app defines a schema with a few simple rules: 3. We specify the `incompleteCount` is a number, which on insertion is set to `0` if not otherwise specified. 4. We specify that the `userId`, which is optional, must be a string that looks like the ID of a user document. -We're using the SimpleSchema for Meteor related funcitonality, like IDs, but we encourage you to create custom regEx expressions for security reasons, for fields like `email` or `name`. Check out the [Simple Schema docs](https://github.com/longshotlabs/simpl-schema#regex) for more information. +We're using the SimpleSchema for Meteor related functionality, like IDs, but we encourage you to create custom regEx expressions for security reasons, for fields like `email` or `name`. Check out the [Simple Schema docs](https://github.com/longshotlabs/simpl-schema#regex) for more information. We attach the schema to the namespace of `Lists` directly, which allows us to check objects against this schema directly whenever we want, such as in a form or [Method](methods.html). In the [next section](#schemas-on-write) we'll see how to use this schema automatically when writing to the collection. diff --git a/guide/source/data-loading.md b/guide/source/data-loading.md index 27ed645cd4..eac550fd24 100644 --- a/guide/source/data-loading.md +++ b/guide/source/data-loading.md @@ -589,31 +589,35 @@ A pattern for turning a polled REST endpoint looks something like this: ```js const POLL_INTERVAL = 5000; -Meteor.publish('polled-publication', function() { - const publishedKeys = {}; +Meteor.publish('polled-publication', async function() { + const publishedKeys = {}; - const poll = () => { - // Let's assume the data comes back as an array of JSON documents, with an _id field - const data = HTTP.get(REST_URL, REST_OPTIONS); + const poll = async () => { + // Let's assume the data comes back as an array of JSON documents, with an _id field + const response = await fetch(REST_URL, REST_OPTIONS); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + data = await response.json(); + data.forEach((doc) => { + if (publishedKeys[doc._id]) { + this.changed(COLLECTION_NAME, doc._id, doc); + } else { + publishedKeys[doc._id] = true; + this.added(COLLECTION_NAME, doc._id, doc); + } + }); + } + }; - data.forEach((doc) => { - if (publishedKeys[doc._id]) { - this.changed(COLLECTION_NAME, doc._id, doc); - } else { - publishedKeys[doc._id] = true; - this.added(COLLECTION_NAME, doc._id, doc); - } + await poll(); + this.ready(); + + const interval = Meteor.setInterval(poll, POLL_INTERVAL); + + this.onStop(() => { + Meteor.clearInterval(interval); }); - }; - - poll(); - this.ready(); - - const interval = Meteor.setInterval(poll, POLL_INTERVAL); - - this.onStop(() => { - Meteor.clearInterval(interval); - }); }); ``` diff --git a/guide/source/deployment.md b/guide/source/deployment.md index 25e0842c67..fa9d8f08de 100644 --- a/guide/source/deployment.md +++ b/guide/source/deployment.md @@ -99,7 +99,7 @@ If you are hosting a webfont as part of your application and serving it via a CD ```js import { WebApp } from 'meteor/webapp'; -WebApp.rawConnectHandlers.use(function(req, res, next) { +WebApp.rawHandlers.use(function(req, res, next) { if (req._parsedUrl.pathname.match(/\.(ttf|ttc|otf|eot|woff|woff2|font\.css|css)$/)) { res.setHeader('Access-Control-Allow-Origin', /* your hostname, or just '*' */); } @@ -194,7 +194,7 @@ MONGO_URL=mongodb://localhost:27017/myapp ROOT_URL=http://my-app.com PORT=3000 n ``` * `ROOT_URL` is the base URL for your Meteor project -* `PORT` is the port at which the application is running +* `PORT` is the port at which the application is running * `MONGO_URL` is a [Mongo connection string URI](https://docs.mongodb.com/manual/reference/connection-string/) supplied by the MongoDB provider. @@ -322,7 +322,7 @@ Galaxy's UI provides a detailed logging system, which can be invaluable to deter If you really want to understand the ins and outs of running your Meteor application, you should use an Application Performance Monitoring (APM) service. There are multiple services designed for Meteor apps: -- [Meteor APM](https://www.meteor.com/cloud) +- [Meteor APM](https://galaxycloud.app/) - [Monti APM](https://montiapm.com/) - [Meteor Elastic APM](https://github.com/Meteor-Community-Packages/meteor-elastic-apm) diff --git a/guide/source/index.md b/guide/source/index.md index 9963e638ff..0f801b9b88 100644 --- a/guide/source/index.md +++ b/guide/source/index.md @@ -3,7 +3,7 @@ title: Introduction description: This is the guide for using Meteor, a full-stack JavaScript platform for developing modern web and mobile applications. --- -> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3.0 is in progress, and it will run on the latest Node.js version. For more information, please consult our [migration guide](https://guide.meteor.com/3.0-migration.html). +> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3.x has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://docs.meteor.com).

What is Meteor?

@@ -44,11 +44,11 @@ meteor 1. The place to get started with Meteor is the [tutorials page](https://www.meteor.com/developers/tutorials). 1. [Meteor Examples](https://github.com/meteor/examples) is a list of examples using Meteor. You can also include your example with Meteor. - + 1. Once you are familiar with the basics, the [Meteor Guide](http://guide.meteor.com) covers intermediate material on how to use Meteor in a larger scale app. 1. Visit the [Meteor discussion forums](https://forums.meteor.com) to announce projects, get help, talk about the community, or discuss changes to core. - + 1. [Meteor Slack Community](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc) is the best place to ask (and answer!) technical questions and also meet Meteor developers. 1. [Atmosphere](https://atmospherejs.com) is the repository of community packages designed especially for Meteor. diff --git a/guide/source/methods.md b/guide/source/methods.md index a9689a2ef1..3db5ca7c3c 100644 --- a/guide/source/methods.md +++ b/guide/source/methods.md @@ -171,35 +171,35 @@ updateText.run.call({ userId: 'abcd' }, { As you can see, this approach to calling Methods results in a better development workflow - you can more easily deal with the different parts of the Method separately and test your code without having to deal with Meteor internals. But this approach requires you to write a lot of boilerplate on the Method definition side. -

Advanced Methods with mdg:validated-method

+

Advanced Methods with jam:method

-To alleviate some of the boilerplate that's involved in correct Method definitions, we've published a wrapper package called `mdg:validated-method` that does most of this for you. Here's the same Method as above, but defined with the package: +To alleviate some of the boilerplate that's involved in correct Method definitions, you can use a package called `jam:method` that does most of this for you. Here's the same Method as above, but defined with the package: ```js -import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import { createMethod } from 'meteor/jam:method'; -export const updateText = new ValidatedMethod({ +export const updateText = createMethod({ name: 'todos.updateText', - validate: new SimpleSchema({ + schema: new SimpleSchema({ todoId: { type: String }, newText: { type: String } - }).validator(), - run({ todoId, newText }) { - const todo = Todos.findOne(todoId); - + }), + async run({ todoId, newText }) { + const todo = await Todos.findOneAsync(todoId); + if (!todo.editableBy(this.userId)) { throw new Meteor.Error('todos.updateText.unauthorized', 'Cannot edit todos in a private list that is not yours'); } - Todos.update(todoId, { + Todos.updateAsync(todoId, { $set: { text: newText } }); } }); ``` -You call it the same way you call the advanced Method above, but the Method definition is significantly simpler. We believe this style of Method lets you clearly see the important parts - the name of the Method sent over the wire, the format of the expected arguments, and the JavaScript namespace by which the Method can be referenced. Validated methods only accept a single argument and a callback function. +You call it the same way you call the advanced Method above, but the Method definition is significantly simpler. We believe this style of Method lets you clearly see the important parts - the name of the Method sent over the wire, the format of the expected arguments, and the JavaScript namespace by which the Method can be referenced.

Error handling

@@ -227,17 +227,13 @@ When the server was not able to complete the user's desired action because of a When a Method call fails because the arguments are of the wrong type, it's good to throw a `ValidationError`. This works like `Meteor.Error`, but is a custom constructor that enforces a standard error format that can be read by different form and validation libraries. In particular, if you are calling this Method from a form, throwing a `ValidationError` will make it possible to display nice error messages next to particular fields in the form. -When you use `mdg:validated-method` with `simpl-schema` as demonstrated above, this type of error is thrown for you. - -Read more about the error format in the [`mdg:validation-error` docs](https://atmospherejs.com/mdg/validation-error). -

Handling errors

When you call a Method, any errors thrown by it will be returned in the callback. At this point, you should identify which error type it is and display the appropriate message to the user. In this case, it is unlikely that the Method will throw a `ValidationError` or an internal server error, so we will only handle the unauthorized error: ```js // Call the Method -updateText.call({ +updateText({ todoId: '12345', newText: 'This is a todo item.' }, (err, res) => { @@ -261,7 +257,7 @@ We'll talk about how to handle the `ValidationError` in the section on forms bel

Errors in Method simulation

-When a Method is called, it usually runs twice---once on the client to simulate the result for Optimistic UI, and again on the server to make the actual change to the database. This means that if your Method throws an error, it will likely fail on the client _and_ the server. For this reason, `ValidatedMethod` turns on undocumented option in Meteor to avoid calling the server-side implementation if the simulation throws an error. +When a Method is called, it usually runs twice---once on the client to simulate the result for Optimistic UI, and again on the server to make the actual change to the database. This means that if your Method throws an error, it will likely fail on the client _and_ the server. For this reason, `jam:method` turns on [an option](https://github.com/jamauro/method#options-for-meteorapplyasync) in Meteor to avoid calling the server-side implementation if the simulation throws an error. While this behavior is good for saving server resources in cases where a Method will certainly fail, it's important to make sure that the simulation doesn't throw an error in cases where the server Method would have succeeded (for example, if you didn't load some data on the client that the Method needs to do the simulation properly). In this case, you can wrap server-side-only logic in a block that checks for a method simulation: @@ -283,13 +279,13 @@ const amountRegEx = /^\d*\.(\d\d)?$/; // This Method encodes the form validation requirements. // By defining them in the Method, we do client and server-side // validation in one place. -export const insert = new ValidatedMethod({ +export const insert = createMethod({ name: 'Invoices.methods.insert', - validate: new SimpleSchema({ + schema: new SimpleSchema({ email: { type: String, regEx: emailRegEx }, description: { type: String, min: 5 }, amount: { type: String, regEx: amountRegEx } - }).validator(), + }), run(newInvoice) { // In here, we can be sure that the newInvoice argument is // validated. @@ -299,7 +295,7 @@ export const insert = new ValidatedMethod({ 'Must be logged in to create an invoice.'); } - Invoices.insert(newInvoice) + Invoices.insertAsync(newInvoice) } }); ``` @@ -355,7 +351,7 @@ Template.Invoices_newInvoice.events({ amount: event.target.amount.value }; - insert.call(data, (err, res) => { + insert(data, (err, res) => { if (err) { if (err.error === 'validation-error') { // Initialize error object @@ -434,9 +430,9 @@ If we defined this Method in client and server code, as all Methods should be, a The client enters a special mode where it tracks all changes made to client-side collections, so that they can be rolled back later. When this step is complete, the user of your app sees their UI update instantly with the new content of the client-side database, but the server hasn't received any data yet. -If an exception is thrown from the Method simulation, then by default Meteor ignores it and continues to step (2). If you are using `ValidatedMethod` or pass a special `throwStubExceptions` option to `Meteor.apply`, then an exception thrown from the simulation will stop the server-side Method from running at all. +If an exception is thrown from the Method simulation, then by default Meteor ignores it and continues to step (2). If you are using `jam:method` or pass a special `throwStubExceptions` [option](https://github.com/jamauro/method#options-for-meteorapplyasync) to `Meteor.apply`, then an exception thrown from the simulation will stop the server-side Method from running at all. -The return value of the Method simulation is discarded, unless the `returnStubValue` option is passed when calling the Method, in which case it is returned to the Method caller. ValidatedMethod passes this option by default. +The return value of the Method simulation is discarded, unless the `returnStubValue` option is passed when calling the Method, in which case it is returned to the Method caller. `jam:method` passes this option by default.

2. A `method` DDP message is sent to the server

diff --git a/guide/source/performance-improvement.md b/guide/source/performance-improvement.md index f6721550f7..28298e8232 100644 --- a/guide/source/performance-improvement.md +++ b/guide/source/performance-improvement.md @@ -3,10 +3,10 @@ title: Performance improvements description: How to optimize your Meteor application for higher performance when you start growing. --- -This guide focuses on providing you tips and common practices on how to improve performance of your Meteor app (sometimes also called scaling). -It is important to note that at the end of the day Meteor is a Node.js app tied closely to MongoDB, -so a lot of the problems you are going to encounter are common to other Node.js and MongoDB apps. -Also do note that every app is different so there are unique challenges to each, therefore +This guide focuses on providing you tips and common practices on how to improve performance of your Meteor app (sometimes also called scaling). +It is important to note that at the end of the day Meteor is a Node.js app tied closely to MongoDB, +so a lot of the problems you are going to encounter are common to other Node.js and MongoDB apps. +Also do note that every app is different so there are unique challenges to each, therefore practices describe in this guide should be used as a guiding posts rather than absolutes. This guide has been heavily inspired by [Marcin Szuster's Vazco article](https://www.vazco.eu/blog/how-to-optimize-and-scale-meteor-projects), the official [Meteor Galaxy guide](https://galaxy-guide.meteor.com/), @@ -15,11 +15,11 @@ and talk by Paulo MogollΓ³n's talk at Impact 2022 titled ["First steps on scalin

Performance monitoring

Before any optimization can take place we need to know what is our problem. This is where APM (Application Performance Monitor) comes in. -If you are hosting on Galaxy then this is automatically included in the [Professional plan](https://www.meteor.com/cloud/pricing) -and you can learn more about in its [own dedicated guide article](https://cloud-guide.meteor.com/apm-getting-started.html). -For those hosting outside of Galaxy the most popular solution is to go with [Monti APM](https://montiapm.com/) which shares -all the main functionality with Galaxy APM. You can also choose other APM for Node.js, but they will not show you Meteor -specific data that Galaxy APM and Monti APM specialize in. For this guide we will focus on showing how to work with Galaxy APM, +If you are hosting on Galaxy then this is automatically included in the [Professional plan](https://galaxycloud.app/meteorjs/pricing) +and you can learn more about in its [own dedicated guide article](https://cloud-guide.meteor.com/apm-getting-started.html). +For those hosting outside of Galaxy the most popular solution is to go with [Monti APM](https://montiapm.com/) which shares +all the main functionality with Galaxy APM. You can also choose other APM for Node.js, but they will not show you Meteor +specific data that Galaxy APM and Monti APM specialize in. For this guide we will focus on showing how to work with Galaxy APM, which is the same as with Monti APM, for simplicity. Once you setup either of those APMs you will need to add a package to your Meteor app to start sending them data. @@ -37,9 +37,9 @@ meteor add montiapm:agent ```

Finding issues in APM

-APM will start with providing you with an overview of how your app is performing. You can then dive deep into details of -publications, methods, errors happening (both on client and server) and more. You will spend a lot of time in the detailed -tabs looking for methods and publications to improve and analyzing the impact of your actions. The process, for example for +APM will start with providing you with an overview of how your app is performing. You can then dive deep into details of +publications, methods, errors happening (both on client and server) and more. You will spend a lot of time in the detailed +tabs looking for methods and publications to improve and analyzing the impact of your actions. The process, for example for optimizing methods, will look like this: 1. Go to the detailed view under the Methods tab. @@ -52,14 +52,14 @@ Not every long-performing method has to be improved. Take a look at the followin * methodX - mean response time 1 515 ms, throughput 100,05/min * methodY - mean response time 34 000 ms, throughput 0,03/min -At first glance, the 34 seconds response time can catch your attention, and it may seem that the methodY -is more relevant to improvement. But don’t ignore the fact that this method is being used only once in +At first glance, the 34 seconds response time can catch your attention, and it may seem that the methodY +is more relevant to improvement. But don’t ignore the fact that this method is being used only once in a few hours by the system administrators or scheduled cron action. -And now, let’s take a look at the methodX. Its response time is evidently lower BUT compared to the frequency +And now, let’s take a look at the methodX. Its response time is evidently lower BUT compared to the frequency of use, it is still high, and without any doubt should be optimized first. -It’s also absolutely vital to remember that you shouldn't optimize everything as it goes. +It’s also absolutely vital to remember that you shouldn't optimize everything as it goes. The key is to think strategically and match the most critical issues with your product priorities. For more information about all the things you can find in Galaxy APM take a look at the Meteor APM section in [Galaxy Guide](https://galaxy-guide.meteor.com/apm-getting-started.html). @@ -71,75 +71,75 @@ At the same this is the most resource intensive part of a Meteor application. Under the hood WebSockets are being used with additional abilities provided by DDP.

Proper use of publications

-Since publications can get resource intensive they should be reserved for usage that requires up to date, live data or +Since publications can get resource intensive they should be reserved for usage that requires up to date, live data or that are changing frequently and you need the users to see that. -You will need to evaluate your app to figure out which situations these are. As a rule of thumb any data that are not -required to be live or are not changing frequently can be fetched once via other means and re-fetched as needed, +You will need to evaluate your app to figure out which situations these are. As a rule of thumb any data that are not +required to be live or are not changing frequently can be fetched once via other means and re-fetched as needed, in most cases the re-fetching shouldn't be necessary. -But even before you proceed any further there are a few improvements that you can make here. +But even before you proceed any further there are a few improvements that you can make here. First make sure that you only get the fields you need, limit the number of documents you send to the client to what you need (aka always set the `limit` option) and ensure that you have set all your indexes.

Methods over publications

-The first easiest replacement is to use Meteor methods instead of publications. In this case you can use the existing publication -and instead of returning a cursor you will call `.fetchAsync()` and return the actual data. The same performance improvements +The first easiest replacement is to use Meteor methods instead of publications. In this case you can use the existing publication +and instead of returning a cursor you will call `.fetchAsync()` and return the actual data. The same performance improvements to get the method work faster apply here, but once called it sends the data and you don't have the overhead of a publication. -What is crucial here is to ensure that your choice of a front-end framework doesn't call the method every time, but only once +What is crucial here is to ensure that your choice of a front-end framework doesn't call the method every time, but only once to load the data or when specifically needed (for example when the data gets updated due to user action or when the user requests it).

Publication replacements

Using methods has its limitations and there are other tools that you might want to evaluate as a potential replacement. -[Grapher](https://github.com/cult-of-coders/grapher) is a favorite answer and allows you to easily blend with another -replacement which is [GraphQL](https://graphql.org/) and in particular [Apollo GraphQL](https://www.apollographql.com/), +[Grapher](https://github.com/cult-of-coders/grapher) is a favorite answer and allows you to easily blend with another +replacement which is [GraphQL](https://graphql.org/) and in particular [Apollo GraphQL](https://www.apollographql.com/), which also has an integration [package](https://atmospherejs.com/meteor/apollo) with Meteor. Finally, you can also go back to using REST as well. Do note, that you can mix all of these based on your needs.

Low observer reuse

-Observers are among the key components of Meteor. They take care of observing documents on MongoDB and they notify changes. +Observers are among the key components of Meteor. They take care of observing documents on MongoDB and they notify changes. Creating them is an expensive operations, so you want to make sure that Meteor reuses them as much as possible. > [Learn more about observers](https://galaxy-guide.meteor.com/apm-know-your-observers.html) -The key for observer reuse is to make sure that the queries requested are identical. This means that user given values -should be standardised and so should any dynamic input like time. Publications for users should check if user is signed in +The key for observer reuse is to make sure that the queries requested are identical. This means that user given values +should be standardised and so should any dynamic input like time. Publications for users should check if user is signed in first before returning publication and if user is not signed in, then it should instead call `this.ready();`. > [Learn more on improving observer reuse](https://galaxy-guide.meteor.com/apm-improve-cpu-and-network-usage)

Redis Oplog

-[Redis Oplog](https://atmospherejs.com/cultofcoders/redis-oplog) is a popular solution to Meteor's Oplog tailing -(which ensures the reactivity, but has some severe limitations that especially impact performance). Redis Oplog as name -suggests uses [redis](https://redis.io/) to track changes to data that you only need and cache them. This reduces load on +[Redis Oplog](https://atmospherejs.com/cultofcoders/redis-oplog) is a popular solution to Meteor's Oplog tailing +(which ensures the reactivity, but has some severe limitations that especially impact performance). Redis Oplog as name +suggests uses [redis](https://redis.io/) to track changes to data that you only need and cache them. This reduces load on the server and database, allows you to track only the data that you want and only publish the changes you need.

Methods

-While methods are listed as one of the possible replacements for publications, they themselves can be made more performant, -after all it really depends on what you put inside them and APM will provide you with the necessary insight on which +While methods are listed as one of the possible replacements for publications, they themselves can be made more performant, +after all it really depends on what you put inside them and APM will provide you with the necessary insight on which methods are the problem.

Heavy actions

-In general heavy tasks that take a lot of resources or take long and block the server for that time should be taken out -and instead be run in its own server that focuses just on running those heavy tasks. This can be another Meteor server +In general heavy tasks that take a lot of resources or take long and block the server for that time should be taken out +and instead be run in its own server that focuses just on running those heavy tasks. This can be another Meteor server or even better something specifically optimized for that given task.

Reoccurring jobs

-Reoccurring jobs are another prime candidate to be taken out into its own application. What this means is that you will have -an independent server that is going to be tasked with running the reoccurring jobs and the main application will only add to +Reoccurring jobs are another prime candidate to be taken out into its own application. What this means is that you will have +an independent server that is going to be tasked with running the reoccurring jobs and the main application will only add to the list and be recipient of the results, most likely via database results.

Rate limiting

-Rate limit your methods to reduce effectiveness of DDOS attack and spare your server. This is also a good practice to -ensure that you don't accidentally DDOS your self. For example a user who clicks multiple time on a button that triggers -an expensive function. In this example you should also in general ensure that any button that triggers a server event +Rate limit your methods to reduce effectiveness of DDOS attack and spare your server. This is also a good practice to +ensure that you don't accidentally DDOS your self. For example a user who clicks multiple time on a button that triggers +an expensive function. In this example you should also in general ensure that any button that triggers a server event should be disabled until there is a response from the server that the event has finished. You can and should rate limit both methods and collections. @@ -154,15 +154,15 @@ These are all applicable, and you should spend some time researching into them a

IP whitelisting

-If your MongoDB hosting provider allows it, you should make sure that you whitelist the IPs of your application servers. -If you don't then your database servers are likely to come under attack from hackers trying to brute force their way in. +If your MongoDB hosting provider allows it, you should make sure that you whitelist the IPs of your application servers. +If you don't then your database servers are likely to come under attack from hackers trying to brute force their way in. Besides the security risk this also impacts performance as authentication is not a cheap operation and it will impact performance. See [Galaxy guide](https://galaxy-guide.meteor.com/container-environment.html#network-outgoing) on IP whitelisting to get IPs for your Galaxy servers.

Indexes

-While single indexes on one field are helpful on simple query calls, you will most likely have more advance queries with +While single indexes on one field are helpful on simple query calls, you will most likely have more advance queries with multiple variables. To cover those you will need to create compound indexes. For example: ```javascript @@ -177,7 +177,7 @@ Statistics.createIndexAsync( ``` When creating indexes you should sort the variables in ESR (equity, sort, range) style. Meaning, first you put variables that will be equal to something specific. Second you put variables that sort things, -and third variables that provide range for that query. +and third variables that provide range for that query. Further you should order these variables in a way that the fields that filter the most should be first. Make sure that all the indexes are used and remove unused indexes as leaving unused indexes will have negative impact @@ -187,7 +187,7 @@ on performance as the database will have to still keep track on all the indexed To optimize finds ensure that all queries have are indexed. Meaning that any `.find()` variables should be indexed as described above. -All your finds should have a limit on the return so that the database stops going through the data once it has reached +All your finds should have a limit on the return so that the database stops going through the data once it has reached the limit, and you only return the limited number of results instead of the whole database. Beware of queries with `n + 1` issue. For example in a database that has cars and car owners. You don't want to get cars, @@ -202,14 +202,14 @@ If you still have issues make sure that you read data from secondaries.

Beware of collection hooks

-While collection hooks can help in many cases beware of them and make sure that you understand how they work as they might -create additional queries that you might not know about. Make sure to review packages that use them so that they won't +While collection hooks can help in many cases beware of them and make sure that you understand how they work as they might +create additional queries that you might not know about. Make sure to review packages that use them so that they won't create additional queries.

Caching

Once your user base increases you want to invest into query caching like using Redis, Redis Oplog and other. -For more complex queries or when you are retrieving data from multiple collections, then you want to use [aggregation](https://www.mongodb.com/docs/manual/aggregation/) +For more complex queries or when you are retrieving data from multiple collections, then you want to use [aggregation](https://www.mongodb.com/docs/manual/aggregation/) and save their results.

Scaling

@@ -229,13 +229,13 @@ Galaxy has these as well. Learn more about [setting triggers for scaling on Gala Setting this is vital, so that your application can keep on running when you have extra people come and then saves you money by scaling down when the containers are not in use. When initially setting these pay a close attention to the performance of your app. you need to learn when is the right time to scale your app so it has enough time to spin up new containers before the existing one get overwhelmed by traffic and so on. -There are other points to pay attention to as well. For example if your app is used by corporation you might want to setup that on weekdays the minimum number of containers is going to increase just before the start of working hours and the then decrease the minimum to 1 for after hours and on weekends. +There are other points to pay attention to as well. For example if your app is used by corporation you might want to setup that on weekdays the minimum number of containers is going to increase just before the start of working hours and the then decrease the minimum to 1 for after hours and on weekends. Usually when you are working on performance issues you will have higher numbers of containers as you optimize your app. It is therefore vital to revisit your scaling setting after each rounds of improvements to ensure that scaling triggers are properly optimized.

Packages

-During development, it is very tempting to add packages to solve issue or support some features. -This should be done carefully and each package should be wetted carefully if it is a good fit for the application. -Besides security and maintenance issues you also want to know which dependencies given package introduces and +During development, it is very tempting to add packages to solve issue or support some features. +This should be done carefully and each package should be wetted carefully if it is a good fit for the application. +Besides security and maintenance issues you also want to know which dependencies given package introduces and as a whole what will be the impact on performance. diff --git a/guide/source/prepare-meteor-3.0.md b/guide/source/prepare-meteor-3.0.md index 3dd79429f0..bd0ccccb8b 100644 --- a/guide/source/prepare-meteor-3.0.md +++ b/guide/source/prepare-meteor-3.0.md @@ -3,119 +3,4 @@ title: How to migrate to Meteor Async in Meteor 2.x description: How to migrate your application to async methods and be ready to 3.0. --- -In the new Meteor 3.0, Meteor moves its methods/operations to asynchronous. In the past, version 2.x was using Fibers, our promise solution, which is no longer supported since Node 16, and to follow the community standards, we are moving to `async` and `await`. - -Here are a couple of methods that are now async, and you need to refactor them. Instead of findOne, you need to use the suffix Async, findOneAsync, for example: - -Mongo.Collection: -- findOneAsync -- insertAsync -- removeAsync -- updateAsync -- upsertAsync - -Collection.Cursor: -- countAsync -- fetchAsync -- forEachAsync -- mapAsync - -accounts-base: -- Meteor.userAsync() - -callback-hook:forEachAsync -- forEachAsync - -ddp-server -- Meteor.callAsync() - -The complete list of updated methods is listed [here](https://github.com/meteor/meteor/blob/d5c3b2eeafd0ad78ee7e2553f3f269c5c2a2e2a9/docs/generators/changelog/versions/3.0.md#L5-L17). - -If you want to understand better what was changed and the context of Fibers, read these complementary posts: -- [2.8](https://grubba.medium.com/new-meteor-2-8-and-the-new-mongodb-async-ap-edbcb853869a?source=user_profile---------9----------------------------) _New Meteor 2.8 and the new MongoDB Async API_ -- [2.8.1](https://grubba.medium.com/new-meteor-2-8-1-and-adding-types-to-the-core-8a6ee56f0141?source=user_profile---------7----------------------------) _New MeteorJS 2.8.1 and adding types to the core_ -- [2.9](https://blog.meteor.com/new-meteorjs-2-9-and-the-new-scaffold-api-5fcc0f3b1ce5) _New MeteorJS 2.9 and the new Scaffold API_ -- [2.10](https://blog.meteor.com/new-meteor-js-2-10-and-the-async-tracker-feature-ffdbe817c801) _New Meteor.js 2.10 and the Async Tracker Feature_ -- [2.11](https://grubba.medium.com/new-meteor-2-11-and-the-new-embedded-mongodb-19767076961b?source=user_profile---------4----------------------------) _New Meteor 2.11 and the new embedded MongoDB_ -- [2.12](https://grubba.medium.com/new-meteor-js-2-12-and-the-blaze-2-6-2-release-b72c2a7a593f?source=user_profile---------1----------------------------) _New Meteor.js 2.12 and Blaze 2.6.2 Release_ -- [2.13](https://grubba.medium.com/new-meteor-js-2-13-node-js-14-21-4-security-patch-and-blaze-2-7-1-release-60134947e4c?source=user_profile---------0----------------------------) _New Meteor.js 2.13, Node.js 14.21.4 security patch and Blaze 2.7.1 release_ - -To help Meteor users update their apps to the new Meteor version, you can follow this guide with some insights on how to do it. - -## Use at least Meteor version [2.8](https://blog.meteor.com/new-meteor-2-8-and-the-new-mongodb-async-ap-edbcb853869a) - -We recommend starting the async migration by updating your application to 2.8 or newer, as you can do this progressively. Unlike 3.0, you can simultaneously maintain the same codebase with the new asynchronous and old synchronous behaviors. Ideally, you should update to the latest version of Meteor 2.x and carefully follow each changelog. After you refactor all your code to async in version 2.x, you can more easily update it to version 3.0 by following all the changes listed in its [changelog](https://github.com/meteor/meteor/blob/d5c3b2eeafd0ad78ee7e2553f3f269c5c2a2e2a9/docs/generators/changelog/versions/3.0.md). - -To help with this update, we suggest you use a [codemod](https://www.sitepoint.com/getting-started-with-codemods/) to automate part of the refactoring process. Follow [this script](https://github.com/minhna/meteor-async-migration) created by [minhna](https://github.com/minhna). The project has documentation explaining how to run the script. This codemod should only affect the server side of your application. Starting the update from the front end or back end is a personal choice. While starting from the server side is a valid approach, it is essential to evaluate whether migrating features one by one might be a better strategy. This way, you can resolve errors incrementally and avoid the risk of encountering multiple client-side issues that could break the entire application. - -A helpful feature of the script is that it will refactor some methods to async, such as findOne, count, and other methods from the accounts-base package, such as `Meteor.user()`, and also the function that calls these methods by adding an 'async' before them. - -## Edge cases -Depending on your codebase, the codemod may not work in some specific scenarios. We'll list some edge case examples, and if this is the case for your codebase, you'll need to make the changes manually or refactor the codemod. - -### MongoDB methods updates -A possible edge case is if you are defining your MongoDB collection using the `meteor/quave:collections` package, the codemod will check if it is a MongoDB collection by checking the form of the imports - this means that when the script reads the import coming from ` quave`, it will not consider this to be a MongoDB collection. - -### Async functions -Let's assume your codebase has the same or similar issue listed above. This may imply some problems in refactoring for async functions since the codemod does not correspond to any async method case. This can generate other side effects that imply issues with refactoring forEachAsync, mapAsync, and others. - -### How do we identify those edge cases? -To identify these edge cases, you can use the search feature in your IDE to find your methods and start refactoring by running your refactored codemod or updating the code manually. Since it now only affects the server side, after refactoring, you can run your application, observe the errors that will occur in your terminal, and fix them progressively. -After refactoring the server side to async, your application will run without errors, and then you can move to the client side. - -## Changes for Blaze projects (at least [2.7](https://www.blazejs.org/changelog#v2702023may23)) -In Blaze, every HTML file has a related JavaScript file. After refactoring the JavaScript file to async, you will get a Promise wrapping the value instead of the actual value. To present it on your front end, you must unwrap it. Let's see an example: - -```javascript -{{#let shouldFlag=isFlagged}} - {{#if @pending 'shouldFlag' }} - - {{/if}} - {{#if @rejected 'shouldFlag' }} - - {{/if}} - {{#if @resolved 'shouldFlag' }} - - {{/if}} -{{/let}} -``` - -If you don't unwrap the value, you will get an unresolved promise on the front end. You can use Blaze [Async States](https://www.blazejs.org/api/spacebars#Async-states), which uses the Spacebars Meteor package to handle the promise state. With it, you can handle different states and return appropriate content. - -## Changes for React projects -We recommend installing the package `react-meteor-data`, which contains hooks for these new asynchronous methods. If you use `useFind` on the server side, with SSR, for example, you will need to use the new suspense/useFind hook. We recommend reading the [New Suspense Hooks for Meteor](https://blog.meteor.com/new-suspense-hooks-for-meteor-5391570b3007) article to understand this package better. Example: - -```javascript -const TaskList = () => { - useSubscribe("tasks"); - const tasks = useTracker('tasks',() => TasksCollection.find({}).fetch()); - return ( -
    - {tasks.map((task) => ( - - ))} -
- ); -}; - -export const App = () => { - return ( -
-

Welcome to Meteor!

- Loading...
}> - - - -
- ); -}; -``` - -Note that we're not using the if (loading) anymore. To see a practical project, you can check [simpletasks](https://github.com/fredmaiaarantes/simpletasks/), which already use asynchronous API. - -If you use `Tracker.autorun()`, for example, reading about the tracker with the [async callback function](https://blog.meteor.com/new-meteor-js-2-10-and-the-async-tracker-feature-ffdbe817c801) is also recommended. - - ------------ - -We hope to make your transition easier with these instructions, references, and tools. You may face some challenges, but remember that you can progressively refactor it. For more detailed updates on Meteor 3.0, please check our [Fibers project board](https://github.com/orgs/meteor/projects/10) and the [Meteor 3.0 PR](https://github.com/meteor/meteor/pull/12359). +Please visit [Migrating to Async in Meteor 2.x](https://v3-migration-docs.meteor.com/migrating-to-async-in-v2/) for more up-to-date information on getting your Meteor 2 application ready for Meteor 3.0. \ No newline at end of file diff --git a/guide/source/security.md b/guide/source/security.md index a6060a4858..157c60dd01 100644 --- a/guide/source/security.md +++ b/guide/source/security.md @@ -36,9 +36,9 @@ Each of these points will have their own section below.

Avoid allow/deny

-In this guide, we're going to take a strong position that using [allow](http://docs.meteor.com/#/full/allow) or [deny](http://docs.meteor.com/#/full/deny) to run MongoDB queries directly from the client is not a good idea. The main reason is that it is hard to follow the principles outlined above. It's extremely difficult to validate the complete space of possible MongoDB operators, which could potentially grow over time with new versions of MongoDB. +In this guide, we're going to take a strong position that using [allow](https://docs.meteor.com/api/collections.html#Mongo-Collection-allow) or [deny](https://docs.meteor.com/api/collections.html#Mongo-Collection-deny) to run MongoDB queries directly from the client is not a good idea. The main reason is that it is hard to follow the principles outlined above. It's extremely difficult to validate the complete space of possible MongoDB operators, which could potentially grow over time with new versions of MongoDB. -There have been several articles about the potential pitfalls of accepting MongoDB update operators from the client, in particular the [Allow & Deny Security Challenge](https://www.discovermeteor.com/blog/allow-deny-security-challenge/) and its [results](https://www.discovermeteor.com/blog/allow-deny-challenge-results/), both on the Discover Meteor blog. +There have been several articles about the potential pitfalls of accepting MongoDB update operators from the client, in particular the [Allow & Deny Security Challenge](https://web.archive.org/web/20220705130732/https://www.discovermeteor.com/blog/allow-deny-security-challenge/) and its [results](https://web.archive.org/web/20220819163744/https://www.discovermeteor.com/blog/allow-deny-challenge-results/), both on the Discover Meteor blog. Given the points above, we recommend that all Meteor apps should use Methods to accept data input from the client, and restrict the arguments accepted by each Method as tightly as possible. @@ -80,9 +80,9 @@ Meteor.methods({ If someone comes along and passes a non-ID selector like `{}`, they will end up deleting the entire collection. -

mdg:validated-method

+

jam:method

-To help you write good Methods that exhaustively validate their arguments, we've written a wrapper package for Methods that enforces argument validation. Read more about how to use it in the [Methods article](methods.html#validated-method). The rest of the code samples in this article will assume that you are using this package. If you aren't, you can still apply the same principles but the code will look a little different. +To help you write good Methods that exhaustively validate their arguments, you can use a community package for Methods that enforces argument validation. Read more about how to use it in the [Methods article](methods.html#jam-method). The rest of the code samples in this article will assume that you are using this package. If you aren't, you can still apply the same principles but the code will look a little different.

Don't pass userId from the client

@@ -116,25 +116,25 @@ The _only_ times you should be passing any user ID as an argument are the follow The best way to make your app secure is to understand all of the possible inputs that could come from an untrusted source, and make sure that they are all handled correctly. The easiest way to understand what inputs can come from the client is to restrict them to as small of a space as possible. This means your Methods should all be specific actions, and shouldn't take a multitude of options that change the behavior in significant ways. The end goal is that you can look at each Method in your app and validate or test that it is secure. Here's a secure example Method from the Todos example app: ```js -export const makePrivate = new ValidatedMethod({ +export const makePrivate = new createMethod({ name: 'lists.makePrivate', validate: new SimpleSchema({ listId: { type: String } }).validator(), - run({ listId }) { + async run({ listId }) { if (!this.userId) { throw new Meteor.Error('lists.makePrivate.notLoggedIn', 'Must be logged in to make private lists.'); } - const list = Lists.findOne(listId); + const list = await Lists.findOneAsync(listId); if (list.isLastPublicList()) { throw new Meteor.Error('lists.makePrivate.lastPublicList', 'Cannot make the last public list private.'); } - Lists.update(listId, { + await Lists.updateAsync(listId, { $set: { userId: this.userId } }); @@ -148,16 +148,16 @@ You can see that this Method does a _very specific thing_ - it makes a single li However, this doesn't mean you can't have any flexibility in your Methods. Let's look at an example: ```js -Meteor.users.methods.setUserData = new ValidatedMethod({ +Meteor.users.methods.setUserData = new createMethod({ name: 'Meteor.users.methods.setUserData', validate: new SimpleSchema({ fullName: { type: String, optional: true }, dateOfBirth: { type: Date, optional: true }, }).validator(), - run(fieldsToSet) { - Meteor.users.update(this.userId, { + async run(fieldsToSet) { + return (await Meteor.users.updateAsync(this.userId, { $set: fieldsToSet - }); + })); } }); ``` @@ -200,7 +200,8 @@ if (Meteor.isServer) { This will make every Method only callable 5 times per second per connection. This is a rate limit that shouldn't be noticeable by the user at all, but will prevent a malicious script from totally flooding the server with requests. You will need to tune the limit parameters to match your app's needs. -If you're using validated methods, there's an available [ddp-rate-limiter-mixin](https://github.com/nlhuykhang/ddp-rate-limiter-mixin). +If you're using `jam:method`, it comes with built in [rate-limiting](https://github.com/jamauro/method#rate-limiting). +

Publications

@@ -274,10 +275,10 @@ Publications are not reactive, and they only re-run when the currently logged in ```js // #1: Bad! If the owner of the list changes, the old owner will still see it -Meteor.publish('list', function (listId) { +Meteor.publish('list', async function (listId) { check(listId, String); - const list = Lists.findOne(listId); + const list = await Lists.findOneAsync(listId); if (list.userId !== this.userId) { throw new Meteor.Error('list.unauthorized', @@ -351,7 +352,7 @@ export const MMR = { ```js // In a file loaded on client and server -Meteor.users.methods.updateMMR = new ValidatedMethod({ +Meteor.users.methods.updateMMR = new createMethod({ name: 'Meteor.users.methods.updateMMR', validate: null, run() { @@ -470,7 +471,7 @@ Generally speaking, all production HTTP requests should go over HTTPS, and all W It's best to handle the redirection from HTTP to HTTPS on the platform which handles the SSL certificates and termination. * On [Galaxy](deployment.html#galaxy), enable the "Force HTTPS" setting on a specific domain in the "Domains & Encryption" section of the application's "Settings" tab. -* Other deployments *may* have control panel options or may need to be manually configured on the the proxy server (e.g. HAProxy, nginx, etc.). The articles linked above provide some assistance on this. +* Other deployments *may* have control panel options or may need to be manually configured on the proxy server (e.g. HAProxy, nginx, etc.). The articles linked above provide some assistance on this. In the event that a platform does not offer the ability to configure this, the `force-ssl` package can be added to the project and Meteor will attempt to intelligently redirect based on the presence of the `x-forwarded-for` header. @@ -497,7 +498,7 @@ By default, Helmet can be used to set various HTTP headers (see link above). The import helmet from "helmet"; // Within server side Meter.startup() -WebApp.connectHandlers.use(helmet()) +WebApp.handlers.use(helmet()) ``` At a minimum, Meteor recommends users to set the following headers. Note that code examples shown below are specific to Helmet. @@ -517,7 +518,7 @@ By default, Meteor recommends unsafe inline scripts and styles are allowed, sinc import helmet from "helmet"; // Within server side Meter.startup() -WebApp.connectHandlers.use( +WebApp.handlers.use( helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], @@ -696,7 +697,7 @@ With Helmet, Frameguard sets the X-Frame-Options header. import helmet from "helmet"; // Within server side Meter.startup() -WebApp.connectHandlers.use(helmet.frameguard()); // defaults to sameorigin +WebApp.handlers.use(helmet.frameguard()); // defaults to sameorigin ``` For more detail please read the following guide: [Frameguard](https://helmetjs.github.io/docs/frameguard/). diff --git a/guide/source/testing.md b/guide/source/testing.md index f7500c2db4..7dfffb4a51 100644 --- a/guide/source/testing.md +++ b/guide/source/testing.md @@ -238,9 +238,11 @@ import { Tracker } from 'meteor/tracker'; const withDiv = function withDiv(callback) { const el = document.createElement('div'); document.body.appendChild(el); + let view = null try { - callback(el); + view = callback(el); } finally { + if (view) Blaze.remove(view) document.body.removeChild(el); } }; @@ -248,9 +250,10 @@ const withDiv = function withDiv(callback) { export const withRenderedTemplate = function withRenderedTemplate(template, data, callback) { withDiv((el) => { const ourTemplate = isString(template) ? Template[template] : template; - Blaze.renderWithData(ourTemplate, data, el); + const view = Blaze.renderWithData(ourTemplate, data, el); Tracker.flush(); callback(el); + return view }); }; ``` diff --git a/guide/source/ui-ux.md b/guide/source/ui-ux.md index 4578cced7b..d4235c0f1e 100644 --- a/guide/source/ui-ux.md +++ b/guide/source/ui-ux.md @@ -11,9 +11,9 @@ Meteor supports many view layers. The most popular are: - [React](react.html): official [page](http://reactjs.org/) - [Blaze](blaze.html): official [page](http://blazejs.org/) -- [Angular](http://www.angular-meteor.com): official [page](https://angular.io/) +- [Angular](angular.html): official [page](https://angular.io/) - [Vue](vue.html): official [page](https://vuejs.org/) -- [Svelte](https://www.meteor.com/tutorials/svelte/creating-an-app): official [page](https://svelte.dev/) +- [Svelte](svelte.html): official [page](https://svelte.dev/) If you are starting with web development we recommend that you use Blaze as it's very simple to learn. diff --git a/guide/source/vue.md b/guide/source/vue.md index 831fb1d6f5..d28018c087 100644 --- a/guide/source/vue.md +++ b/guide/source/vue.md @@ -41,6 +41,12 @@ Meteor's build tool and Pub/Sub API (or Apollo) provides Vue with this API that

Integrating Vue With Meteor

+Creating vue3 app + +``` +meteor create --vue +``` + To start a new project: ```sh @@ -424,7 +430,7 @@ VueSSR.createApp = function (context) {

Async data and Hydration

-Hydration is the the word for loading state into components on the serverside and then reusing that data on the clientside. +Hydration is the word for loading state into components on the serverside and then reusing that data on the clientside. This allows components to fully render their markup on the server and prevents a 're-render' on the clientside when the bundle is loaded. [Nuxt](https://nuxtjs.org/) solves this gracefully with a feature called [asyncData](https://nuxtjs.org/guide/async-data). diff --git a/guide/source/writing-atmosphere-packages.md b/guide/source/writing-atmosphere-packages.md index 0449d0690d..31a3fa8738 100644 --- a/guide/source/writing-atmosphere-packages.md +++ b/guide/source/writing-atmosphere-packages.md @@ -296,6 +296,14 @@ Package.onTest(function(api) { From within your test entry point, you can import other files as you would in the package proper. +You can also use [`mtest`](https://github.com/zodern/mtest) to test your packages like so: + +```bash +mtest --package ./ --once 2.14 +``` + +Which helps immensely if you'd like to test your package in CI/CD setup. You can see an example [here](https://github.com/monti-apm/monti-apm-agent/blob/master/.github/workflows/test.yml). + You can read more about testing in Meteor in the [Testing article](testing.html).

Publishing your package

diff --git a/meteor b/meteor index 0f1769385c..517e4bd0fe 100755 --- a/meteor +++ b/meteor @@ -1,13 +1,13 @@ #!/usr/bin/env bash -BUNDLE_VERSION=14.21.4.3 - +BUNDLE_VERSION=22.18.0.3 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. # Use of : "${ARCH:=$(uname)}" assignment permits users to set their # architecture manually; this is useful for multi-arch systems whose -# uname executables may sometimes return different architectures in +# uname executables may sometimes return different architectures +# in # different contexts. # Ex: ARCH=arm64 meteor ARGS...; UNAME="$(uname)" @@ -31,9 +31,9 @@ if [ "$UNAME" = "Darwin" ] ; then fi elif [ "$UNAME" = "Linux" ] ; then : "${ARCH:=$(uname -m)}" - if [ "$ARCH" != "x86_64" ] ; then + if [[ "$ARCH" != "x86_64" && "$ARCH" != "aarch64" ]] ; then echo "Unsupported architecture: $ARCH" - echo "Meteor only supports x86_64" + echo "Meteor only supports x86_64 and aarch64" exit 1 fi fi @@ -122,6 +122,7 @@ fi DEV_BUNDLE="$SCRIPT_DIR/dev_bundle" METEOR="$SCRIPT_DIR/tools/index.js" +PROCESS_REQUIRES="$SCRIPT_DIR/tools/node-process-warnings.js" # Set the nofile ulimit as high as permitted by the hard-limit/kernel if [ "$(ulimit -Sn)" != "unlimited" ]; then @@ -147,5 +148,6 @@ fi exec "$DEV_BUNDLE/bin/node" \ --max-old-space-size=4096 \ --no-wasm-code-gc \ + --require="$PROCESS_REQUIRES"\ ${TOOL_NODE_FLAGS} \ "$METEOR" "$@" diff --git a/meteor.bat b/meteor.bat index aa6b05d750..1f0f75d081 100644 --- a/meteor.bat +++ b/meteor.bat @@ -48,6 +48,7 @@ SET BABEL_CACHE_DIR=%~dp0\.babel-cache "%~dp0\dev_bundle\bin\node.exe" ^ --no-wasm-code-gc ^ + --require="%~dp0\tools\node-process-warnings.js" ^ %TOOL_NODE_FLAGS% ^ "%~dp0\tools\index.js" %* diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/.gitignore b/npm-packages/babel-preset-meteor/.gitignore similarity index 100% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/.gitignore rename to npm-packages/babel-preset-meteor/.gitignore diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/LICENSE.txt b/npm-packages/babel-preset-meteor/LICENSE.txt similarity index 100% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/LICENSE.txt rename to npm-packages/babel-preset-meteor/LICENSE.txt diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/README.md b/npm-packages/babel-preset-meteor/README.md similarity index 100% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/README.md rename to npm-packages/babel-preset-meteor/README.md diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/package-lock.json b/npm-packages/babel-preset-meteor/babel-presets-meteor/package-lock.json deleted file mode 100644 index f8a4c3e1c7..0000000000 --- a/npm-packages/babel-preset-meteor/babel-presets-meteor/package-lock.json +++ /dev/null @@ -1,1057 +0,0 @@ -{ - "name": "babel-preset-meteor", - "version": "7.10.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/compat-data": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", - "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==" - }, - "@babel/core": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.16.tgz", - "integrity": "sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.16", - "@babel/helper-compilation-targets": "^7.13.16", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.16", - "@babel/parser": "^7.13.16", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.15", - "@babel/types": "^7.13.16", - "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" - } - }, - "@babel/generator": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.16.tgz", - "integrity": "sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg==", - "requires": { - "@babel/types": "^7.13.16", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", - "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", - "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz", - "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==", - "requires": { - "@babel/compat-data": "^7.13.15", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.13.11", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", - "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", - "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "regexpu-core": "^4.7.1" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", - "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", - "requires": { - "@babel/types": "^7.13.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", - "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-wrap-function": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", - "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", - "requires": { - "@babel/types": "^7.12.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" - }, - "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==" - }, - "@babel/helper-wrap-function": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", - "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "@babel/helpers": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.17.tgz", - "integrity": "sha512-Eal4Gce4kGijo1/TGJdqp3WuhllaMLSrW6XcL0ulyUAQOuxHcCafZE8KHg9857gcTehsm/v7RcOx2+jp0Ryjsg==", - "dev": true, - "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.17", - "@babel/types": "^7.13.17" - } - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.16.tgz", - "integrity": "sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw==" - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", - "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", - "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", - "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", - "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", - "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", - "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", - "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", - "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", - "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", - "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.13.16.tgz", - "integrity": "sha512-ad3PHUxGnfWF4Efd3qFuznEtZKoBp0spS+DgqzVzRPV7urEBvPLue3y2j80w4Jf2YLzZHj8TOv/Lmvdmh3b2xg==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-classes": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", - "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", - "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz", - "integrity": "sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", - "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", - "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", - "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", - "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-replace-supers": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", - "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", - "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", - "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", - "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", - "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", - "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", - "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", - "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", - "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==" - } - } - }, - "@babel/runtime": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.17.tgz", - "integrity": "sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.17.tgz", - "integrity": "sha512-BMnZn0R+X6ayqm3C3To7o1j7Q020gWdqdyP50KEoVqaCO2c/Im7sYZSmVgvefp8TTMQ+9CtwuBp0Z1CZ8V3Pvg==", - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.16", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.16", - "@babel/types": "^7.13.17", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.17.tgz", - "integrity": "sha512-RawydLgxbOPDlTLJNtoIypwdmAy//uQIzlKt2+iBiJaRlVuI6QLUxVAyWGNfOzp8Yu4L4lLIacoCyTNtpb4wiA==", - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.16.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.5.tgz", - "integrity": "sha512-C2HAjrM1AI/djrpAUU/tr4pml1DqLIzJKSLDBXBrNErl9ZCCTXdhwxdJjYc16953+mBWf7Lw+uUJgpgb8cN71A==", - "requires": { - "caniuse-lite": "^1.0.30001214", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.719", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - } - }, - "caniuse-lite": { - "version": "1.0.30001214", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001214.tgz", - "integrity": "sha512-O2/SCpuaU3eASWVaesQirZv1MSjUNOvmugaD8zNSJqw6Vv5SGwoOpA9LJs3pNPfM745nxqPvfZY3MQKY4AKHYg==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "electron-to-chromium": { - "version": "1.3.720", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.720.tgz", - "integrity": "sha512-B6zLTxxaOFP4WZm6DrvgRk8kLFYWNhQ5TrHMC0l5WtkMXhU5UbnvWoTfeEwqOruUSlNMhVLfYak7REX6oC5Yfw==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==" - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "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=" - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" - } - } -} diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/proposals.js b/npm-packages/babel-preset-meteor/babel-presets-meteor/proposals.js deleted file mode 100644 index d429ab1224..0000000000 --- a/npm-packages/babel-preset-meteor/babel-presets-meteor/proposals.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.plugins = [ - require("@babel/plugin-syntax-nullish-coalescing-operator"), - require("@babel/plugin-proposal-nullish-coalescing-operator"), - - require("@babel/plugin-syntax-optional-chaining"), - require("@babel/plugin-proposal-optional-chaining"), - - require("@babel/plugin-syntax-optional-catch-binding"), - require("@babel/plugin-proposal-optional-catch-binding"), - - require("@babel/plugin-syntax-class-properties"), - require("@babel/plugin-proposal-class-properties"), - - require("@babel/plugin-syntax-async-generators"), - require("@babel/plugin-proposal-async-generator-functions"), - - require("@babel/plugin-syntax-object-rest-spread"), - require("@babel/plugin-proposal-object-rest-spread"), - - require("@babel/plugin-proposal-logical-assignment-operators"), -]; diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/index.js b/npm-packages/babel-preset-meteor/index.js similarity index 100% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/index.js rename to npm-packages/babel-preset-meteor/index.js diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/modern.js b/npm-packages/babel-preset-meteor/modern.js similarity index 95% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/modern.js rename to npm-packages/babel-preset-meteor/modern.js index cb36342a31..a1d56ad1e4 100644 --- a/npm-packages/babel-preset-meteor/babel-presets-meteor/modern.js +++ b/npm-packages/babel-preset-meteor/modern.js @@ -26,5 +26,6 @@ exports.minimumVersions = { // https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js electron: [1, 6], // https://github.com/meteor/babel-preset-meteor/issues/13 - samsungInternet: [6, 2] + samsungInternet: [6, 2], + facebook: 325 }; diff --git a/npm-packages/babel-preset-meteor/package-lock.json b/npm-packages/babel-preset-meteor/package-lock.json new file mode 100644 index 0000000000..9b13786a82 --- /dev/null +++ b/npm-packages/babel-preset-meteor/package-lock.json @@ -0,0 +1,1314 @@ +{ + "name": "babel-preset-meteor", + "version": "7.10.4", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", + "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==" + }, + "@babel/core": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.0.tgz", + "integrity": "sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.0", + "@babel/helper-compilation-targets": "^7.13.16", + "@babel/helper-module-transforms": "^7.14.0", + "@babel/helpers": "^7.14.0", + "@babel/parser": "^7.14.0", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.14.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" + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", + "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "requires": { + "@babel/highlight": "^7.24.6", + "picocolors": "^1.0.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "requires": { + "@babel/types": "^7.24.6" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", + "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==" + }, + "@babel/helper-function-name": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", + "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "requires": { + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "requires": { + "@babel/types": "^7.24.6" + } + }, + "@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==" + }, + "@babel/template": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", + "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "requires": { + "@babel/code-frame": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", + "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", + "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "requires": { + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", + "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "requires": { + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + } + }, + "@babel/helper-replace-supers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", + "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", + "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==" + } + } + }, + "@babel/helper-simple-access": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", + "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", + "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "requires": { + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", + "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==" + }, + "@babel/helper-validator-identifier": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", + "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==" + }, + "@babel/helper-validator-option": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", + "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==" + }, + "@babel/helper-wrap-function": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz", + "integrity": "sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==", + "requires": { + "@babel/helper-function-name": "^7.24.6", + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "requires": { + "@babel/highlight": "^7.24.6", + "picocolors": "^1.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", + "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "requires": { + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==" + }, + "@babel/template": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", + "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "requires": { + "@babel/code-frame": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helpers": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" + } + }, + "@babel/highlight": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", + "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.24.6", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==" + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.6.tgz", + "integrity": "sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==", + "requires": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-remap-async-to-generator": "^7.24.6", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "requires": { + "@babel/highlight": "^7.24.6", + "picocolors": "^1.0.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "requires": { + "@babel/types": "^7.24.6" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", + "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==" + }, + "@babel/helper-function-name": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", + "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "requires": { + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.6.tgz", + "integrity": "sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-wrap-function": "^7.24.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", + "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==" + }, + "@babel/helper-validator-identifier": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", + "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==" + }, + "@babel/helper-wrap-function": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz", + "integrity": "sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==", + "requires": { + "@babel/helper-function-name": "^7.24.6", + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/highlight": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", + "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.24.6", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==" + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/template": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", + "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "requires": { + "@babel/code-frame": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6" + } + }, + "@babel/types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "requires": { + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.6.tgz", + "integrity": "sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + } + } + }, + "@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.6.tgz", + "integrity": "sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + } + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.6.tgz", + "integrity": "sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + } + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.6.tgz", + "integrity": "sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==", + "requires": { + "@babel/helper-compilation-targets": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.6" + }, + "dependencies": { + "@babel/helper-compilation-targets": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", + "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", + "requires": { + "@babel/compat-data": "^7.24.6", + "@babel/helper-validator-option": "^7.24.6", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz", + "integrity": "sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6" + } + } + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.6.tgz", + "integrity": "sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + } + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.6.tgz", + "integrity": "sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + } + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz", + "integrity": "sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.6" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", + "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==" + } + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "@babel/runtime": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", + "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "caniuse-lite": { + "version": "1.0.30001627", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz", + "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "electron-to-chromium": { + "version": "1.4.789", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", + "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==" + }, + "escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "update-browserslist-db": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "dependencies": { + "picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + } + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } +} diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/package.json b/npm-packages/babel-preset-meteor/package.json similarity index 79% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/package.json rename to npm-packages/babel-preset-meteor/package.json index 60da6fdc9a..f19c86de82 100644 --- a/npm-packages/babel-preset-meteor/babel-presets-meteor/package.json +++ b/npm-packages/babel-preset-meteor/package.json @@ -1,22 +1,16 @@ { "name": "babel-preset-meteor", - "version": "7.10.0", + "version": "7.10.4", "description": "Babel preset for ES2015+ features supported by Meteor", "author": "Ben Newman ", "license": "MIT", "repository": "https://github.com/meteor/babel-preset-meteor", "main": "index.js", + "type": "commonjs", "scripts": { "update-versions": "bash scripts/update-versions" }, "dependencies": { - "@babel/plugin-proposal-async-generator-functions": "^7.13.15", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", - "@babel/plugin-proposal-optional-chaining": "^7.13.12", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -24,16 +18,23 @@ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.13.0", + "@babel/plugin-transform-async-generator-functions": "^7.24.6", "@babel/plugin-transform-async-to-generator": "^7.13.0", "@babel/plugin-transform-block-scoped-functions": "^7.12.13", "@babel/plugin-transform-block-scoping": "^7.13.16", + "@babel/plugin-transform-class-properties": "^7.24.6", "@babel/plugin-transform-classes": "^7.13.0", "@babel/plugin-transform-computed-properties": "^7.13.0", "@babel/plugin-transform-destructuring": "^7.13.17", "@babel/plugin-transform-exponentiation-operator": "^7.12.13", "@babel/plugin-transform-for-of": "^7.13.0", "@babel/plugin-transform-literals": "^7.12.13", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.6", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.6", + "@babel/plugin-transform-object-rest-spread": "^7.24.6", "@babel/plugin-transform-object-super": "^7.12.13", + "@babel/plugin-transform-optional-catch-binding": "^7.24.6", + "@babel/plugin-transform-optional-chaining": "^7.24.6", "@babel/plugin-transform-parameters": "^7.13.0", "@babel/plugin-transform-property-literals": "^7.12.13", "@babel/plugin-transform-regenerator": "^7.13.15", diff --git a/npm-packages/babel-preset-meteor/proposals.js b/npm-packages/babel-preset-meteor/proposals.js new file mode 100644 index 0000000000..e2a314ac56 --- /dev/null +++ b/npm-packages/babel-preset-meteor/proposals.js @@ -0,0 +1,21 @@ +exports.plugins = [ + require("@babel/plugin-syntax-nullish-coalescing-operator"), + require("@babel/plugin-transform-nullish-coalescing-operator"), + + require("@babel/plugin-syntax-optional-chaining"), + require("@babel/plugin-transform-optional-chaining"), + + require("@babel/plugin-syntax-optional-catch-binding"), + require("@babel/plugin-transform-optional-catch-binding"), + + require("@babel/plugin-syntax-class-properties"), + require("@babel/plugin-transform-class-properties"), + + require("@babel/plugin-syntax-async-generators"), + require("@babel/plugin-transform-async-generator-functions"), + + require("@babel/plugin-syntax-object-rest-spread"), + require("@babel/plugin-transform-object-rest-spread"), + + require("@babel/plugin-transform-logical-assignment-operators") +]; diff --git a/npm-packages/babel-preset-meteor/babel-presets-meteor/scripts/update-versions b/npm-packages/babel-preset-meteor/scripts/update-versions similarity index 100% rename from npm-packages/babel-preset-meteor/babel-presets-meteor/scripts/update-versions rename to npm-packages/babel-preset-meteor/scripts/update-versions diff --git a/npm-packages/cordova-plugin-meteor-webapp/package-lock.json b/npm-packages/cordova-plugin-meteor-webapp/package-lock.json index 3037eaae66..c4dcebebf9 100644 --- a/npm-packages/cordova-plugin-meteor-webapp/package-lock.json +++ b/npm-packages/cordova-plugin-meteor-webapp/package-lock.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-meteor-webapp", - "version": "2.0.0", + "version": "2.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -95,6 +95,11 @@ "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", "dev": true }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" + }, "archiver": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", @@ -796,11 +801,6 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", @@ -2304,11 +2304,6 @@ "text-table": "~0.2.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2934,10 +2929,7 @@ "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=" }, "has-flag": { "version": "3.0.0", @@ -3121,11 +3113,6 @@ "through": "^2.3.6" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -3216,9 +3203,9 @@ "dev": true }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "ansi-styles": { @@ -5041,11 +5028,6 @@ "strip-ansi": "^4.0.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -5072,10 +5054,7 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" }, "strip-bom": { "version": "3.0.0", diff --git a/npm-packages/cordova-plugin-meteor-webapp/package.json b/npm-packages/cordova-plugin-meteor-webapp/package.json index e38a37b301..71873605c4 100644 --- a/npm-packages/cordova-plugin-meteor-webapp/package.json +++ b/npm-packages/cordova-plugin-meteor-webapp/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-meteor-webapp", - "version": "2.0.0", + "version": "2.0.4", "description": "Cordova plugin that serves a Meteor web app through a local server and implements hot code push", "cordova": { "id": "cordova-plugin-meteor-webapp", @@ -22,6 +22,7 @@ ], "author": "Meteor Development Group", "license": "MIT", + "type": "commonjs", "scripts": { "pretest": "ios-sim start --devicetypeid=iPhone-11-Pro-Max", "test": "cordova-paramedic --plugin . --platform ios --target 'iPhone-11-Pro-Max' --args=--buildFlag='-UseModernBuildSystem=0' --verbose" @@ -30,7 +31,7 @@ "xcode": "^2.0.0" }, "devDependencies": { - "cordova": "^9.0.0", + "cordova": "^12.0.0", "cordova-paramedic": "github:meteor/cordova-paramedic#40df66c3efc2f0db4d66b8c172174a68c031c114", "ios-deploy": "^1.10.0-beta.3", "ios-sim": "^8.0.2" diff --git a/npm-packages/cordova-plugin-meteor-webapp/src/android/AssetBundleManager.java b/npm-packages/cordova-plugin-meteor-webapp/src/android/AssetBundleManager.java index fa50d1f56a..0a95884b03 100644 --- a/npm-packages/cordova-plugin-meteor-webapp/src/android/AssetBundleManager.java +++ b/npm-packages/cordova-plugin-meteor-webapp/src/android/AssetBundleManager.java @@ -86,7 +86,7 @@ class AssetBundleManager { } public void checkForUpdates(final HttpUrl baseUrl) { - HttpUrl manifestUrl = baseUrl.resolve("manifest.json"); + HttpUrl manifestUrl = baseUrl.newBuilder().addPathSegment("manifest.json").build(); Request request = new Request.Builder().url(manifestUrl).build(); diff --git a/npm-packages/cordova-plugin-meteor-webapp/src/android/WebAppLocalServer.java b/npm-packages/cordova-plugin-meteor-webapp/src/android/WebAppLocalServer.java index 2d8abac9ff..c5d06ab120 100644 --- a/npm-packages/cordova-plugin-meteor-webapp/src/android/WebAppLocalServer.java +++ b/npm-packages/cordova-plugin-meteor-webapp/src/android/WebAppLocalServer.java @@ -270,7 +270,7 @@ public class WebAppLocalServer extends CordovaPlugin implements AssetBundleManag callbackContext.error("checkForUpdates requires a rootURL to be configured"); return; } - HttpUrl baseUrl = rootUrl.resolve("__cordova/"); + HttpUrl baseUrl = rootUrl.newBuilder().addPathSegment("__cordova").build(); assetBundleManager.checkForUpdates(baseUrl); callbackContext.success(); } diff --git a/npm-packages/cordova-plugin-meteor-webapp/src/ios/GCDWebServer b/npm-packages/cordova-plugin-meteor-webapp/src/ios/GCDWebServer new file mode 160000 index 0000000000..38e9bf08e0 --- /dev/null +++ b/npm-packages/cordova-plugin-meteor-webapp/src/ios/GCDWebServer @@ -0,0 +1 @@ +Subproject commit 38e9bf08e09490561f4e982867cbc2adcee2b886 diff --git a/npm-packages/cordova-plugin-meteor-webapp/tests/fixtures/bundled_www/cordova_plugins.js b/npm-packages/cordova-plugin-meteor-webapp/tests/fixtures/bundled_www/cordova_plugins.js index a9491512f4..c2fb084f46 100644 --- a/npm-packages/cordova-plugin-meteor-webapp/tests/fixtures/bundled_www/cordova_plugins.js +++ b/npm-packages/cordova-plugin-meteor-webapp/tests/fixtures/bundled_www/cordova_plugins.js @@ -8,14 +8,6 @@ module.exports = [ "window.StatusBar" ] }, - { - "file": "plugins/cordova-plugin-splashscreen/www/splashscreen.js", - "id": "cordova-plugin-splashscreen.SplashScreen", - "pluginId": "cordova-plugin-splashscreen", - "clobbers": [ - "navigator.splashscreen" - ] - }, { "file": "plugins/cordova-plugin-wkwebview-engine/src/www/ios/ios-wkwebview-exec.js", "id": "cordova-plugin-wkwebview-engine.ios-wkwebview-exec", @@ -33,8 +25,8 @@ module.exports = [ ] } ]; -module.exports.metadata = +module.exports.metadata = // TOP OF METADATA {} // BOTTOM OF METADATA -}); \ No newline at end of file +}); diff --git a/npm-packages/eslint-config-meteor/README.md b/npm-packages/eslint-config-meteor/README.md index 046c174268..1242bbbee6 100644 --- a/npm-packages/eslint-config-meteor/README.md +++ b/npm-packages/eslint-config-meteor/README.md @@ -24,7 +24,7 @@ The peer dependencies can be installed manually by following the `package.json` $ # Install `install-peerdeps` within the current Meteor tool version. $ meteor npm install --global install-peerdeps $ # Run the newly installed `install-peerdeps` to install this package and its dependencies. -$ meteor install-peerdeps --dev @meteorjs/eslint-config-meteor +$ meteor npx install-peerdeps --dev @meteorjs/eslint-config-meteor ``` ## Configure diff --git a/npm-packages/eslint-config-meteor/package.json b/npm-packages/eslint-config-meteor/package.json index 6b1d62defe..001b65df52 100644 --- a/npm-packages/eslint-config-meteor/package.json +++ b/npm-packages/eslint-config-meteor/package.json @@ -1,6 +1,6 @@ { "name": "@meteorjs/eslint-config-meteor", - "version": "1.0.4", + "version": "1.0.5", "description": "Eslint configuration for Meteor", "main": "index.js", "scripts": { @@ -16,6 +16,7 @@ "url": "https://github.com/meteor/meteor/issues" }, "homepage": "https://github.com/meteor/meteor/tree/devel/npm-packages/eslint-config-meteor#readme", + "type": "commonjs", "peerDependencies": { "babel-eslint": ">= 7", "eslint": ">= 3", diff --git a/npm-packages/eslint-plugin-meteor/README.md b/npm-packages/eslint-plugin-meteor/README.md index fd322c5f93..fff5044a51 100644 --- a/npm-packages/eslint-plugin-meteor/README.md +++ b/npm-packages/eslint-plugin-meteor/README.md @@ -56,7 +56,7 @@ meteor Building an application with Meteor? -* Deploy on Galaxy hosting: https://www.meteor.com/cloud +* Deploy on Galaxy hosting: https://galaxycloud.app/ * Announcement list: sign up at https://www.meteor.com/ * Discussion forums: https://forums.meteor.com/ * Join the Meteor community Slack by clicking this [invite link](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc). diff --git a/npm-packages/eslint-plugin-meteor/package.json b/npm-packages/eslint-plugin-meteor/package.json index 7845d884a3..8eb64bd0c1 100644 --- a/npm-packages/eslint-plugin-meteor/package.json +++ b/npm-packages/eslint-plugin-meteor/package.json @@ -1,9 +1,10 @@ { "name": "eslint-plugin-meteor", - "version": "7.4.0", + "version": "7.4.1", "author": "Dominik Ferber ", "description": "Meteor specific linting rules for ESLint", "main": "lib/index.js", + "type": "commonjs", "publishConfig": { "tag": "next" }, diff --git a/npm-packages/eslint-plugin-meteor/scripts/admin/launch-meteor b/npm-packages/eslint-plugin-meteor/scripts/admin/launch-meteor index 1ec76b4280..b749cc20ea 100755 --- a/npm-packages/eslint-plugin-meteor/scripts/admin/launch-meteor +++ b/npm-packages/eslint-plugin-meteor/scripts/admin/launch-meteor @@ -60,9 +60,11 @@ if [ ! -x "$METEOR_WAREHOUSE_DIR/meteor" ]; then PLATFORM="os.linux.x86_32" elif [ "${LINUX_ARCH}" = "x86_64" ] ; then PLATFORM="os.linux.x86_64" + elif [ "${LINUX_ARCH}" = "aarch64" ] ; then + PLATFORM="os.linux.aarch64" else echo "Unusable architecture: ${LINUX_ARCH}" - echo "Meteor only supports i686 and x86_64 for now." + echo "Meteor only supports i686, x86_64 and aarch64 for now." exit 1 fi fi diff --git a/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-all-platforms.sh b/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-all-platforms.sh index 2e96214eae..8d1cd11ba2 100755 --- a/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-all-platforms.sh +++ b/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-all-platforms.sh @@ -42,7 +42,7 @@ main () { echo # XXX there is no os.windows.x86_64 as we don't build for it at the moment - PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.windows.x86_32 ) + PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.windows.x86_32 os.linux.aarch64 ) for PLATFORM in ${PLATFORMS[@]}; do COMMAND="`dirname $0`/publish-meteor-tool-on-arch.sh $GITSHA $PLATFORM $SESSION_FILE" echo $COMMAND diff --git a/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-arch.sh b/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-arch.sh index 9041ac4035..795f43a140 100755 --- a/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-arch.sh +++ b/npm-packages/eslint-plugin-meteor/scripts/admin/publish-meteor-tool-on-arch.sh @@ -18,7 +18,7 @@ main () { echo "usage: $0 " 1>&2 echo "The passed sha1 is checked out and published from the machines." 1>&2 echo "Options for platform:" 1>&2 - echo " os.osx.x86_64 os.linux.x86_64 os.linux.x86_32" 1>&2 + echo " os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.linux.aarch64" 1>&2 echo " os.windows.x86_32 os.windows.x86_64" 1>&2 exit 1 fi @@ -33,7 +33,7 @@ main () { METEOR="$CHECKOUT_DIR/meteor" - UNIX_PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 ) + UNIX_PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.linux.aarch64 ) WINDOWS_PLATFORMS=( os.windows.x86_32 os.windows.x86_64 ) if [[ $PLATFORM =~ ^(os\.linux|os\.osx) ]] ; then diff --git a/npm-packages/eslint-plugin-meteor/scripts/build-dev-bundle-common.sh b/npm-packages/eslint-plugin-meteor/scripts/build-dev-bundle-common.sh index 941a01eabb..65d4c79cdc 100644 --- a/npm-packages/eslint-plugin-meteor/scripts/build-dev-bundle-common.sh +++ b/npm-packages/eslint-plugin-meteor/scripts/build-dev-bundle-common.sh @@ -5,10 +5,10 @@ set -u UNAME=$(uname) ARCH=$(uname -m) -NODE_VERSION=14.17.6 -MONGO_VERSION_64BIT=4.4.4 +NODE_VERSION=14.21.3 +MONGO_VERSION_64BIT=6.0.3 MONGO_VERSION_32BIT=3.2.22 -NPM_VERSION=6.14.15 +NPM_VERSION=6.14.18 if [ "$UNAME" == "Linux" ] ; then if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then diff --git a/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-server-package.js b/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-server-package.js index 677597f2e4..b29072cb17 100644 --- a/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-server-package.js +++ b/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-server-package.js @@ -8,25 +8,21 @@ var packageJson = { name: "meteor-dev-bundle", private: true, dependencies: { - // Keep the versions of these packages consistent with the versions - // found in dev-bundle-tool-package.js. - fibers: "https://github.com/meteor/node-fibers/archive/refs/tags/5.0.0.tar.gz", - "meteor-promise": "0.9.0", promise: "8.1.0", - "@meteorjs/reify": "0.24.0", - "@babel/parser": "7.15.3", - "@types/underscore": "1.11.2", - underscore: "1.13.1", + "@meteorjs/reify": "0.25.3", + "@babel/parser": "7.17.0", + "@types/underscore": "1.11.4", + underscore: "1.13.6", "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - "@types/semver": "5.4.0", - semver: "5.4.1" + "@types/semver": "5.5.0", + semver: "5.7.1" }, // These are only used in dev mode (by shell.js) so end-users can avoid // needing to install them if they use `npm install --production`. devDependencies: { split2: "3.2.2", - multipipe: "1.0.2", - chalk: "0.5.1" + multipipe: "2.0.1", + chalk: "4.1.2" } }; diff --git a/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-tool-package.js b/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-tool-package.js index c048959e0b..aedf49c8c0 100644 --- a/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-tool-package.js +++ b/npm-packages/eslint-plugin-meteor/scripts/dev-bundle-tool-package.js @@ -10,27 +10,23 @@ var packageJson = { dependencies: { // Explicit dependency because we are replacing it with a bundled version // and we want to make sure there are no dependencies on a higher version - npm: "6.14.15", + npm: "10.9.3", pacote: "https://github.com/meteor/pacote/tarball/a81b0324686e85d22c7688c47629d4009000e8b8", - "node-gyp": "8.0.0", - "node-pre-gyp": "0.15.0", - typescript: "4.9.4", - "@meteorjs/babel": "7.18.0-beta.6", - // Keep the versions of these packages consistent with the versions - // found in dev-bundle-server-package.js. - "meteor-promise": "0.9.0", - fibers: "https://github.com/meteor/node-fibers/archive/refs/tags/5.0.0.tar.gz", - "@meteorjs/reify": "0.24.0", + "node-gyp": "9.4.0", + "@mapbox/node-pre-gyp": "1.0.11", + typescript: "5.6.3", + "@meteorjs/babel": "7.20.0", + "@meteorjs/reify": "0.25.3", // So that Babel can emit require("@babel/runtime/helpers/...") calls. "@babel/runtime": "7.15.3", // For backwards compatibility with isopackets that still depend on // babel-runtime rather than @babel/runtime. "babel-runtime": "7.0.0-beta.3", "@types/underscore": "1.11.2", - underscore: "1.13.1", + underscore: "1.13.6", "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - "@types/semver": "5.4.0", - semver: "5.4.1", + "@types/semver": "5.5.0", + semver: "5.7.1", request: "2.88.2", uuid: "3.4.0", "graceful-fs": "4.2.6", @@ -41,8 +37,8 @@ var packageJson = { // TODO: We should replace this with: https://github.com/jprichardson/node-kexec/pull/38 kexec: "https://github.com/meteor/node-kexec/tarball/f29f54037c7db6ad29e1781463b182e5929215a0", "source-map": "0.7.3", - chalk: "4.1.1", - sqlite3: "5.0.2", + chalk: "4.1.2", + sqlite3: "5.1.6", "http-proxy": "1.18.1", "is-reachable": "3.1.0", "wordwrap": "1.0.0", diff --git a/npm-packages/meteor-babel/README.md b/npm-packages/meteor-babel/README.md index 1ba631d800..497f50a213 100644 --- a/npm-packages/meteor-babel/README.md +++ b/npm-packages/meteor-babel/README.md @@ -1,3 +1,9 @@ # @meteorjs/babel [![Build Status](https://travis-ci.com/meteor/babel.svg)](https://travis-ci.com/meteor/babel) [Babel](https://babeljs.io/) wrapper package for use with [Meteor](https://github.com/meteor/meteor). + +## Updating: + +If while updating this package the CI starts failing due inconsistencies +in the package-lock.json file, you can run `npm install --package-lock-only` +to update the package-lock.json file to the latest version of the package. diff --git a/npm-packages/meteor-babel/options.js b/npm-packages/meteor-babel/options.js index 4454148783..94252888e5 100644 --- a/npm-packages/meteor-babel/options.js +++ b/npm-packages/meteor-babel/options.js @@ -35,6 +35,10 @@ function getReifyOptions(features) { // wrap it with a function to rename the `module` identifier. reifyOptions.moduleAlias = "module"; } + + if (features.topLevelAwait) { + reifyOptions.topLevelAwait = true; + } } return reifyOptions; @@ -183,17 +187,15 @@ function getDefaultsForNode8(features) { require("@babel/plugin-proposal-object-rest-spread") ); - // Ensure that async functions run in a Fiber, while also taking - // full advantage of native async/await support in Node 8. - const isFiberDisabled = process.env.DISABLE_FIBERS === '1'; - const ignoreAsyncPlugin = process.env.IGNORE_ASYNC_PLUGIN === '1'; - - if (!ignoreAsyncPlugin) { - combined.plugins.push([require("./plugins/async-await.js"), { - // Do not transform `await x` to `Promise.await(x)`, since Node - // 8 has native support for await expressions. - useNativeAsyncAwait: isFiberDisabled, - }]); + if (features.useNativeAsyncAwait === false) { + combined.plugins.push([ + require('./plugins/async-await.js'), + { + // Even though Node 8 supports native async/await, it is not + // compatible with fibers. + useNativeAsyncAwait: false, + }, + ]); } // Enable async generator functions proposal. combined.plugins.push(require("@babel/plugin-proposal-async-generator-functions")); diff --git a/npm-packages/meteor-babel/package-lock.json b/npm-packages/meteor-babel/package-lock.json index 18e8305a96..3ded2f7c42 100644 --- a/npm-packages/meteor-babel/package-lock.json +++ b/npm-packages/meteor-babel/package-lock.json @@ -1,4347 +1,314 @@ { "name": "@meteorjs/babel", - "version": "7.18.0-beta.6", - "lockfileVersion": 2, + "version": "7.20.1", + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "@meteorjs/babel", - "version": "7.18.0-beta.6", - "license": "MIT", - "dependencies": { - "@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.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", - "typescript": "~4.9.4" - }, - "devDependencies": { - "@babel/plugin-proposal-decorators": "7.14.5", - "@babel/plugin-syntax-decorators": "7.14.5", - "d3": "4.13.0", - "fibers": "5.0.0", - "meteor-promise": "0.9.0", - "mocha": "6.2.3", - "promise": "8.1.0", - "source-map": "0.6.1" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz", - "integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@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==", - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.9.tgz", - "integrity": "sha512-p3QjZmMGHDGdpcwEYYWu7i7oJShJvtgMjJeb0W95PPhSm++3lm8YXYOh45Y6iCN9PkZLTZ7CIX5nFrp7pw7TXw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/@babel/compat-data": { - "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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/core/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/@babel/core/node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/@babel/core/node_modules/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_modules/@babel/core/node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" - }, - "node_modules/@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", - "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", - "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", - "dependencies": { - "@babel/compat-data": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "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, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-member-expression-to-functions": "^7.14.7", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "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==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@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", - "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", - "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", - "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-wrap-function": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", - "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", - "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", - "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", - "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", - "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "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==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.14.5.tgz", - "integrity": "sha512-LYz5nvQcvYeRVjui1Ykn28i+3aUiXwQ/3MGoEy0InTaz1pJo/lAzmIDXX+BQny/oufgHzJ6vnEEiXQ8KZjEVFg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-decorators": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", - "dependencies": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz", - "integrity": "sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", - "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", - "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", - "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", - "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "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==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "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==", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "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==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "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==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/preset-react/node_modules/@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==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@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==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@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==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@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==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@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==" - }, - "node_modules/@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==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@meteorjs/reify": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@meteorjs/reify/-/reify-0.23.0.tgz", - "integrity": "sha512-sHQCbZHoM+PxT+pWvkJDsaOpJP+tMQ31Mr2t1T0YcXl18eScb0bQNafe8TugNCc4pngByppfscVX4ppr84MzDw==", - "dependencies": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", - "magic-string": "^0.25.3", - "periscopic": "^2.0.3", - "semver": "^5.7.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@meteorjs/reify/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==" - }, - "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "deprecated": "This is probably built in to whatever tool you're using. If you still need it... idk", - "peerDependencies": { - "acorn": "^6.0.0" - } - }, - "node_modules/ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "node_modules/babel-helper-evaluate-path": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", - "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==" - }, - "node_modules/babel-helper-flip-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=" - }, - "node_modules/babel-helper-is-nodes-equiv": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=" - }, - "node_modules/babel-helper-is-void-0": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=" - }, - "node_modules/babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=" - }, - "node_modules/babel-helper-remove-or-void": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=" - }, - "node_modules/babel-helper-to-multiple-sequence-expressions": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", - "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==" - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-minify-builtins": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", - "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==" - }, - "node_modules/babel-plugin-minify-constant-folding": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", - "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", - "dependencies": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "node_modules/babel-plugin-minify-dead-code-elimination": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", - "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", - "dependencies": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-mark-eval-scopes": "^0.4.3", - "babel-helper-remove-or-void": "^0.4.3", - "lodash": "^4.17.11" - } - }, - "node_modules/babel-plugin-minify-flip-comparisons": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", - "dependencies": { - "babel-helper-is-void-0": "^0.4.3" - } - }, - "node_modules/babel-plugin-minify-guarded-expressions": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", - "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", - "dependencies": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-flip-expressions": "^0.4.3" - } - }, - "node_modules/babel-plugin-minify-infinity": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=" - }, - "node_modules/babel-plugin-minify-mangle-names": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", - "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", - "dependencies": { - "babel-helper-mark-eval-scopes": "^0.4.3" - } - }, - "node_modules/babel-plugin-minify-numeric-literals": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=" - }, - "node_modules/babel-plugin-minify-replace": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", - "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==" - }, - "node_modules/babel-plugin-minify-simplify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", - "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", - "dependencies": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-flip-expressions": "^0.4.3", - "babel-helper-is-nodes-equiv": "^0.0.1", - "babel-helper-to-multiple-sequence-expressions": "^0.5.0" - } - }, - "node_modules/babel-plugin-minify-type-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", - "dependencies": { - "babel-helper-is-void-0": "^0.4.3" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "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==", - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "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==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "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==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-transform-inline-consecutive-adds": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=" - }, - "node_modules/babel-plugin-transform-member-expression-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=" - }, - "node_modules/babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", - "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=" - }, - "node_modules/babel-plugin-transform-minify-booleans": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=" - }, - "node_modules/babel-plugin-transform-property-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", - "dependencies": { - "esutils": "^2.0.2" - } - }, - "node_modules/babel-plugin-transform-regexp-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=" - }, - "node_modules/babel-plugin-transform-remove-console": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=" - }, - "node_modules/babel-plugin-transform-remove-debugger": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=" - }, - "node_modules/babel-plugin-transform-remove-undefined": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", - "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", - "dependencies": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "node_modules/babel-plugin-transform-simplify-comparison-operators": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=" - }, - "node_modules/babel-plugin-transform-undefined-to-void": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=" - }, - "node_modules/babel-preset-meteor": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.10.0.tgz", - "integrity": "sha512-bcdNfRCQAjTV42cUcmaG5/ltLZZQLpZajUcP+o0Lr+aLTY/XLNkGfASM5383wdXiAkEFl0sDOXeknnLlQtrmdg==", - "dependencies": { - "@babel/plugin-proposal-async-generator-functions": "^7.13.15", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", - "@babel/plugin-proposal-optional-chaining": "^7.13.12", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.13.0", - "@babel/plugin-transform-async-to-generator": "^7.13.0", - "@babel/plugin-transform-block-scoped-functions": "^7.12.13", - "@babel/plugin-transform-block-scoping": "^7.13.16", - "@babel/plugin-transform-classes": "^7.13.0", - "@babel/plugin-transform-computed-properties": "^7.13.0", - "@babel/plugin-transform-destructuring": "^7.13.17", - "@babel/plugin-transform-exponentiation-operator": "^7.12.13", - "@babel/plugin-transform-for-of": "^7.13.0", - "@babel/plugin-transform-literals": "^7.12.13", - "@babel/plugin-transform-object-super": "^7.12.13", - "@babel/plugin-transform-parameters": "^7.13.0", - "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.13.15", - "@babel/plugin-transform-shorthand-properties": "^7.12.13", - "@babel/plugin-transform-spread": "^7.13.0", - "@babel/plugin-transform-sticky-regex": "^7.12.13", - "@babel/plugin-transform-template-literals": "^7.13.0", - "@babel/plugin-transform-typeof-symbol": "^7.12.13", - "@babel/plugin-transform-unicode-regex": "^7.12.13" - } - }, - "node_modules/babel-preset-minify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", - "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", - "dependencies": { - "babel-plugin-minify-builtins": "^0.5.0", - "babel-plugin-minify-constant-folding": "^0.5.0", - "babel-plugin-minify-dead-code-elimination": "^0.5.1", - "babel-plugin-minify-flip-comparisons": "^0.4.3", - "babel-plugin-minify-guarded-expressions": "^0.4.4", - "babel-plugin-minify-infinity": "^0.4.3", - "babel-plugin-minify-mangle-names": "^0.5.0", - "babel-plugin-minify-numeric-literals": "^0.4.3", - "babel-plugin-minify-replace": "^0.5.0", - "babel-plugin-minify-simplify": "^0.5.1", - "babel-plugin-minify-type-constructors": "^0.4.3", - "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", - "babel-plugin-transform-member-expression-literals": "^6.9.4", - "babel-plugin-transform-merge-sibling-variables": "^6.9.4", - "babel-plugin-transform-minify-booleans": "^6.9.4", - "babel-plugin-transform-property-literals": "^6.9.4", - "babel-plugin-transform-regexp-constructors": "^0.4.3", - "babel-plugin-transform-remove-console": "^6.9.4", - "babel-plugin-transform-remove-debugger": "^6.9.4", - "babel-plugin-transform-remove-undefined": "^0.5.0", - "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", - "babel-plugin-transform-undefined-to-void": "^6.9.4", - "lodash": "^4.17.11" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", - "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001248", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz", - "integrity": "sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/core-js-compat/node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/core-js-compat/node_modules/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_modules/core-js-compat/node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "dev": true, - "dependencies": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" - } - }, - "node_modules/d3-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==", - "dev": true - }, - "node_modules/d3-axis": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", - "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=", - "dev": true - }, - "node_modules/d3-brush": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", - "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", - "dev": true, - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "node_modules/d3-chord": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", - "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", - "dev": true, - "dependencies": { - "d3-array": "1", - "d3-path": "1" - } - }, - "node_modules/d3-collection": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", - "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", - "dev": true - }, - "node_modules/d3-color": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", - "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=", - "dev": true - }, - "node_modules/d3-dispatch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", - "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=", - "dev": true - }, - "node_modules/d3-drag": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", - "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", - "dev": true, - "dependencies": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "node_modules/d3-dsv": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", - "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", - "dev": true, - "dependencies": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json", - "csv2tsv": "bin/dsv2dsv", - "dsv2dsv": "bin/dsv2dsv", - "dsv2json": "bin/dsv2json", - "json2csv": "bin/json2dsv", - "json2dsv": "bin/json2dsv", - "json2tsv": "bin/json2dsv", - "tsv2csv": "bin/dsv2dsv", - "tsv2json": "bin/dsv2json" - } - }, - "node_modules/d3-ease": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", - "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=", - "dev": true - }, - "node_modules/d3-force": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", - "dev": true, - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "node_modules/d3-format": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==", - "dev": true - }, - "node_modules/d3-geo": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", - "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", - "dev": true, - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/d3-hierarchy": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", - "integrity": "sha1-ochFxC+Eoga88cAcAQmOpN2qeiY=", - "dev": true - }, - "node_modules/d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", - "dev": true, - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/d3-path": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", - "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=", - "dev": true - }, - "node_modules/d3-polygon": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", - "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=", - "dev": true - }, - "node_modules/d3-quadtree": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", - "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", - "dev": true - }, - "node_modules/d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=", - "dev": true - }, - "node_modules/d3-random": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=", - "dev": true - }, - "node_modules/d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", - "dev": true, - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" - } - }, - "node_modules/d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", - "dev": true, - "dependencies": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-color": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "node_modules/d3-selection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", - "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==", - "dev": true - }, - "node_modules/d3-shape": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", - "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", - "dev": true, - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/d3-time": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==", - "dev": true - }, - "node_modules/d3-time-format": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", - "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", - "dev": true, - "dependencies": { - "d3-time": "1" - } - }, - "node_modules/d3-timer": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", - "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==", - "dev": true - }, - "node_modules/d3-transition": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", - "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", - "dev": true, - "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "node_modules/d3-voronoi": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=", - "dev": true - }, - "node_modules/d3-zoom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", - "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", - "dev": true, - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.793", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.793.tgz", - "integrity": "sha512-l9NrGV6Mr4ov5mayYPvIWcwklNw5ROmy6rllzz9dCACw9nKE5y+s5uQk+CBJMetxrWZ6QJFsvEfG6WDcH2IGUg==" - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fibers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.0.tgz", - "integrity": "sha512-UpGv/YAZp7mhKHxDvC1tColrroGRX90sSvh8RMZV9leo+e5+EkRVgCEZPlmXeo3BUNQTZxUaVdLskq1Q2FyCPg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/flat": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", - "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", - "dev": true, - "dependencies": { - "is-buffer": "~2.0.3" - }, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "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==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "node_modules/log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "dependencies": { - "chalk": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/meteor-babel-helpers": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/meteor-babel-helpers/-/meteor-babel-helpers-0.0.3.tgz", - "integrity": "sha1-8uXZ+HlvvS6JAQI9dpnlsgLqn7A=" - }, - "node_modules/meteor-promise": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-0.9.0.tgz", - "integrity": "sha512-O1Fj1Oa5FfyIkAkDtZVnoYYEIC3miy7lvEeIQZVYunGSbOuivSbfAiPPsD+P45WNlcBALhUo94UzlHeIKBYNuQ==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", - "dev": true, - "dependencies": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "node_modules/mocha/node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "node_modules/node-environment-flags/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/periscopic": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.3.tgz", - "integrity": "sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==", - "dependencies": { - "estree-walker": "^2.0.2", - "is-reference": "^1.1.4" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "dependencies": { - "regenerate": "^1.4.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "dependencies": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "node_modules/regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/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==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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=", - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "dependencies": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - } - }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz", - "integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, "@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==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" } }, "@babel/compat-data": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.9.tgz", - "integrity": "sha512-p3QjZmMGHDGdpcwEYYWu7i7oJShJvtgMjJeb0W95PPhSm++3lm8YXYOh45Y6iCN9PkZLTZ7CIX5nFrp7pw7TXw==" + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==" }, "@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "requires": { - "@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", + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "dependencies": { - "@babel/compat-data": { - "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.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.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - } - }, - "@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==" + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" } } }, "@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" } }, "@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.22.5" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", - "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/types": "^7.22.15" } }, "@babel/helper-compilation-targets": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", - "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "requires": { - "@babel/compat-data": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" } }, "@babel/helper-create-class-features-plugin": { - "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, + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-member-expression-to-functions": "^7.14.7", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" } }, "@babel/helper-define-polyfill-provider": { - "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==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.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", - "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", - "requires": { - "@babel/types": "^7.14.5" - } + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "requires": { - "@babel/types": "^7.14.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "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==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", - "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.23.0" } }, "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.24.0" } }, "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "requires": { - "@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-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-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/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" } }, "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.22.5" } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", - "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-wrap-function": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" } }, "@babel/helper-replace-supers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", - "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "requires": { - "@babel/helper-member-expression-to-functions": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" } }, "@babel/helper-simple-access": { - "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==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", - "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.22.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" + }, "@babel/helper-validator-identifier": { - "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==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@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.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==" }, "@babel/helper-wrap-function": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", - "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "requires": { - "@babel/helper-function-name": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" } }, "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" } }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" } }, "@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==" }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", - "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "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==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "requires": { - "@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/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-decorators": { @@ -4356,51 +323,51 @@ } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", "requires": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" + "@babel/plugin-transform-parameters": "^7.20.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, @@ -4438,18 +405,11 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "requires": { - "@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/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -4493,330 +453,259 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", - "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-classes": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", - "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" } }, "@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-for-of": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", - "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" } }, "@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-modules-commonjs": { - "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==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "requires": { - "@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/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" } }, "@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" } }, "@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-react-display-name": { - "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==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", "requires": { - "@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/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-react-jsx": { - "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==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", "requires": { - "@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/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" } }, "@babel/plugin-transform-react-jsx-development": { - "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==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.7" + "@babel/plugin-transform-react-jsx": "^7.22.5" } }, "@babel/plugin-transform-react-pure-annotations": { - "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==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", + "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", "requires": { - "@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/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", "requires": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" } }, "@babel/plugin-transform-runtime": { - "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==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", + "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", "requires": { - "@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/helper-module-imports": "^7.24.3", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" } }, "@babel/preset-react": { - "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==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", + "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", "requires": { - "@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/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-react-display-name": "^7.24.1", + "@babel/plugin-transform-react-jsx": "^7.23.4", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.24.1" } }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, "@babel/runtime": { "version": "7.17.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", @@ -4826,122 +715,103 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" } }, "@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "requires": { - "@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", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", "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.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "@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==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@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==" + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@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==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@meteorjs/reify": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@meteorjs/reify/-/reify-0.23.0.tgz", - "integrity": "sha512-sHQCbZHoM+PxT+pWvkJDsaOpJP+tMQ31Mr2t1T0YcXl18eScb0bQNafe8TugNCc4pngByppfscVX4ppr84MzDw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@meteorjs/reify/-/reify-0.25.4.tgz", + "integrity": "sha512-/HwynJK85QtS2Rm26M9TS8aEMnqVJ2TIzJNJTGAQz+G6cTYmJGWaU4nFH96oxiDIBbnT6Y3TfX92HDuS9TtNRg==", "requires": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", + "acorn": "^8.8.1", "magic-string": "^0.25.3", "periscopic": "^2.0.3", - "semver": "^5.7.1" + "semver": "^7.5.4" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" } } }, "@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": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "requires": {} + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==" }, "ansi-colors": { "version": "3.2.3", @@ -4950,9 +820,9 @@ "dev": true }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", "dev": true }, "ansi-styles": { @@ -4972,12 +842,62 @@ "sprintf-js": "~1.0.2" } }, + "array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + } + }, + "array.prototype.reduce": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz", + "integrity": "sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-array-method-boxes-properly": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + } + }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "requires": { + "possible-typed-array-names": "^1.0.0" + } + }, "babel-helper-evaluate-path": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", @@ -4986,41 +906,33 @@ "babel-helper-flip-expressions": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=" + "integrity": "sha512-rSrkRW4YQ2ETCWww9gbsWk4N0x1BOtln349Tk0dlCS90oT68WMLyGR7WvaMp3eAnsVrCqdUtC19lo1avyGPejA==" }, "babel-helper-is-nodes-equiv": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=" + "integrity": "sha512-ri/nsMFVRqXn7IyT5qW4/hIAGQxuYUFHa3qsxmPtbk6spZQcYlyDogfVpNm2XYOslH/ULS4VEJGUqQX5u7ACQw==" }, "babel-helper-is-void-0": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=" + "integrity": "sha512-07rBV0xPRM3TM5NVJEOQEkECX3qnHDjaIbFvWYPv+T1ajpUiVLiqTfC+MmiZxY5KOL/Ec08vJdJD9kZiP9UkUg==" }, "babel-helper-mark-eval-scopes": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=" + "integrity": "sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA==" }, "babel-helper-remove-or-void": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=" + "integrity": "sha512-eYNceYtcGKpifHDir62gHJadVXdg9fAhuZEXiRQnJJ4Yi4oUTpqpNY//1pM4nVyjjDMPYaC2xSf0I+9IqVzwdA==" }, "babel-helper-to-multiple-sequence-expressions": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==" }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-minify-builtins": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", @@ -5035,9 +947,9 @@ } }, "babel-plugin-minify-dead-code-elimination": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", - "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.2.tgz", + "integrity": "sha512-krq9Lwi0QIzyAlcNBXTL4usqUvevB4BzktdEsb8srcXC1AaYqRJiAQw6vdKdJSaXbz6snBvziGr6ch/aoRCfpA==", "requires": { "babel-helper-evaluate-path": "^0.5.0", "babel-helper-mark-eval-scopes": "^0.4.3", @@ -5048,7 +960,7 @@ "babel-plugin-minify-flip-comparisons": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "integrity": "sha512-8hNwgLVeJzpeLVOVArag2DfTkbKodzOHU7+gAZ8mGBFGPQHK6uXVpg3jh5I/F6gfi5Q5usWU2OKcstn1YbAV7A==", "requires": { "babel-helper-is-void-0": "^0.4.3" } @@ -5065,12 +977,12 @@ "babel-plugin-minify-infinity": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=" + "integrity": "sha512-X0ictxCk8y+NvIf+bZ1HJPbVZKMlPku3lgYxPmIp62Dp8wdtbMLSekczty3MzvUOlrk5xzWYpBpQprXUjDRyMA==" }, "babel-plugin-minify-mangle-names": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", - "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz", + "integrity": "sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw==", "requires": { "babel-helper-mark-eval-scopes": "^0.4.3" } @@ -5078,7 +990,7 @@ "babel-plugin-minify-numeric-literals": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=" + "integrity": "sha512-5D54hvs9YVuCknfWywq0eaYDt7qYxlNwCqW9Ipm/kYeS9gYhJd0Rr/Pm2WhHKJ8DC6aIlDdqSBODSthabLSX3A==" }, "babel-plugin-minify-replace": { "version": "0.5.0", @@ -5099,62 +1011,62 @@ "babel-plugin-minify-type-constructors": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "integrity": "sha512-4ADB0irJ/6BeXWHubjCJmrPbzhxDgjphBMjIjxCc25n4NGJ00NsYqwYt+F/OvE9RXx8KaSW7cJvp+iZX436tnQ==", "requires": { "babel-helper-is-void-0": "^0.4.3" } }, "babel-plugin-polyfill-corejs2": { - "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==", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" } }, "babel-plugin-polyfill-corejs3": { - "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==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" } }, "babel-plugin-polyfill-regenerator": { - "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==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", + "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.6.1" } }, "babel-plugin-transform-inline-consecutive-adds": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=" + "integrity": "sha512-8D104wbzzI5RlxeVPYeQb9QsUyepiH1rAO5hpPpQ6NPRgQLpIVwkS/Nbx944pm4K8Z+rx7CgjPsFACz/VCBN0Q==" }, "babel-plugin-transform-member-expression-literals": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=" + "integrity": "sha512-Xq9/Rarpj+bjOZSl1nBbZYETsNEDDJSrb6Plb1sS3/36FukWFLLRysgecva5KZECjUJTrJoQqjJgtWToaflk5Q==" }, "babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", - "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=" + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.5.tgz", + "integrity": "sha512-xj/KrWi6/uP+DrD844h66Qh2cZN++iugEIgH8QcIxhmZZPNP6VpOE9b4gP2FFW39xDAY43kCmYMM6U0QNKN8fw==" }, "babel-plugin-transform-minify-booleans": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=" + "integrity": "sha512-9pW9ePng6DZpzGPalcrULuhSCcauGAbn8AeU3bE34HcDkGm8Ldt0ysjGkyb64f0K3T5ilV4mriayOVv5fg0ASA==" }, "babel-plugin-transform-property-literals": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "integrity": "sha512-Pf8JHTjTPxecqVyL6KSwD/hxGpoTZjiEgV7nCx0KFQsJYM0nuuoCajbg09KRmZWeZbJ5NGTySABYv8b/hY1eEA==", "requires": { "esutils": "^2.0.2" } @@ -5162,17 +1074,17 @@ "babel-plugin-transform-regexp-constructors": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=" + "integrity": "sha512-JjymDyEyRNhAoNFp09y/xGwYVYzT2nWTGrBrWaL6eCg2m+B24qH2jR0AA8V8GzKJTgC8NW6joJmc6nabvWBD/g==" }, "babel-plugin-transform-remove-console": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=" + "integrity": "sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg==" }, "babel-plugin-transform-remove-debugger": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=" + "integrity": "sha512-Kd+eTBYlXfwoFzisburVwrngsrz4xh9I0ppoJnU/qlLysxVBRgI4Pj+dk3X8F5tDiehp3hhP8oarRMT9v2Z3lw==" }, "babel-plugin-transform-remove-undefined": { "version": "0.5.0", @@ -5185,17 +1097,17 @@ "babel-plugin-transform-simplify-comparison-operators": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=" + "integrity": "sha512-GLInxhGAQWJ9YIdjwF6dAFlmh4U+kN8pL6Big7nkDzHoZcaDQOtBm28atEhQJq6m9GpAovbiGEShKqXv4BSp0A==" }, "babel-plugin-transform-undefined-to-void": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=" + "integrity": "sha512-D2UbwxawEY1xVc9svYAUZQM2xarwSNXue2qDIx6CeV2EuMGaes/0su78zlIDIAgE7BvnMw4UpmSo9fDy+znghg==" }, "babel-preset-meteor": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.10.0.tgz", - "integrity": "sha512-bcdNfRCQAjTV42cUcmaG5/ltLZZQLpZajUcP+o0Lr+aLTY/XLNkGfASM5383wdXiAkEFl0sDOXeknnLlQtrmdg==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.10.1.tgz", + "integrity": "sha512-izJeOKYW69dPwWDDBRdnJ1/sMQ9626CVVZQHqtvrjJtZJ9FHUTknrQ9+RMgYL13R6RfkFWF9Bw5J/2K+DdYGpw==", "requires": { "@babel/plugin-proposal-async-generator-functions": "^7.13.15", "@babel/plugin-proposal-class-properties": "^7.13.0", @@ -5233,24 +1145,24 @@ } }, "babel-preset-minify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", - "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.2.tgz", + "integrity": "sha512-v4GL+kk0TfovbRIKZnC3HPbu2cAGmPAby7BsOmuPdMJfHV+4FVdsGXTH/OOGQRKYdjemBuL1+MsE6mobobhe9w==", "requires": { "babel-plugin-minify-builtins": "^0.5.0", "babel-plugin-minify-constant-folding": "^0.5.0", - "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-dead-code-elimination": "^0.5.2", "babel-plugin-minify-flip-comparisons": "^0.4.3", "babel-plugin-minify-guarded-expressions": "^0.4.4", "babel-plugin-minify-infinity": "^0.4.3", - "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-mangle-names": "^0.5.1", "babel-plugin-minify-numeric-literals": "^0.4.3", "babel-plugin-minify-replace": "^0.5.0", "babel-plugin-minify-simplify": "^0.5.1", "babel-plugin-minify-type-constructors": "^0.4.3", "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", "babel-plugin-transform-member-expression-literals": "^6.9.4", - "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.5", "babel-plugin-transform-minify-booleans": "^6.9.4", "babel-plugin-transform-property-literals": "^6.9.4", "babel-plugin-transform-regexp-constructors": "^0.4.3", @@ -5285,24 +1197,27 @@ "dev": true }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" } }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "camelcase": { @@ -5312,9 +1227,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001248", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz", - "integrity": "sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw==" + "version": "1.0.30001608", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001608.tgz", + "integrity": "sha512-cjUJTQkk9fQlJR2s4HMuPMvTiRggl0rAVMtthQuyOlDWuqHXqN8azLq+pi8B2TjwKJ32diHjUqRIKeFX4z1FoA==" }, "chalk": { "version": "2.4.2", @@ -5338,9 +1253,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "string-width": { @@ -5376,12 +1291,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "commander": { "version": "2.20.3", @@ -5392,58 +1302,20 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "core-js-compat": { - "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==", + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "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==" - }, - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } + "browserslist": "^4.23.0" } }, "d3": { @@ -5493,13 +1365,13 @@ "d3-axis": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", - "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=", + "integrity": "sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==", "dev": true }, "d3-brush": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", - "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", + "integrity": "sha512-nUFueDzOlvwFvuOBynGSyJM7Wt1H9fKgJeoWFSg3ScS4c7FJBch92FKUJKum4xtgPYHdgH2C3bRg3GzSVltCJQ==", "dev": true, "requires": { "d3-dispatch": "1", @@ -5512,7 +1384,7 @@ "d3-chord": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", - "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", + "integrity": "sha512-o0ExexkK1N0KikUakKrQwttP5Flu8AYD6iBUh3AdPJqnTh6xlvcX5wFRuuo29sLOAr9+T4yZPUH1S3CCQJ1SlQ==", "dev": true, "requires": { "d3-array": "1", @@ -5522,19 +1394,19 @@ "d3-collection": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", - "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", + "integrity": "sha512-+TPxaBFzbzfpLF3Hjz8JPeuStNmJnyWAufu8VUfpDCDn5RieIgY+OQDjhKMDorf2naLgAjjZXLUQN7XFp/kgog==", "dev": true }, "d3-color": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", - "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=", + "integrity": "sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==", "dev": true }, "d3-dispatch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", - "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=", + "integrity": "sha512-Qh2DR3neW3lq/ug4oymXHYoIsA91nYt47ERb+fPKjRg6zLij06aP7KqHHl2NyziK9ASxrR3GLkHCtZvXe/jMVg==", "dev": true }, "d3-drag": { @@ -5561,7 +1433,7 @@ "d3-ease": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", - "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=", + "integrity": "sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==", "dev": true }, "d3-force": { @@ -5594,7 +1466,7 @@ "d3-hierarchy": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", - "integrity": "sha1-ochFxC+Eoga88cAcAQmOpN2qeiY=", + "integrity": "sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==", "dev": true }, "d3-interpolate": { @@ -5609,31 +1481,31 @@ "d3-path": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", - "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=", + "integrity": "sha512-eD76prgnTKYkLzHlY2UMyOEZXTpC+WOanCr1BLxo38w4fPPPq/LgCFqRQvqFU3AJngfZmmKR7rgKPZ4EGJ9Atw==", "dev": true }, "d3-polygon": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", - "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=", + "integrity": "sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==", "dev": true }, "d3-quadtree": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", - "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", + "integrity": "sha512-U2Jc3jF3JOBGXIOnvWY9C4ekRwRX9hEVpMMmeduJyaxAwPmoe7t84iZFTLn1RwYOyrXxJF55H/Hrg186TFQQdw==", "dev": true }, "d3-queue": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=", + "integrity": "sha512-2rs+6pNFKkrJhqe1rg5znw7dKJ7KZr62j9aLZfhondkrnz6U7VRmJj1UGcbD8MRc46c7H8m4SWhab8EalBQrkw==", "dev": true }, "d3-random": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=", + "integrity": "sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==", "dev": true }, "d3-request": { @@ -5672,7 +1544,7 @@ "d3-shape": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", - "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", + "integrity": "sha512-LP48zJ9ykPKjCdd0vSu5k2l4s8v1vI6vvdDeJtmgtTa+L6Ery0lzvOaV7pMunFuLv11hwSRZQnSnlhFl801aiw==", "dev": true, "requires": { "d3-path": "1" @@ -5716,7 +1588,7 @@ "d3-voronoi": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=", + "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==", "dev": true }, "d3-zoom": { @@ -5732,10 +1604,43 @@ "d3-transition": "1" } }, + "data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -5743,21 +1648,35 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "requires": { - "object-keys": "^1.0.12" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true }, "diff": { @@ -5767,9 +1686,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.793", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.793.tgz", - "integrity": "sha512-l9NrGV6Mr4ov5mayYPvIWcwklNw5ROmy6rllzz9dCACw9nKE5y+s5uQk+CBJMetxrWZ6QJFsvEfG6WDcH2IGUg==" + "version": "1.4.733", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz", + "integrity": "sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==" }, "emoji-regex": { "version": "7.0.3", @@ -5778,28 +1697,112 @@ "dev": true }, "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "requires": { - "call-bind": "^1.0.2", + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "dependencies": { + "object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + } + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, + "es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" } }, "es-to-primitive": { @@ -5814,14 +1817,14 @@ } }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "esprima": { "version": "4.0.1", @@ -5866,16 +1869,43 @@ "is-buffer": "~2.0.3" } }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true }, "gensync": { "version": "1.0.0-beta.2", @@ -5889,13 +1919,27 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" } }, "glob": { @@ -5917,35 +1961,78 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true }, "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } }, "he": { "version": "1.2.0", @@ -5965,7 +2052,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -5979,29 +2066,43 @@ "dev": true }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" } }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true - }, - "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "requires": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, "is-buffer": { @@ -6011,42 +2112,57 @@ "dev": true }, "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "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==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" + } + }, + "is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "requires": { + "is-typed-array": "^1.1.13" } }, "is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true }, "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true }, "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-reference": { "version": "1.2.1", @@ -6057,20 +2173,32 @@ } }, "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7" } }, "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-symbol": { "version": "1.0.4", @@ -6081,10 +2209,34 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.14" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "js-tokens": { @@ -6108,12 +2260,9 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "locate-path": { "version": "3.0.0", @@ -6133,7 +2282,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "log-symbols": { "version": "2.2.0", @@ -6144,24 +2293,26 @@ "chalk": "^2.0.1" } }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "sourcemap-codec": "^1.4.4" + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" } }, "meteor-babel-helpers": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/meteor-babel-helpers/-/meteor-babel-helpers-0.0.3.tgz", - "integrity": "sha1-8uXZ+HlvvS6JAQI9dpnlsgLqn7A=" - }, - "meteor-promise": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-0.9.0.tgz", - "integrity": "sha512-O1Fj1Oa5FfyIkAkDtZVnoYYEIC3miy7lvEeIQZVYunGSbOuivSbfAiPPsD+P45WNlcBALhUo94UzlHeIKBYNuQ==", - "dev": true + "integrity": "sha512-PgfmiyT/HiBaxwGHxS4t3Qi0fpmEW3O0WW2VfrgekiMGz3aZPd9/4PRIaMMZsfyjQ1vyEm6dZqTAFZENbuoTxw==" }, "minimatch": { "version": "3.0.4", @@ -6173,9 +2324,10 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true }, "mkdirp": { "version": "0.5.4", @@ -6232,18 +2384,6 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", @@ -6271,55 +2411,61 @@ }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true } } }, "node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz", + "integrity": "sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "gopd": "^1.0.1", + "safe-array-concat": "^1.1.2" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -6352,13 +2498,13 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-parse": { @@ -6380,6 +2526,12 @@ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, + "possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true + }, "promise": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", @@ -6395,48 +2547,55 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "requires": { "@babel/runtime": "^7.8.4" } }, - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" } }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } }, "regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -6444,14 +2603,14 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" } } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "require-main-filename": { @@ -6461,11 +2620,11 @@ "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -6473,13 +2632,31 @@ "rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", "dev": true }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + } }, "safer-buffer": { "version": "2.1.2", @@ -6488,25 +2665,52 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "source-map": { @@ -6523,7 +2727,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "string-width": { @@ -6536,30 +2740,44 @@ "strip-ansi": "^4.0.0" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -6568,7 +2786,7 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true }, "supports-color": { @@ -6587,48 +2805,109 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + } + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==" + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } }, "which": { "version": "1.3.1", @@ -6653,11 +2932,24 @@ } }, "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, + "which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -6679,9 +2971,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "string-width": { @@ -6709,13 +3001,13 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "xmlhttprequest": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", "dev": true }, "y18n": { @@ -6724,6 +3016,11 @@ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "yargs": { "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", @@ -6743,9 +3040,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "string-width": { diff --git a/npm-packages/meteor-babel/package.json b/npm-packages/meteor-babel/package.json index c52337d855..24771f96c0 100644 --- a/npm-packages/meteor-babel/package.json +++ b/npm-packages/meteor-babel/package.json @@ -1,8 +1,9 @@ { "name": "@meteorjs/babel", "author": "Meteor ", - "version": "7.18.0-beta.6", + "version": "7.20.1", "license": "MIT", + "type": "commonjs", "description": "Babel wrapper package for use with Meteor", "keywords": [ "meteor", @@ -41,22 +42,24 @@ "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.0", "@babel/types": "^7.17.0", - "@meteorjs/reify": "0.23.0", + "@meteorjs/reify": "0.25.4", "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", - "typescript": "~4.9.4" + "typescript": "~5.4.5" }, "devDependencies": { "@babel/plugin-proposal-decorators": "7.14.5", "@babel/plugin-syntax-decorators": "7.14.5", "d3": "4.13.0", "fibers": "5.0.0", - "meteor-promise": "0.9.0", "mocha": "6.2.3", "promise": "8.1.0", "source-map": "0.6.1" + }, + "volta": { + "node": "14.21.3" } } diff --git a/npm-packages/meteor-babel/plugins/async-await.js b/npm-packages/meteor-babel/plugins/async-await.js index 9110ae383a..c0f5490360 100644 --- a/npm-packages/meteor-babel/plugins/async-await.js +++ b/npm-packages/meteor-babel/plugins/async-await.js @@ -8,6 +8,10 @@ module.exports = function (babel) { visitor: { Function: { exit: function (path) { + if (this.opts.useNativeAsyncAwait !== false) { + return; + } + const node = path.node; if (!node.async) { return; @@ -27,7 +31,7 @@ module.exports = function (babel) { node.body, // The inner function called by Promise.asyncApply should be // async if we have native async/await support. - !! this.opts.useNativeAsyncAwait + !!this.opts.useNativeAsyncAwait ); const promiseResultExpression = t.callExpression( @@ -53,7 +57,7 @@ module.exports = function (babel) { }, AwaitExpression: function (path) { - if (this.opts.useNativeAsyncAwait) { + if (this.opts.useNativeAsyncAwait !== false) { // No need to transform await expressions if we have native // support for them. return; diff --git a/npm-packages/meteor-babel/runtime.js b/npm-packages/meteor-babel/runtime.js index c7fe580b3f..73c1a164f4 100644 --- a/npm-packages/meteor-babel/runtime.js +++ b/npm-packages/meteor-babel/runtime.js @@ -11,21 +11,3 @@ Module.prototype.resolve = function (id) { require("@meteorjs/reify/lib/runtime").enable(Module.prototype); -if (!process.env.DISABLE_FIBERS) { - require("meteor-promise").makeCompatible( - global.Promise = global.Promise || - require("promise/lib/es6-extensions"), - require("fibers") - ); - -// If Promise.asyncApply is defined, use it to wrap calls to -// regeneratorRuntime.async so that the entire async function will run in -// its own Fiber, not just the code that comes after the first await. - if (typeof Promise.asyncApply === "function") { - var regeneratorRuntime = require("@babel/runtime/regenerator"); - var realAsync = regeneratorRuntime.async; - regeneratorRuntime.async = function (innerFn) { - return Promise.asyncApply(realAsync, regeneratorRuntime, arguments); - }; - } -} diff --git a/npm-packages/meteor-babel/test/decorators.js b/npm-packages/meteor-babel/test/decorators.js index a05ca240db..a12ceb4923 100644 --- a/npm-packages/meteor-babel/test/decorators.js +++ b/npm-packages/meteor-babel/test/decorators.js @@ -25,12 +25,11 @@ describe("@decorators", function () { .includes("decorators-legacy")); assert.ok(legacyResult.options.plugins.some(function (plugin) { - return plugin.key === "regenerator-transform"; + return plugin.key === "transform-regenerator"; })); assert.strictEqual(legacyResult.code.trim(), [ "var _class;", - "", "var A = dec(_class = function A() {}) || _class;", ].join("\n")); }); @@ -57,12 +56,11 @@ describe("@decorators", function () { .includes("decorators-legacy")); assert.ok(legacyResult.options.plugins.every(function (plugin) { - return plugin.key !== "regenerator-transform"; + return plugin.key !== "transform-regenerator"; })); assert.strictEqual(legacyResult.code.trim(), [ "var _class;", - "", "let A = dec(_class = class A {}) || _class;", ].join("\n")); }); @@ -89,16 +87,11 @@ describe("@decorators", function () { .includes("decorators-legacy")); assert.ok(legacyResult.options.plugins.every(function (plugin) { - return plugin.key !== "regenerator-transform"; - })); - - assert.ok(legacyResult.options.plugins.some(function (plugin) { - return plugin.key === "transform-meteor-async-await"; + return plugin.key !== "transform-regenerator"; })); assert.strictEqual(legacyResult.code.trim(), [ "var _class;", - "", "let A = dec(_class = class A {}) || _class;", ].join("\n")); }); diff --git a/npm-packages/meteor-babel/test/tests.js b/npm-packages/meteor-babel/test/tests.js index fb77a6390f..2dd7a4a585 100644 --- a/npm-packages/meteor-babel/test/tests.js +++ b/npm-packages/meteor-babel/test/tests.js @@ -315,7 +315,6 @@ describe("@meteorjs/babel", () => { " }", "});", "var Test;", - "", "(function (Test) {", " Test.enabled = true;", "})(Test || module.runSetters(Test = {}, [\"Test\"]));", @@ -775,40 +774,6 @@ val = "zxcv";`; assert.strictEqual(sum, limit * (limit + 1) / 2); }); - it("Promise.await", () => { - var markers = []; - - async function f() { - markers.push("before"); - if (require("fibers").current) { - assert.strictEqual( - Promise.await(Promise.resolve(1234)), - 1234 - ); - } else { - assert.strictEqual( - await Promise.resolve(1234), - 1234 - ); - } - markers.push("after"); - return "done"; - } - - assert.deepEqual(markers, []); - - var promise = f(); - - // The async function should execute synchronously up to the first - // Promise.await or await expression, but no further. - assert.deepEqual(markers, ["before"]); - - return promise.then(result => { - assert.strictEqual(result, "done"); - assert.deepEqual(markers, ["before", "after"]); - }); - }); - it("async arrow functions", async function () { const addOneAsync = async arg => (await arg) + 1; const sum = await addOneAsync(2345); diff --git a/npm-packages/meteor-installer/README.md b/npm-packages/meteor-installer/README.md index 9a84c48eca..1430bcab86 100644 --- a/npm-packages/meteor-installer/README.md +++ b/npm-packages/meteor-installer/README.md @@ -1,75 +1,106 @@ -## Meteor Installer - -Node.js <=14.x and npm <=6.x is recommended. - -Install Meteor by running: - -```bash -npm install -g meteor -``` - -[Read more](https://www.meteor.com/developers/install) - -### Meteor version relationship - -| NPM Package | Meteor Official Release | -|-------------|-------------------------| -| 2.13.3 | 2.13.3 | -| 2.13.1 | 2.13.1 | -| 2.13.0 | 2.13.0 | -| 2.12.1 | 2.12.0 | -| 2.12.0 | 2.12.0 | -| 2.11.0 | 2.11.0 | -| 2.10.0 | 2.10.0 | -| 2.9.1 | 2.9.1 | -| 2.9.0 | 2.9.0 | -| 2.8.2 | 2.8.1 | -| 2.8.1 | 2.8.1 | -| 2.8.0 | 2.8.0 | -| 2.7.5 | 2.7.3 | -| 2.7.4 | 2.7.3 | -| 2.7.3 | 2.7.2 | -| 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.9 | 2.5.8 | -| 2.5.8 | 2.5.7 | -| 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, it is just an installer. You should not include it as a dependency in your project. If you do, your deployment 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`) - -### Proxy configuration - -Setting the `https_proxy` or `HTTPS_PROXY` environment variable to a valid proxy URL will cause the -downloader to use the configured proxy to retrieve the Meteor files. +## Meteor Installer + +### Recommended Versions + +- For Meteor 2 (Legacy) + - Use Node.js 14.x + - Use npm 6.x +- For Meteor 3 + - Use Node.js 20.x or higher + - Use npm 9.x or higher + +### Installation + +To install Meteor, run the following command: + +```bash +npx meteor +``` + +It will install Meteor's latest version, alternatively you can install a specific version by running: + +```bash +npx meteor@ +``` + +This command will execute the Meteor installer without adding it permanently to your global npm packages. + +For more information, visit: + +- [Meteor 2 Installation Guide (Legacy)](https://v2-docs.meteor.com/install.html) +- [**Meteor 3 Installation Guide**](https://v3-docs.meteor.com/about/install.html) + + + + + +### Important Note + +This npm package is not the Meteor framework itself; it is just an installer. Do not include it as a dependency in your project, as doing so may break your deployment. + +### 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`) + +### Proxy Configuration + +Set the `https_proxy` or `HTTPS_PROXY` environment variable to a valid proxy URL to download Meteor files through the configured proxy. + +### Meteor Version Compatibility + +| NPM Package | Meteor Official Release | +|-------------|-------------------------| +| 3.0.4 | 3.0.4 | +| 3.0.3 | 3.0.3 | +| 3.0.2 | 3.0.2 | +| 3.0.1 | 3.0.1 | +| 3.0.0 | 3.0 | +| 2.16.0 | 2.16.0 | +| 2.15.0 | 2.15.0 | +| 2.14.0 | 2.14.0 | +| 2.13.3 | 2.13.3 | +| 2.13.1 | 2.13.1 | +| 2.13.0 | 2.13.0 | +| 2.12.1 | 2.12.0 | +| 2.12.0 | 2.12.0 | +| 2.11.0 | 2.11.0 | +| 2.10.0 | 2.10.0 | +| 2.9.1 | 2.9.1 | +| 2.9.0 | 2.9.0 | +| 2.8.2 | 2.8.1 | +| 2.8.1 | 2.8.1 | +| 2.8.0 | 2.8.0 | +| 2.7.5 | 2.7.3 | +| 2.7.4 | 2.7.3 | +| 2.7.3 | 2.7.2 | +| 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.9 | 2.5.8 | +| 2.5.8 | 2.5.7 | +| 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 | diff --git a/npm-packages/meteor-installer/cli.js b/npm-packages/meteor-installer/cli.js index ea3c2034cc..7bcc2f9eeb 100755 --- a/npm-packages/meteor-installer/cli.js +++ b/npm-packages/meteor-installer/cli.js @@ -1,10 +1,10 @@ #!/usr/bin/env node -const command = process.argv[2]; +const command = process.argv[2] || 'install'; if (!command) { console.log(` - Usage: meteor-installer + Usage: npx meteor@ Commands: install diff --git a/npm-packages/meteor-installer/config.js b/npm-packages/meteor-installer/config.js index d0c58c2c7c..4f96ac3ad4 100644 --- a/npm-packages/meteor-installer/config.js +++ b/npm-packages/meteor-installer/config.js @@ -1,7 +1,7 @@ -const path = require('path'); const os = require('os'); +const path = require('path'); -const METEOR_LATEST_VERSION = '2.13.3'; +const METEOR_LATEST_VERSION = '3.3.2'; const sudoUser = process.env.SUDO_USER || ''; function isRoot() { return process.getuid && process.getuid() === 0; @@ -12,6 +12,7 @@ function isSudo() { const localAppData = process.env.LOCALAPPDATA; const isWindows = () => os.platform() === 'win32'; const isMac = () => os.platform() === 'darwin'; +const isLinux = () => os.platform() === 'linux'; let rootPath; if (isWindows()) { @@ -21,7 +22,7 @@ if (isWindows()) { } else { if (isRoot()) { console.info( - 'You are running the install script as root, without SUDO. This is not recommended and should be avoided. Continuing.' + 'You are running the install script as root, without SUDO. This is not recommended and should be avoided. Continuing.', ); } rootPath = os.homedir(); @@ -47,6 +48,7 @@ module.exports = { startedPath: path.resolve(rootPath, '.meteor-install-started.txt'), isWindows, isMac, + isLinux, isRoot, isSudo, shouldSetupExecPath, diff --git a/npm-packages/meteor-installer/extract.js b/npm-packages/meteor-installer/extract.js index 39e8c0776f..2a6362d66f 100644 --- a/npm-packages/meteor-installer/extract.js +++ b/npm-packages/meteor-installer/extract.js @@ -1,10 +1,11 @@ -const tar = require('tar'); const sevenBin = require('7zip-bin'); -const Seven = require('node-7z'); -const fs = require('fs'); -const { resolve, dirname } = require('path'); const child_process = require('child_process'); -const { isMac } = require('./config.js'); +const fs = require('fs'); +const Seven = require('node-7z'); +const { resolve, dirname } = require('path'); +const tar = require('tar'); + +const { isLinux } = require('./config.js'); function extractWith7Zip(tarPath, destination, onProgress) { return new Promise((resolve, reject) => { @@ -12,15 +13,15 @@ function extractWith7Zip(tarPath, destination, onProgress) { $progress: true, $bin: sevenBin.path7za, }); - stream.on('progress', function(progress) { + stream.on('progress', function (progress) { onProgress(progress); }); - stream.on('error', function(err) { + stream.on('error', function (err) { return reject(err); }); - stream.on('end', function() { + stream.on('end', function () { return resolve(); }); }); @@ -48,14 +49,14 @@ function createSymlinks(symlinks, baseDir) { function extractWithNativeTar(tarPath, destination) { child_process.execSync( `tar -xf "${tarPath}" ${ - !isMac() ? `--checkpoint-action=ttyout="#%u: %T \r"` : `` + isLinux() ? `--checkpoint-action=ttyout="#%u: %T \r"` : `` } -C "${destination}"`, { cwd: process.cwd(), env: process.env, stdio: [process.stdin, process.stdout, process.stderr], encoding: 'utf-8', - } + }, ); } @@ -116,7 +117,7 @@ function extractWithTar(tarPath, destination, onProgress) { } createSymlinks(symlinks, destination); resolve(); - } + }, ); }); } diff --git a/npm-packages/meteor-installer/install.js b/npm-packages/meteor-installer/install.js index 8b89028b07..0c3d7b7922 100644 --- a/npm-packages/meteor-installer/install.js +++ b/npm-packages/meteor-installer/install.js @@ -1,13 +1,13 @@ -const { DownloaderHelper } = require('node-downloader-helper'); -const cliProgress = require('cli-progress'); -const Seven = require('node-7z'); -const path = require('path'); const sevenBin = require('7zip-bin'); -const semver = require('semver'); const child_process = require('child_process'); -const tmp = require('tmp'); -const os = require('os'); +const cliProgress = require('cli-progress'); const fs = require('fs'); +const Seven = require('node-7z'); +const { DownloaderHelper } = require('node-downloader-helper'); +const os = require('os'); +const path = require('path'); +const semver = require('semver'); +const tmp = require('tmp'); const fsPromises = fs.promises; @@ -20,17 +20,17 @@ const { rootPath, sudoUser, isSudo, - isMac, + isLinux, METEOR_LATEST_VERSION, shouldSetupExecPath, } = require('./config'); -const { uninstall } = require('./uninstall'); const { extractWithTar, extractWith7Zip, extractWithNativeTar, } = require('./extract'); const { engines } = require('./package.json'); +const { uninstall } = require('./uninstall'); const nodeVersion = engines.node; const npmVersion = engines.npm; @@ -38,38 +38,41 @@ const npmVersion = engines.npm; // Compare installed NodeJs version with required NodeJs version if (!semver.satisfies(process.version, nodeVersion)) { console.warn( - `WARNING: Recommended versions are Node.js ${nodeVersion} and npm ${npmVersion}.` + `WARNING: Recommended versions are Node.js ${nodeVersion} and npm ${npmVersion}.`, ); console.warn( - `We recommend using a Node version manager like NVM or Volta to install Node.js and npm.\n` + `We recommend using a Node version manager like NVM or Volta to install Node.js and npm.\n`, ); } -const isInstalledGlobally = process.env.npm_config_global === 'true'; +const isInstalledGlobally = + process.env.npm_config_global === 'true' || + process.env.npm_lifecycle_event === 'npx'; if (!isInstalledGlobally) { console.error('******************************************'); console.error( - 'You are not using a global npm context to install, you should never add meteor to your package.json.' + 'You are not using a global npm context to install, you should never add meteor to your package.json.', ); console.error('Make sure you pass -g to npm install.'); console.error('Aborting...'); console.error('******************************************'); - process.exit(1); + process.exit(0); } process.on('unhandledRejection', err => { throw err; }); + if (os.arch() !== 'x64') { const isValidM1Version = semver.gte( semver.coerce(METEOR_LATEST_VERSION), - '2.5.1-beta.3' + '2.5.1-beta.3', ); - if (os.arch() !== 'arm64' || !isMac() || !isValidM1Version) { + if (os.arch() !== 'arm64' || !isValidM1Version) { console.error( 'The current architecture is not supported in this version: ', os.arch(), - '. Try Meteor 2.5.1-beta.3 or above.' + '. Try Meteor 2.5.1-beta.3 or above.', ); process.exit(1); } @@ -81,9 +84,15 @@ const downloadPlatform = { linux: 'linux', }; -const url = `https://packages.meteor.com/bootstrap-link?arch=os.${ - downloadPlatform[os.platform()] -}.${os.arch() === 'arm64' ? 'arm64' : 'x86_64'}&release=${release}`; +function getDownloadArch() { + const osArch = os.arch(); + if (isLinux() && osArch === 'arm64') return 'aarch64'; + if (osArch === 'arm64') return 'arm64'; + return 'x86_64'; +} + +const arch = `os.${downloadPlatform[os.platform()]}.${getDownloadArch()}`; +const url = `https://packages.meteor.com/bootstrap-link?arch=${arch}&release=${release}`; let tempDirObject; try { @@ -95,10 +104,10 @@ try { console.error("Couldn't create tmp dir for extracting meteor."); console.error('There are 2 possible causes:'); console.error( - '\t1. You are running npm install -g meteor as root without passing the --unsafe-perm option. Please rerun with this option enabled.' + '\t1. You are running npm install -g meteor as root without passing the --unsafe-perm option. Please rerun with this option enabled.', ); console.error( - '\t2. You might not have enough space in disk or permission to create folders' + '\t2. You might not have enough space in disk or permission to create folders', ); console.error('****************************'); console.error(''); @@ -121,9 +130,9 @@ if (fs.existsSync(startedPath)) { console.log( `If you want to reinstall it, run: - $ meteor-installer uninstall - $ meteor-installer install -` + $ npx meteor uninstall + $ npx meteor@ install +`, ); process.exit(); } @@ -151,6 +160,9 @@ try { } } +console.log(`=> Arch: ${arch}`); +console.log(`=> Meteor Release: ${release}`); + download(); function generateProxyAgent() { @@ -171,7 +183,7 @@ function download() { format: 'Downloading |{bar}| {percentage}%', clearOnComplete: true, }, - cliProgress.Presets.shades_classic + cliProgress.Presets.shades_classic, ); downloadProgress.start(100, 0); @@ -199,8 +211,19 @@ function download() { } if (isWindows()) { - decompress(); - return; + const hasNativeTar = fs.existsSync( + path.resolve('C:/Windows/System32', 'tar.exe'), + ); + if (hasNativeTar) { + // tar works exactly the same as it's bsdtar counterpart on UNIX so continue + console.log( + 'Native binary for tar is available on this version of Windows.', + ); + console.log('Switching to the native tar.exe binary on Windows.'); + } else { + decompress(); + return; + } } fs.writeFileSync(startedPath, 'Meteor install started'); @@ -209,7 +232,7 @@ function download() { await extractWithNativeTar(path.resolve(tempPath, tarGzName), extractPath); const extractEnd = Date.now(); console.log( - `=> Meteor extracted in ${(extractEnd - extractStart) / 1000}s` + `=> Meteor extracted in ${(extractEnd - extractStart) / 1000}s`, ); await setup(); }); @@ -224,7 +247,7 @@ function decompress() { format: 'Decompressing |{bar}| {percentage}%', clearOnComplete: true, }, - cliProgress.Presets.shades_classic + cliProgress.Presets.shades_classic, ); decompressProgress.start(100, 0); @@ -232,11 +255,11 @@ function decompress() { $progress: true, $bin: sevenBin.path7za, }); - myStream.on('progress', function(progress) { + myStream.on('progress', function (progress) { decompressProgress.update(progress.percent); }); - myStream.on('end', function() { + myStream.on('end', function () { decompressProgress.update(100); decompressProgress.stop(); const end = Date.now(); @@ -254,7 +277,7 @@ async function extract() { format: 'Extracting |{bar}| {percentage}% - {fileCount} files completed', clearOnComplete: true, }, - cliProgress.Presets.shades_classic + cliProgress.Presets.shades_classic, ); decompressProgress.start(100, 0, { fileCount: 0, @@ -290,7 +313,9 @@ async function setup() { async function setupExecPath() { if (isWindows()) { // set for the current session and beyond - child_process.execSync(`setx path "${meteorPath}/;%path%`); + child_process.execSync( + `powershell -c "$path = (Get-Item 'HKCU:\\Environment').GetValue('Path', '', 'DoNotExpandEnvironmentNames'); [Environment]::SetEnvironmentVariable('PATH', \\"${meteorPath};$path\\", 'User');"`, + ); return; } const exportCommand = `export PATH=${meteorPath}:$PATH`; @@ -316,7 +341,7 @@ function showGettingStarted() { const exportCommand = `export PATH=${meteorPath}:$PATH`; const runCommand = isWindows() - ? `set path "${meteorPath}/;%path%` + ? `set path "${meteorPath}/;%path%"` : exportCommand; const message = ` *************************************** @@ -335,7 +360,7 @@ Or see the docs at: Deploy and host your app with Cloud: - www.meteor.com/cloud + https://galaxycloud.app/ *************************************** You might need to open a new terminal window to have access to the meteor command, or run this in your terminal: diff --git a/npm-packages/meteor-installer/package-lock.json b/npm-packages/meteor-installer/package-lock.json new file mode 100644 index 0000000000..95184ff90f --- /dev/null +++ b/npm-packages/meteor-installer/package-lock.json @@ -0,0 +1,793 @@ +{ + "name": "meteor", + "version": "3.3.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "meteor", + "version": "3.3.2", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "7zip-bin": "^5.2.0", + "cli-progress": "^3.11.1", + "https-proxy-agent": "^5.0.1", + "node-7z": "^2.1.2", + "node-downloader-helper": "^2.1.9", + "rimraf": "^6.0.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tmp": "^0.2.1" + }, + "bin": { + "meteor-installer": "cli.js" + }, + "engines": { + "node": ">=20.x", + "npm": ">=10.x" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==" + }, + "node_modules/lodash.defaultto": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/lodash.defaultto/-/lodash.defaultto-4.14.0.tgz", + "integrity": "sha512-G6tizqH6rg4P5j32Wy4Z3ZIip7OfG8YWWlPFzUFGcYStH1Ld0l1tWs6NevEQNEDnO1M3NZYjuHuraaFSN5WqeQ==" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==" + }, + "node_modules/lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==" + }, + "node_modules/lodash.negate": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.negate/-/lodash.negate-3.0.2.tgz", + "integrity": "sha512-JGJYYVslKYC0tRMm/7igfdHulCjoXjoganRNWM8AgS+RXfOvFnPkOveDhPI65F9aAypCX9QEEQoBqWf7Q6uAeA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-7z": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-7z/-/node-7z-2.1.2.tgz", + "integrity": "sha512-mSmn90OIYKYIkuRwH1YRJl2sMwB9OlYhCQS4SPTOfxlzWwomoC1G9j4tsvAsv7vJPwvK7B76Z0a2dH5Mvwo91Q==", + "dependencies": { + "cross-spawn": "^7.0.2", + "debug": "^4.1.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.defaultto": "^4.14.0", + "lodash.flattendeep": "^4.4.0", + "lodash.isempty": "^4.4.0", + "lodash.negate": "^3.0.2", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-downloader-helper": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz", + "integrity": "sha512-FSvAol2Z8UP191sZtsUZwHIN0eGoGue3uEXGdWIH5228e9KH1YHXT7fN8Oa33UGf+FbqGTQg3sJfrRGzmVCaJA==", + "bin": { + "ndh": "bin/ndh" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/npm-packages/meteor-installer/package.json b/npm-packages/meteor-installer/package.json index 0465731d17..e9fc928561 100644 --- a/npm-packages/meteor-installer/package.json +++ b/npm-packages/meteor-installer/package.json @@ -1,29 +1,30 @@ -{ - "name": "meteor", - "version": "2.13.3", - "description": "Install Meteor", - "main": "install.js", - "scripts": { - "install": "node cli.js install" - }, - "author": "zodern", - "license": "MIT", - "dependencies": { - "7zip-bin": "^5.2.0", - "cli-progress": "^3.11.1", - "https-proxy-agent": "^5.0.1", - "node-7z": "^2.1.2", - "node-downloader-helper": "^1.0.19", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "tar": "^6.1.11", - "tmp": "^0.2.1" - }, - "bin": { - "meteor-installer": "cli.js" - }, - "engines": { - "node": "<=14.x", - "npm": "<=6.x" - } -} +{ + "name": "meteor", + "version": "3.3.2", + "description": "Install Meteor", + "main": "install.js", + "scripts": { + "install": "node cli.js install" + }, + "author": "zodern", + "license": "MIT", + "type": "commonjs", + "dependencies": { + "7zip-bin": "^5.2.0", + "cli-progress": "^3.11.1", + "https-proxy-agent": "^5.0.1", + "node-7z": "^2.1.2", + "node-downloader-helper": "^2.1.9", + "rimraf": "^6.0.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tmp": "^0.2.1" + }, + "bin": { + "meteor-installer": "cli.js" + }, + "engines": { + "node": ">=20.x", + "npm": ">=10.x" + } +} diff --git a/npm-packages/meteor-installer/uninstall.js b/npm-packages/meteor-installer/uninstall.js index 28c638e3c0..013a75e3ae 100644 --- a/npm-packages/meteor-installer/uninstall.js +++ b/npm-packages/meteor-installer/uninstall.js @@ -1,6 +1,7 @@ -const { meteorPath } = require('./config'); const rimraf = require('rimraf'); +const { meteorPath } = require('./config'); + function uninstall() { console.log(`Uninstalling Meteor from ${meteorPath}`); diff --git a/npm-packages/meteor-node-stubs/.npmignore b/npm-packages/meteor-node-stubs/.npmignore index 07e6e472cc..e69de29bb2 100644 --- a/npm-packages/meteor-node-stubs/.npmignore +++ b/npm-packages/meteor-node-stubs/.npmignore @@ -1 +0,0 @@ -/node_modules diff --git a/npm-packages/meteor-node-stubs/CHANGELOG.md b/npm-packages/meteor-node-stubs/CHANGELOG.md index 8e02fcc3d8..c510d86ea7 100644 --- a/npm-packages/meteor-node-stubs/CHANGELOG.md +++ b/npm-packages/meteor-node-stubs/CHANGELOG.md @@ -1,3 +1,18 @@ +v1.2.13 - 2025-02-27 + +* Update `elliptic` to v6.6.1 to address a security vulnerability. + +v1.2.12 - 2024-10-31 + +* Update `elliptic` to v6.6.0 to address a security vulnerability. + +v1.2.11 - 2024-10-25 + +* Update `rimraf` to v5 to remove vulnerable `inflight` dependency. + +v1.2.8 - 2024-04-01 +* Add new dependency `@meteorjs/crypto-browserify` to replace `crypto-browserify` as it had unsafe dependencies. + v1.2.1 - 2022-03-17 * Fix the missing dependencies. diff --git a/npm-packages/meteor-node-stubs/package-lock.json b/npm-packages/meteor-node-stubs/package-lock.json index 0f2873a785..960afee14a 100644 --- a/npm-packages/meteor-node-stubs/package-lock.json +++ b/npm-packages/meteor-node-stubs/package-lock.json @@ -1,79 +1,354 @@ { "name": "meteor-node-stubs", - "version": "1.2.5", - "lockfileVersion": 1, + "version": "1.2.23", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { + "packages": { + "": { + "name": "meteor-node-stubs", + "version": "1.2.23", + "bundleDependencies": [ + "@meteorjs/crypto-browserify", + "assert", + "browserify-zlib", + "buffer", + "console-browserify", + "constants-browserify", + "domain-browser", + "events", + "https-browserify", + "os-browserify", + "path-browserify", + "process", + "punycode", + "querystring-es3", + "readable-stream", + "stream-browserify", + "stream-http", + "string_decoder", + "timers-browserify", + "tty-browserify", + "url", + "util", + "vm-browserify" + ], + "license": "MIT", + "dependencies": { + "@meteorjs/crypto-browserify": "^3.12.1", + "assert": "^2.1.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "domain-browser": "^4.23.0", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.2", + "sha.js": "^2.4.12", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.5", + "vm-browserify": "^1.1.2" + }, + "devDependencies": { + "rimraf": "^5.0.10" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@meteorjs/browserify-sign": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@meteorjs/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-xnQRbIrjHxaVbOEbzbcdav4QDRTnfRAVHi21SPosnGNiIHTdTeGQGmTF/f7GwntxqynabSifdBHeGA7W8lIKSQ==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.1", + "brorand": "^1.1.0", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash-base": "~3.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@meteorjs/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@meteorjs/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@meteorjs/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@meteorjs/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@meteorjs/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@meteorjs/create-ecdh": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@meteorjs/create-ecdh/-/create-ecdh-4.0.5.tgz", + "integrity": "sha512-dhn3AICsDlIZ5qY/Qu+QOL+ZGKaHcGss4PQ3CfmAF3f+o5fPJ2aDJcxd5f2au2k6sxyNqvCsLAFYFHXxHoH9yQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@meteorjs/create-ecdh/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@meteorjs/crypto-browserify": { + "version": "3.12.4", + "resolved": "https://registry.npmjs.org/@meteorjs/crypto-browserify/-/crypto-browserify-3.12.4.tgz", + "integrity": "sha512-K5Sgvxef93Zrw5T9cJxKuNVgpl1C2W8cfcicN6HKy98G6RoIrx6hikwWnq8FlagvOzdIQEC2s+SMn7UFNSK0eA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@meteorjs/browserify-sign": "^4.2.3", + "@meteorjs/create-ecdh": "^4.0.4", + "browserify-cipher": "^1.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "inBundle": true, + "license": "MIT", + "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "inBundle": true, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" } }, - "assert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", - "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", - "requires": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "available-typed-arrays": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", - "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==" - }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, - "base64-js": { + "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "inBundle": true, + "license": "MIT" }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "brorand": { + "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "inBundle": true, + "license": "MIT" }, - "browserify-aes": { + "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", "create-hash": "^1.1.0", @@ -82,134 +357,206 @@ "safe-buffer": "^5.0.1" } }, - "browserify-cipher": { + "node_modules/browserify-cipher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", "evp_bytestokey": "^1.0.0" } }, - "browserify-des": { + "node_modules/browserify-des": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "browserify-zlib": { + "node_modules/browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "pako": "~1.0.5" } }, - "buffer": { + "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, - "buffer-xor": { + "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "inBundle": true, + "license": "MIT" }, - "builtin-status-codes": { + "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "inBundle": true, + "license": "MIT" }, - "call-bind": { + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "cipher-base": { + "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "node_modules/cipher-base": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } }, - "console-browserify": { + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "inBundle": true }, - "constants-browserify": { + "node_modules/constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "inBundle": true, + "license": "MIT" }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "inBundle": true, + "license": "MIT" }, - "create-hash": { + "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", "md5.js": "^1.3.4", @@ -217,11 +564,13 @@ "sha.js": "^2.4.0" } }, - "create-hmac": { + "node_modules/create-hmac": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", "inherits": "^2.0.1", @@ -230,720 +579,1559 @@ "sha.js": "^2.4.8" } }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "inBundle": true, + "license": "MIT", + "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, - "diffie-hellman": { + "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/domain-browser": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", + "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", + "inBundle": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=10" }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "funding": { + "url": "https://bevry.me/fund" } }, - "domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==" - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "inBundle": true, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" } }, - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" - }, - "events": { + "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } }, - "evp_bytestokey": { + "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "inBundle": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-bigints": { + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "hash.js": { + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, - "hmac-drbg": { + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "inBundle": true, + "license": "MIT", + "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, - "https-browserify": { + "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "inBundle": true, + "license": "MIT" }, - "ieee754": { + "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "inBundle": true, + "license": "ISC" }, - "is-arguments": { + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "requires": { - "call-bind": "^1.0.0" + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" - }, - "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" - }, - "is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" - }, - "is-generator-function": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.9.tgz", - "integrity": "sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A==" - }, - "is-nan": { + "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" - }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-typed-array": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", - "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", - "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.0-next.2", - "foreach": "^2.0.5", - "has-symbols": "^1.0.1" + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "md5.js": { + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, - "miller-rabin": { + "node_modules/miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "bin": { + "miller-rabin": "bin/miller-rabin" } }, - "minimalistic-assert": { + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "inBundle": true, + "license": "ISC" }, - "minimalistic-crypto-utils": { + "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "inBundle": true, + "license": "MIT" }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "requires": { - "brace-expansion": "^1.1.7" + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" } }, - "object-keys": { + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-browserify": { + "node_modules/os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "inBundle": true, + "license": "MIT" }, - "pako": { + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "inBundle": true, + "license": "(MIT AND Zlib)" }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "node_modules/parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, - "path-browserify": { + "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "inBundle": true, + "license": "MIT" }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "process": { + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", + "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "create-hash": "~1.1.3", + "create-hmac": "^1.1.7", + "ripemd160": "=2.0.1", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.11", + "to-buffer": "^1.2.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pbkdf2/node_modules/create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "sha.js": "^2.4.0" + } + }, + "node_modules/pbkdf2/node_modules/hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1" + } + }, + "node_modules/pbkdf2/node_modules/ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash-base": "^2.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, - "public-encrypt": { + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } } }, - "punycode": { + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "inBundle": true, + "license": "MIT" }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "querystring-es3": { + "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "inBundle": true, + "engines": { + "node": ">=0.4.x" + } }, - "randombytes": { + "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "safe-buffer": "^5.1.0" } }, - "randomfill": { + "node_modules/randomfill": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "inBundle": true, + "license": "MIT", + "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, - "requires": { - "glob": "^7.1.3" + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "ripemd160": { + "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "stream-browserify": { + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "inBundle": true, + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "inBundle": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, - "stream-http": { + "node_modules/stream-http": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.4", "readable-stream": "^3.6.0", "xtend": "^4.0.2" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { + "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "safe-buffer": "~5.2.0" } }, - "timers-browserify": { + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/timers-browserify": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "requires": { + "inBundle": true, + "license": "MIT", + "dependencies": { "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" } }, - "tty-browserify": { + "node_modules/to-buffer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", + "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "inBundle": true, + "license": "MIT" }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "inBundle": true, + "license": "MIT", "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", - "requires": { + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "inBundle": true, + "license": "MIT", + "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "inBundle": true, + "license": "MIT" }, - "vm-browserify": { + "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "inBundle": true, + "license": "MIT" }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "which-typed-array": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", - "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", - "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", - "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "xtend": { + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } } } } diff --git a/npm-packages/meteor-node-stubs/package.json b/npm-packages/meteor-node-stubs/package.json index d422247d65..3e2867429e 100644 --- a/npm-packages/meteor-node-stubs/package.json +++ b/npm-packages/meteor-node-stubs/package.json @@ -2,46 +2,47 @@ "name": "meteor-node-stubs", "author": "Ben Newman ", "description": "Stub implementations of Node built-in modules, a la Browserify", - "version": "1.2.5", + "version": "1.2.24", "main": "index.js", "license": "MIT", "homepage": "https://github.com/meteor/meteor/blob/devel/npm-packages/meteor-node-stubs/README.md", + "type": "commonjs", "scripts": { "prepare": "node scripts/build-deps.js" }, "dependencies": { - "assert": "^2.0.0", + "@meteorjs/crypto-browserify": "^3.12.1", + "assert": "^2.1.0", "browserify-zlib": "^0.2.0", "buffer": "^5.7.1", "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "domain-browser": "^4.22.0", - "elliptic": "^6.5.4", + "domain-browser": "^4.23.0", "events": "^3.3.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "^1.0.0", + "path-browserify": "^1.0.1", "process": "^0.11.10", "punycode": "^1.4.1", "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", + "readable-stream": "^3.6.2", + "sha.js": "^2.4.12", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "string_decoder": "^1.3.0", "timers-browserify": "^2.0.12", "tty-browserify": "0.0.1", - "url": "^0.11.0", - "util": "^0.12.4", + "url": "^0.11.4", + "util": "^0.12.5", "vm-browserify": "^1.1.2" }, "bundledDependencies": [ + "@meteorjs/crypto-browserify", "assert", "browserify-zlib", "buffer", "console-browserify", "constants-browserify", - "crypto-browserify", "domain-browser", "events", "https-browserify", @@ -61,7 +62,7 @@ "vm-browserify" ], "devDependencies": { - "rimraf": "^2.5.2" + "rimraf": "^5.0.10" }, "repository": { "type": "git", @@ -80,5 +81,30 @@ ], "bugs": { "url": "https://github.com/meteor/node-stubs/issues" - } + }, + "bundleDependencies": [ + "@meteorjs/crypto-browserify", + "assert", + "browserify-zlib", + "buffer", + "console-browserify", + "constants-browserify", + "domain-browser", + "events", + "https-browserify", + "os-browserify", + "path-browserify", + "process", + "punycode", + "querystring-es3", + "readable-stream", + "stream-browserify", + "stream-http", + "string_decoder", + "timers-browserify", + "tty-browserify", + "url", + "util", + "vm-browserify" + ] } diff --git a/npm-packages/meteor-node-stubs/scripts/build-deps.js b/npm-packages/meteor-node-stubs/scripts/build-deps.js index e85d8d7c1f..7c6808f6ec 100644 --- a/npm-packages/meteor-node-stubs/scripts/build-deps.js +++ b/npm-packages/meteor-node-stubs/scripts/build-deps.js @@ -2,6 +2,7 @@ var fs = require("fs"); var path = require("path"); var depsDir = path.join(__dirname, "..", "deps"); var map = require("../map.json"); +var rr = require("rimraf"); // Each file in the `deps` directory expresses the dependencies of a stub. // For example, `deps/http.js` calls `require("http-browserify")` to @@ -14,16 +15,15 @@ var map = require("../map.json"); // bundled. Note that these modules should not be `require`d at runtime, // but merely scanned at bundling time. -fs.mkdir(depsDir, function () { - require("rimraf")("deps/*.js", function (error) { - if (error) throw error; - Object.keys(map).forEach(function (id) { - fs.writeFileSync( - path.join(depsDir, id + ".js"), - typeof map[id] === "string" - ? "require(" + JSON.stringify(map[id]) + ");\n" - : "" - ); - }); - }); +rr.rimrafSync(depsDir); + +fs.mkdirSync(depsDir); + +Object.keys(map).forEach(function (id) { + fs.writeFileSync( + path.join(depsDir, id + ".js"), + typeof map[id] === "string" + ? "require(" + JSON.stringify(map[id]) + ");\n" + : "" + ); }); diff --git a/npm-packages/meteor-node-stubs/wrappers/crypto.js b/npm-packages/meteor-node-stubs/wrappers/crypto.js index 206074a0af..f5128a2002 100644 --- a/npm-packages/meteor-node-stubs/wrappers/crypto.js +++ b/npm-packages/meteor-node-stubs/wrappers/crypto.js @@ -1,2 +1,2 @@ global.Buffer = global.Buffer || require("buffer").Buffer; -module.exports = require("crypto-browserify"); +module.exports = require("@meteorjs/crypto-browserify"); diff --git a/npm-packages/meteor-promise/package.json b/npm-packages/meteor-promise/package.json index ddad4c87d8..c69cc4a3fb 100644 --- a/npm-packages/meteor-promise/package.json +++ b/npm-packages/meteor-promise/package.json @@ -1,8 +1,9 @@ { "name": "meteor-promise", "author": "Ben Newman ", - "version": "0.9.1", + "version": "0.9.2", "description": "ES6 Promise polyfill with Fiber support", + "type": "commonjs", "keywords": [ "meteor", "promise", @@ -14,9 +15,6 @@ "main": "promise_server.js", "browser": "promise_client.js", "typings": "promise.d.ts", - "scripts": { - "test": "test/run.sh" - }, "homepage": "https://github.com/meteor/promise", "repository": { "type": "git", diff --git a/npm-packages/meteor-promise/promise_server.js b/npm-packages/meteor-promise/promise_server.js index 5f6501da96..c2c569c3b4 100644 --- a/npm-packages/meteor-promise/promise_server.js +++ b/npm-packages/meteor-promise/promise_server.js @@ -9,7 +9,7 @@ exports.makeCompatible = function (Promise, Fiber) { } if (es6PromiseThen.name === "meteorPromiseThen") { - return; // Already compatible. + return; // Already compatible } function meteorPromiseThen(onResolved, onRejected) { diff --git a/npm-packages/meteor-promise/test/index.html b/npm-packages/meteor-promise/test/index.html deleted file mode 100644 index 0590d4aac2..0000000000 --- a/npm-packages/meteor-promise/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - Mocha - - - - - -
- - - - - - diff --git a/npm-packages/meteor-promise/test/mocha.css b/npm-packages/meteor-promise/test/mocha.css deleted file mode 100644 index 42b9798fa4..0000000000 --- a/npm-packages/meteor-promise/test/mocha.css +++ /dev/null @@ -1,270 +0,0 @@ -@charset "utf-8"; - -body { - margin:0; -} - -#mocha { - font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; - margin: 60px 50px; -} - -#mocha ul, -#mocha li { - margin: 0; - padding: 0; -} - -#mocha ul { - list-style: none; -} - -#mocha h1, -#mocha h2 { - margin: 0; -} - -#mocha h1 { - margin-top: 15px; - font-size: 1em; - font-weight: 200; -} - -#mocha h1 a { - text-decoration: none; - color: inherit; -} - -#mocha h1 a:hover { - text-decoration: underline; -} - -#mocha .suite .suite h1 { - margin-top: 0; - font-size: .8em; -} - -#mocha .hidden { - display: none; -} - -#mocha h2 { - font-size: 12px; - font-weight: normal; - cursor: pointer; -} - -#mocha .suite { - margin-left: 15px; -} - -#mocha .test { - margin-left: 15px; - overflow: hidden; -} - -#mocha .test.pending:hover h2::after { - content: '(pending)'; - font-family: arial, sans-serif; -} - -#mocha .test.pass.medium .duration { - background: #c09853; -} - -#mocha .test.pass.slow .duration { - background: #b94a48; -} - -#mocha .test.pass::before { - content: 'βœ“'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #00d6b2; -} - -#mocha .test.pass .duration { - font-size: 9px; - margin-left: 5px; - padding: 2px 5px; - color: #fff; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - -o-border-radius: 5px; - border-radius: 5px; -} - -#mocha .test.pass.fast .duration { - display: none; -} - -#mocha .test.pending { - color: #0b97c4; -} - -#mocha .test.pending::before { - content: 'β—¦'; - color: #0b97c4; -} - -#mocha .test.fail { - color: #c00; -} - -#mocha .test.fail pre { - color: black; -} - -#mocha .test.fail::before { - content: 'βœ–'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #c00; -} - -#mocha .test pre.error { - color: #c00; - max-height: 300px; - overflow: auto; -} - -/** - * (1): approximate for browsers not supporting calc - * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) - * ^^ seriously - */ -#mocha .test pre { - display: block; - float: left; - clear: left; - font: 12px/1.5 monaco, monospace; - margin: 5px; - padding: 15px; - border: 1px solid #eee; - max-width: 85%; /*(1)*/ - max-width: calc(100% - 42px); /*(2)*/ - word-wrap: break-word; - border-bottom-color: #ddd; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 3px #eee; - -moz-border-radius: 3px; - -moz-box-shadow: 0 1px 3px #eee; - border-radius: 3px; -} - -#mocha .test h2 { - position: relative; -} - -#mocha .test a.replay { - position: absolute; - top: 3px; - right: 0; - text-decoration: none; - vertical-align: middle; - display: block; - width: 15px; - height: 15px; - line-height: 15px; - text-align: center; - background: #eee; - font-size: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - -webkit-transition: opacity 200ms; - -moz-transition: opacity 200ms; - transition: opacity 200ms; - opacity: 0.3; - color: #888; -} - -#mocha .test:hover a.replay { - opacity: 1; -} - -#mocha-report.pass .test.fail { - display: none; -} - -#mocha-report.fail .test.pass { - display: none; -} - -#mocha-report.pending .test.pass, -#mocha-report.pending .test.fail { - display: none; -} -#mocha-report.pending .test.pass.pending { - display: block; -} - -#mocha-error { - color: #c00; - font-size: 1.5em; - font-weight: 100; - letter-spacing: 1px; -} - -#mocha-stats { - position: fixed; - top: 15px; - right: 10px; - font-size: 12px; - margin: 0; - color: #888; - z-index: 1; -} - -#mocha-stats .progress { - float: right; - padding-top: 0; -} - -#mocha-stats em { - color: black; -} - -#mocha-stats a { - text-decoration: none; - color: inherit; -} - -#mocha-stats a:hover { - border-bottom: 1px solid #eee; -} - -#mocha-stats li { - display: inline-block; - margin: 0 5px; - list-style: none; - padding-top: 11px; -} - -#mocha-stats canvas { - width: 40px; - height: 40px; -} - -#mocha code .comment { color: #ddd; } -#mocha code .init { color: #2f6fad; } -#mocha code .string { color: #5890ad; } -#mocha code .keyword { color: #8a6343; } -#mocha code .number { color: #2f6fad; } - -@media screen and (max-device-width: 480px) { - #mocha { - margin: 60px 0px; - } - - #mocha #stats { - position: absolute; - } -} diff --git a/npm-packages/meteor-promise/test/mocha.js b/npm-packages/meteor-promise/test/mocha.js deleted file mode 100644 index 564a4f3184..0000000000 --- a/npm-packages/meteor-promise/test/mocha.js +++ /dev/null @@ -1,6069 +0,0 @@ -;(function(){ - -// CommonJS require() - -function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - -require.modules = {}; - -require.resolve = function (path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - -require.register = function (path, fn){ - require.modules[path] = fn; - }; - -require.relative = function (parent) { - return function(p){ - if ('.' != p.charAt(0)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - -require.register("browser/debug.js", function(module, exports, require){ -module.exports = function(type){ - return function(){ - } -}; - -}); // module: browser/debug.js - -require.register("browser/diff.js", function(module, exports, require){ -/* See LICENSE file for terms of use */ - -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ -var JsDiff = (function() { - /*jshint maxparams: 5*/ - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - - return n; - } - - var Diff = function(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - }; - Diff.prototype = { - diff: function(oldString, newString) { - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return [{ value: newString }]; - } - if (!newString) { - return [{ value: oldString, removed: true }]; - } - if (!oldString) { - return [{ value: newString, added: true }]; - } - - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); - - var newLen = newString.length, oldLen = oldString.length; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; - - // Seed editLength = 0 - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { - return bestPath[0].components; - } - - for (var editLength = 1; editLength <= maxEditLength; editLength++) { - for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { - var basePath; - var addPath = bestPath[diagonalPath-1], - removePath = bestPath[diagonalPath+1]; - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath-1] = undefined; - } - - var canAdd = addPath && addPath.newPos+1 < newLen; - var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - this.pushComponent(basePath.components, oldString[oldPos], undefined, true); - } else { - basePath = clonePath(addPath); - basePath.newPos++; - this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); - } - - var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); - - if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { - return basePath.components; - } else { - bestPath[diagonalPath] = basePath; - } - } - } - }, - - pushComponent: function(components, value, added, removed) { - var last = components[components.length-1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length-1] = - {value: this.join(last.value, value), added: added, removed: removed }; - } else { - components.push({value: value, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath; - while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { - newPos++; - oldPos++; - - this.pushComponent(basePath.components, newString[newPos], undefined, undefined); - } - basePath.newPos = newPos; - return oldPos; - }, - - equals: function(left, right) { - var reWhitespace = /\S/; - if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { - return true; - } else { - return left === right; - } - }, - join: function(left, right) { - return left + right; - }, - tokenize: function(value) { - return value; - } - }; - - var CharDiff = new Diff(); - - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; - - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - - var LineDiff = new Diff(); - LineDiff.tokenize = function(value) { - return value.split(/^/m); - }; - - return { - Diff: Diff, - - diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, - diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, - diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, - diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, - - diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, - - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - ret.push('Index: ' + fileName); - ret.push('==================================================================='); - ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - - var diff = LineDiff.diff(oldStr, newStr); - if (!diff[diff.length-1].value) { - diff.pop(); // Remove trailing newline add - } - diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier - - function contextLines(lines) { - return lines.map(function(entry) { return ' ' + entry; }); - } - function eofNL(curRange, i, current) { - var last = diff[diff.length-2], - isLast = i === diff.length-2, - isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); - - // Figure out if this is the last line for the given file and missing NL - if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - if (!oldRangeStart) { - var prev = diff[i-1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); - eofNL(curRange, i, current); - - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length-2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) - + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; newRangeStart = 0; curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } - - return ret.join('\n') + '\n'; - }, - - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'); - var diff = []; - var remEOFNL = false, - addEOFNL = false; - - for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { - if(diffstr[i][0] === '@') { - var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - diff.unshift({ - start:meh[3], - oldlength:meh[2], - oldlines:[], - newlength:meh[4], - newlines:[] - }); - } else if(diffstr[i][0] === '+') { - diff[0].newlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '-') { - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === ' ') { - diff[0].newlines.push(diffstr[i].substr(1)); - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '\\') { - if (diffstr[i-1][0] === '+') { - remEOFNL = true; - } else if(diffstr[i-1][0] === '-') { - addEOFNL = true; - } - } - } - - var str = oldStr.split('\n'); - for (var i = diff.length - 1; i >= 0; i--) { - var d = diff[i]; - for (var j = 0; j < d.oldlength; j++) { - if(str[d.start-1+j] !== d.oldlines[j]) { - return false; - } - } - Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); - } - - if (remEOFNL) { - while (!str[str.length-1]) { - str.pop(); - } - } else if (addEOFNL) { - str.push(''); - } - return str.join('\n'); - }, - - convertChangesToXML: function(changes){ - var ret = []; - for ( var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - }, - - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes){ - var ret = [], change; - for ( var i = 0; i < changes.length; i++) { - change = changes[i]; - ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); - } - return ret; - } - }; -})(); - -if (typeof module !== 'undefined') { - module.exports = JsDiff; -} - -}); // module: browser/diff.js - -require.register("browser/escape-string-regexp.js", function(module, exports, require){ -'use strict'; - -var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - -module.exports = function (str) { - if (typeof str !== 'string') { - throw new TypeError('Expected a string'); - } - - return str.replace(matchOperatorsRe, '\\$&'); -}; - -}); // module: browser/escape-string-regexp.js - -require.register("browser/events.js", function(module, exports, require){ -/** - * Module exports. - */ - -exports.EventEmitter = EventEmitter; - -/** - * Check if `obj` is an array. - */ - -function isArray(obj) { - return '[object Array]' == {}.toString.call(obj); -} - -/** - * Event emitter constructor. - * - * @api public - */ - -function EventEmitter(){}; - -/** - * Adds a listener. - * - * @api public - */ - -EventEmitter.prototype.on = function (name, fn) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = fn; - } else if (isArray(this.$events[name])) { - this.$events[name].push(fn); - } else { - this.$events[name] = [this.$events[name], fn]; - } - - return this; -}; - -EventEmitter.prototype.addListener = EventEmitter.prototype.on; - -/** - * Adds a volatile listener. - * - * @api public - */ - -EventEmitter.prototype.once = function (name, fn) { - var self = this; - - function on () { - self.removeListener(name, on); - fn.apply(this, arguments); - }; - - on.listener = fn; - this.on(name, on); - - return this; -}; - -/** - * Removes a listener. - * - * @api public - */ - -EventEmitter.prototype.removeListener = function (name, fn) { - if (this.$events && this.$events[name]) { - var list = this.$events[name]; - - if (isArray(list)) { - var pos = -1; - - for (var i = 0, l = list.length; i < l; i++) { - if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { - pos = i; - break; - } - } - - if (pos < 0) { - return this; - } - - list.splice(pos, 1); - - if (!list.length) { - delete this.$events[name]; - } - } else if (list === fn || (list.listener && list.listener === fn)) { - delete this.$events[name]; - } - } - - return this; -}; - -/** - * Removes all listeners for an event. - * - * @api public - */ - -EventEmitter.prototype.removeAllListeners = function (name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; - -/** - * Gets all listeners for a certain event. - * - * @api public - */ - -EventEmitter.prototype.listeners = function (name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } - - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } - - return this.$events[name]; -}; - -/** - * Emits an event. - * - * @api public - */ - -EventEmitter.prototype.emit = function (name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = [].slice.call(arguments, 1); - - if ('function' == typeof handler) { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } - - return true; -}; - -}); // module: browser/events.js - -require.register("browser/fs.js", function(module, exports, require){ - -}); // module: browser/fs.js - -require.register("browser/glob.js", function(module, exports, require){ - -}); // module: browser/glob.js - -require.register("browser/path.js", function(module, exports, require){ - -}); // module: browser/path.js - -require.register("browser/progress.js", function(module, exports, require){ -/** - * Expose `Progress`. - */ - -module.exports = Progress; - -/** - * Initialize a new `Progress` indicator. - */ - -function Progress() { - this.percent = 0; - this.size(0); - this.fontSize(11); - this.font('helvetica, arial, sans-serif'); -} - -/** - * Set progress size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.size = function(n){ - this._size = n; - return this; -}; - -/** - * Set text to `str`. - * - * @param {String} str - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.text = function(str){ - this._text = str; - return this; -}; - -/** - * Set font size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.fontSize = function(n){ - this._fontSize = n; - return this; -}; - -/** - * Set font `family`. - * - * @param {String} family - * @return {Progress} for chaining - */ - -Progress.prototype.font = function(family){ - this._font = family; - return this; -}; - -/** - * Update percentage to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - */ - -Progress.prototype.update = function(n){ - this.percent = n; - return this; -}; - -/** - * Draw on `ctx`. - * - * @param {CanvasRenderingContext2d} ctx - * @return {Progress} for chaining - */ - -Progress.prototype.draw = function(ctx){ - try { - var percent = Math.min(this.percent, 100) - , size = this._size - , half = size / 2 - , x = half - , y = half - , rad = half - 1 - , fontSize = this._fontSize; - - ctx.font = fontSize + 'px ' + this._font; - - var angle = Math.PI * 2 * (percent / 100); - ctx.clearRect(0, 0, size, size); - - // outer circle - ctx.strokeStyle = '#9f9f9f'; - ctx.beginPath(); - ctx.arc(x, y, rad, 0, angle, false); - ctx.stroke(); - - // inner circle - ctx.strokeStyle = '#eee'; - ctx.beginPath(); - ctx.arc(x, y, rad - 1, 0, angle, true); - ctx.stroke(); - - // text - var text = this._text || (percent | 0) + '%' - , w = ctx.measureText(text).width; - - ctx.fillText( - text - , x - w / 2 + 1 - , y + fontSize / 2 - 1); - } catch (ex) {} //don't fail if we can't render progress - return this; -}; - -}); // module: browser/progress.js - -require.register("browser/tty.js", function(module, exports, require){ -exports.isatty = function(){ - return true; -}; - -exports.getWindowSize = function(){ - if ('innerHeight' in global) { - return [global.innerHeight, global.innerWidth]; - } else { - // In a Web Worker, the DOM Window is not available. - return [640, 480]; - } -}; - -}); // module: browser/tty.js - -require.register("context.js", function(module, exports, require){ -/** - * Expose `Context`. - */ - -module.exports = Context; - -/** - * Initialize a new `Context`. - * - * @api private - */ - -function Context(){} - -/** - * Set or get the context `Runnable` to `runnable`. - * - * @param {Runnable} runnable - * @return {Context} - * @api private - */ - -Context.prototype.runnable = function(runnable){ - if (0 == arguments.length) return this._runnable; - this.test = this._runnable = runnable; - return this; -}; - -/** - * Set test timeout `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.timeout = function(ms){ - if (arguments.length === 0) return this.runnable().timeout(); - this.runnable().timeout(ms); - return this; -}; - -/** - * Set test timeout `enabled`. - * - * @param {Boolean} enabled - * @return {Context} self - * @api private - */ - -Context.prototype.enableTimeouts = function (enabled) { - this.runnable().enableTimeouts(enabled); - return this; -}; - - -/** - * Set test slowness threshold `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.slow = function(ms){ - this.runnable().slow(ms); - return this; -}; - -/** - * Inspect the context void of `._runnable`. - * - * @return {String} - * @api private - */ - -Context.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_runnable' == key) return; - if ('test' == key) return; - return val; - }, 2); -}; - -}); // module: context.js - -require.register("hook.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Hook`. - */ - -module.exports = Hook; - -/** - * Initialize a new `Hook` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Hook(title, fn) { - Runnable.call(this, title, fn); - this.type = 'hook'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -function F(){}; -F.prototype = Runnable.prototype; -Hook.prototype = new F; -Hook.prototype.constructor = Hook; - - -/** - * Get or set the test `err`. - * - * @param {Error} err - * @return {Error} - * @api public - */ - -Hook.prototype.error = function(err){ - if (0 == arguments.length) { - var err = this._error; - this._error = null; - return err; - } - - this._error = err; -}; - -}); // module: hook.js - -require.register("interfaces/bdd.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , utils = require('../utils') - , escapeRe = require('browser/escape-string-regexp'); - -/** - * BDD-style interface: - * - * describe('Array', function(){ - * describe('#indexOf()', function(){ - * it('should return -1 when not present', function(){ - * - * }); - * - * it('should return the index when present', function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before running tests. - */ - - context.before = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.describe = context.context = function(title, fn){ - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending describe. - */ - - context.xdescribe = - context.xcontext = - context.describe.skip = function(title, fn){ - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive suite. - */ - - context.describe.only = function(title, fn){ - var suite = context.describe(title, fn); - mocha.grep(suite.fullTitle()); - return suite; - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.it = context.specify = function(title, fn){ - var suite = suites[0]; - if (suite.pending) fn = null; - var test = new Test(title, fn); - test.file = file; - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.it.only = function(title, fn){ - var test = context.it(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - return test; - }; - - /** - * Pending test case. - */ - - context.xit = - context.xspecify = - context.it.skip = function(title){ - context.it(title); - }; - }); -}; - -}); // module: interfaces/bdd.js - -require.register("interfaces/exports.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * TDD-style interface: - * - * exports.Array = { - * '#indexOf()': { - * 'should return -1 when the value is not present': function(){ - * - * }, - * - * 'should return the correct index when the value is present': function(){ - * - * } - * } - * }; - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('require', visit); - - function visit(obj, file) { - var suite; - for (var key in obj) { - if ('function' == typeof obj[key]) { - var fn = obj[key]; - switch (key) { - case 'before': - suites[0].beforeAll(fn); - break; - case 'after': - suites[0].afterAll(fn); - break; - case 'beforeEach': - suites[0].beforeEach(fn); - break; - case 'afterEach': - suites[0].afterEach(fn); - break; - default: - var test = new Test(key, fn); - test.file = file; - suites[0].addTest(test); - } - } else { - suite = Suite.create(suites[0], key); - suites.unshift(suite); - visit(obj[key]); - suites.shift(); - } - } - } -}; - -}); // module: interfaces/exports.js - -require.register("interfaces/index.js", function(module, exports, require){ -exports.bdd = require('./bdd'); -exports.tdd = require('./tdd'); -exports.qunit = require('./qunit'); -exports.exports = require('./exports'); - -}); // module: interfaces/index.js - -require.register("interfaces/qunit.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , escapeRe = require('browser/escape-string-regexp') - , utils = require('../utils'); - -/** - * QUnit-style interface: - * - * suite('Array'); - * - * test('#length', function(){ - * var arr = [1,2,3]; - * ok(arr.length == 3); - * }); - * - * test('#indexOf()', function(){ - * var arr = [1,2,3]; - * ok(arr.indexOf(1) == 0); - * ok(arr.indexOf(2) == 1); - * ok(arr.indexOf(3) == 2); - * }); - * - * suite('String'); - * - * test('#length', function(){ - * ok('foo'.length == 3); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before running tests. - */ - - context.before = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Describe a "suite" with the given `title`. - */ - - context.suite = function(title){ - if (suites.length > 1) suites.shift(); - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - return suite; - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn){ - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - var test = new Test(title, fn); - test.file = file; - suites[0].addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn){ - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - /** - * Pending test case. - */ - - context.test.skip = function(title){ - context.test(title); - }; - }); -}; - -}); // module: interfaces/qunit.js - -require.register("interfaces/tdd.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , escapeRe = require('browser/escape-string-regexp') - , utils = require('../utils'); - -/** - * TDD-style interface: - * - * suite('Array', function(){ - * suite('#indexOf()', function(){ - * suiteSetup(function(){ - * - * }); - * - * test('should return -1 when not present', function(){ - * - * }); - * - * test('should return the index when present', function(){ - * - * }); - * - * suiteTeardown(function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before each test case. - */ - - context.setup = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.teardown = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Execute before the suite. - */ - - context.suiteSetup = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after the suite. - */ - - context.suiteTeardown = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.suite = function(title, fn){ - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending suite. - */ - context.suite.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn){ - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - var suite = suites[0]; - if (suite.pending) fn = null; - var test = new Test(title, fn); - test.file = file; - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn){ - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - /** - * Pending test case. - */ - - context.test.skip = function(title){ - context.test(title); - }; - }); -}; - -}); // module: interfaces/tdd.js - -require.register("mocha.js", function(module, exports, require){ -/*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var path = require('browser/path') - , escapeRe = require('browser/escape-string-regexp') - , utils = require('./utils'); - -/** - * Expose `Mocha`. - */ - -exports = module.exports = Mocha; - -/** - * To require local UIs and reporters when running in node. - */ - -if (typeof process !== 'undefined' && typeof process.cwd === 'function') { - var join = path.join - , cwd = process.cwd(); - module.paths.push(cwd, join(cwd, 'node_modules')); -} - -/** - * Expose internals. - */ - -exports.utils = utils; -exports.interfaces = require('./interfaces'); -exports.reporters = require('./reporters'); -exports.Runnable = require('./runnable'); -exports.Context = require('./context'); -exports.Runner = require('./runner'); -exports.Suite = require('./suite'); -exports.Hook = require('./hook'); -exports.Test = require('./test'); - -/** - * Return image `name` path. - * - * @param {String} name - * @return {String} - * @api private - */ - -function image(name) { - return __dirname + '/../images/' + name + '.png'; -} - -/** - * Setup mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.spec` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ - -function Mocha(options) { - options = options || {}; - this.files = []; - this.options = options; - this.grep(options.grep); - this.suite = new exports.Suite('', new exports.Context); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter); - if (null != options.timeout) this.timeout(options.timeout); - this.useColors(options.useColors) - if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts); - if (options.slow) this.slow(options.slow); - - this.suite.on('pre-require', function (context) { - exports.afterEach = context.afterEach || context.teardown; - exports.after = context.after || context.suiteTeardown; - exports.beforeEach = context.beforeEach || context.setup; - exports.before = context.before || context.suiteSetup; - exports.describe = context.describe || context.suite; - exports.it = context.it || context.test; - exports.setup = context.setup || context.beforeEach; - exports.suiteSetup = context.suiteSetup || context.before; - exports.suiteTeardown = context.suiteTeardown || context.after; - exports.suite = context.suite || context.describe; - exports.teardown = context.teardown || context.afterEach; - exports.test = context.test || context.it; - }); -} - -/** - * Enable or disable bailing on the first failure. - * - * @param {Boolean} [bail] - * @api public - */ - -Mocha.prototype.bail = function(bail){ - if (0 == arguments.length) bail = true; - this.suite.bail(bail); - return this; -}; - -/** - * Add test `file`. - * - * @param {String} file - * @api public - */ - -Mocha.prototype.addFile = function(file){ - this.files.push(file); - return this; -}; - -/** - * Set reporter to `reporter`, defaults to "spec". - * - * @param {String|Function} reporter name or constructor - * @api public - */ - -Mocha.prototype.reporter = function(reporter){ - if ('function' == typeof reporter) { - this._reporter = reporter; - } else { - reporter = reporter || 'spec'; - var _reporter; - try { _reporter = require('./reporters/' + reporter); } catch (err) {}; - if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; - if (!_reporter && reporter === 'teamcity') - console.warn('The Teamcity reporter was moved to a package named ' + - 'mocha-teamcity-reporter ' + - '(https://npmjs.org/package/mocha-teamcity-reporter).'); - if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); - this._reporter = _reporter; - } - return this; -}; - -/** - * Set test UI `name`, defaults to "bdd". - * - * @param {String} bdd - * @api public - */ - -Mocha.prototype.ui = function(name){ - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) try { this._ui = require(name); } catch (err) {}; - if (!this._ui) throw new Error('invalid interface "' + name + '"'); - this._ui = this._ui(this.suite); - return this; -}; - -/** - * Load registered files. - * - * @api private - */ - -Mocha.prototype.loadFiles = function(fn){ - var self = this; - var suite = this.suite; - var pending = this.files.length; - this.files.forEach(function(file){ - file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); - --pending || (fn && fn()); - }); -}; - -/** - * Enable growl support. - * - * @api private - */ - -Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); - - runner.on('end', function(){ - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha' - , title: 'Passed' - , image: image('ok') - }); - } - }); -}; - -/** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - */ - -Mocha.prototype.grep = function(re){ - this.options.grep = 'string' == typeof re - ? new RegExp(escapeRe(re)) - : re; - return this; -}; - -/** - * Invert `.grep()` matches. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.invert = function(){ - this.options.invert = true; - return this; -}; - -/** - * Ignore global leaks. - * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - */ - -Mocha.prototype.ignoreLeaks = function(ignore){ - this.options.ignoreLeaks = !!ignore; - return this; -}; - -/** - * Enable global leak checking. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.checkLeaks = function(){ - this.options.ignoreLeaks = false; - return this; -}; - -/** - * Enable growl support. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.growl = function(){ - this.options.growl = true; - return this; -}; - -/** - * Ignore `globals` array or string. - * - * @param {Array|String} globals - * @return {Mocha} - * @api public - */ - -Mocha.prototype.globals = function(globals){ - this.options.globals = (this.options.globals || []).concat(globals); - return this; -}; - -/** - * Emit color output. - * - * @param {Boolean} colors - * @return {Mocha} - * @api public - */ - -Mocha.prototype.useColors = function(colors){ - this.options.useColors = arguments.length && colors != undefined - ? colors - : true; - return this; -}; - -/** - * Use inline diffs rather than +/-. - * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - */ - -Mocha.prototype.useInlineDiffs = function(inlineDiffs) { - this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined - ? inlineDiffs - : false; - return this; -}; - -/** - * Set the timeout in milliseconds. - * - * @param {Number} timeout - * @return {Mocha} - * @api public - */ - -Mocha.prototype.timeout = function(timeout){ - this.suite.timeout(timeout); - return this; -}; - -/** - * Set slowness threshold in milliseconds. - * - * @param {Number} slow - * @return {Mocha} - * @api public - */ - -Mocha.prototype.slow = function(slow){ - this.suite.slow(slow); - return this; -}; - -/** - * Enable timeouts. - * - * @param {Boolean} enabled - * @return {Mocha} - * @api public - */ - -Mocha.prototype.enableTimeouts = function(enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined - ? enabled - : true); - return this -}; - -/** - * Makes all tests async (accepting a callback) - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.asyncOnly = function(){ - this.options.asyncOnly = true; - return this; -}; - -/** - * Disable syntax highlighting (in browser). - * @returns {Mocha} - * @api public - */ -Mocha.prototype.noHighlighting = function() { - this.options.noHighlighting = true; - return this; -}; - -/** - * Run tests and invoke `fn()` when complete. - * - * @param {Function} fn - * @return {Runner} - * @api public - */ - -Mocha.prototype.run = function(fn){ - if (this.files.length) this.loadFiles(); - var suite = this.suite; - var options = this.options; - options.files = this.files; - var runner = new exports.Runner(suite); - var reporter = new this._reporter(runner, options); - runner.ignoreLeaks = false !== options.ignoreLeaks; - runner.asyncOnly = options.asyncOnly; - if (options.grep) runner.grep(options.grep, options.invert); - if (options.globals) runner.globals(options.globals); - if (options.growl) this._growl(runner, reporter); - exports.reporters.Base.useColors = options.useColors; - exports.reporters.Base.inlineDiffs = options.useInlineDiffs; - return runner.run(fn); -}; - -}); // module: mocha.js - -require.register("ms.js", function(module, exports, require){ -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} options - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options){ - options = options || {}; - if ('string' == typeof val) return parse(val); - return options['long'] ? longFormat(val) : shortFormat(val); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); - if (!match) return; - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function shortFormat(ms) { - if (ms >= d) return Math.round(ms / d) + 'd'; - if (ms >= h) return Math.round(ms / h) + 'h'; - if (ms >= m) return Math.round(ms / m) + 'm'; - if (ms >= s) return Math.round(ms / s) + 's'; - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function longFormat(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) return; - if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; - return Math.ceil(ms / n) + ' ' + name + 's'; -} - -}); // module: ms.js - -require.register("reporters/base.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var tty = require('browser/tty') - , diff = require('browser/diff') - , ms = require('../ms') - , utils = require('../utils'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Enable coloring by default. - */ - -exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); - -/** - * Inline diffs instead of +/- - */ - -exports.inlineDiffs = false; - -/** - * Default color map. - */ - -exports.colors = { - 'pass': 90 - , 'fail': 31 - , 'bright pass': 92 - , 'bright fail': 91 - , 'bright yellow': 93 - , 'pending': 36 - , 'suite': 0 - , 'error title': 0 - , 'error message': 31 - , 'error stack': 90 - , 'checkmark': 32 - , 'fast': 90 - , 'medium': 33 - , 'slow': 31 - , 'green': 32 - , 'light': 90 - , 'diff gutter': 90 - , 'diff added': 42 - , 'diff removed': 41 -}; - -/** - * Default symbol map. - */ - -exports.symbols = { - ok: 'βœ“', - err: 'βœ–', - dot: 'β€€' -}; - -// With node.js on Windows: use symbols available in terminal default fonts -if ('win32' == process.platform) { - exports.symbols.ok = '\u221A'; - exports.symbols.err = '\u00D7'; - exports.symbols.dot = '.'; -} - -/** - * Color `str` with the given `type`, - * allowing colors to be disabled, - * as well as user-defined color - * schemes. - * - * @param {String} type - * @param {String} str - * @return {String} - * @api private - */ - -var color = exports.color = function(type, str) { - if (!exports.useColors) return str; - return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; - -/** - * Expose term window size, with some - * defaults for when stderr is not a tty. - */ - -exports.window = { - width: isatty - ? process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1] - : 75 -}; - -/** - * Expose some basic cursor interactions - * that are common among reporters. - */ - -exports.cursor = { - hide: function(){ - isatty && process.stdout.write('\u001b[?25l'); - }, - - show: function(){ - isatty && process.stdout.write('\u001b[?25h'); - }, - - deleteLine: function(){ - isatty && process.stdout.write('\u001b[2K'); - }, - - beginningOfLine: function(){ - isatty && process.stdout.write('\u001b[0G'); - }, - - CR: function(){ - if (isatty) { - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } else { - process.stdout.write('\r'); - } - } -}; - -/** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - -exports.list = function(failures){ - console.error(); - failures.forEach(function(test, i){ - // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); - - // msg - var err = test.err - , message = err.message || '' - , stack = err.stack || message - , index = stack.indexOf(message) + message.length - , msg = stack.slice(0, index) - , actual = err.actual - , expected = err.expected - , escape = true; - - // uncaught - if (err.uncaught) { - msg = 'Uncaught ' + msg; - } - - // explicitly show diff - if (err.showDiff && sameType(actual, expected)) { - escape = false; - err.actual = actual = utils.stringify(actual); - err.expected = expected = utils.stringify(expected); - } - - // actual / expected diff - if (err.showDiff && 'string' == typeof actual && 'string' == typeof expected) { - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); - var match = message.match(/^([^:]+): expected/); - msg = '\n ' + color('error message', match ? match[1] : msg); - - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } - } - - // indent stack trace without msg - stack = stack.slice(index ? index + 1 : index) - .replace(/^/gm, ' '); - - console.error(fmt, (i + 1), test.fullTitle(), msg, stack); - }); -}; - -/** - * Initialize a new `Base` reporter. - * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. - * - * @param {Runner} runner - * @api public - */ - -function Base(runner) { - var self = this - , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } - , failures = this.failures = []; - - if (!runner) return; - this.runner = runner; - - runner.stats = stats; - - runner.on('start', function(){ - stats.start = new Date; - }); - - runner.on('suite', function(suite){ - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function(test){ - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test){ - stats.passes = stats.passes || 0; - - var medium = test.slow() / 2; - test.speed = test.duration > test.slow() - ? 'slow' - : test.duration > medium - ? 'medium' - : 'fast'; - - stats.passes++; - }); - - runner.on('fail', function(test, err){ - stats.failures = stats.failures || 0; - stats.failures++; - test.err = err; - failures.push(test); - }); - - runner.on('end', function(){ - stats.end = new Date; - stats.duration = new Date - stats.start; - }); - - runner.on('pending', function(){ - stats.pending++; - }); -} - -/** - * Output common epilogue used by many of - * the bundled reporters. - * - * @api public - */ - -Base.prototype.epilogue = function(){ - var stats = this.stats; - var tests; - var fmt; - - console.log(); - - // passes - fmt = color('bright pass', ' ') - + color('green', ' %d passing') - + color('light', ' (%s)'); - - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d pending'); - - console.log(fmt, stats.pending); - } - - // failures - if (stats.failures) { - fmt = color('fail', ' %d failing'); - - console.error(fmt, - stats.failures); - - Base.list(this.failures); - console.error(); - } - - console.log(); -}; - -/** - * Pad the given `str` to `len`. - * - * @param {String} str - * @param {String} len - * @return {String} - * @api private - */ - -function pad(str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; -} - - -/** - * Returns an inline diff between 2 strings with coloured ANSI output - * - * @param {Error} Error with actual/expected - * @return {String} Diff - * @api private - */ - -function inlineDiff(err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); - - // linenos - var lines = msg.split('\n'); - if (lines.length > 4) { - var width = String(lines.length).length; - msg = lines.map(function(str, i){ - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); - } - - // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; - - // indent - msg = msg.replace(/^/gm, ' '); - return msg; -} - -/** - * Returns a unified diff between 2 strings - * - * @param {Error} Error with actual/expected - * @return {String} Diff - * @api private - */ - -function unifiedDiff(err, escape) { - var indent = ' '; - function cleanUp(line) { - if (escape) { - line = escapeInvisibles(line); - } - if (line[0] === '+') return indent + colorLines('diff added', line); - if (line[0] === '-') return indent + colorLines('diff removed', line); - if (line.match(/\@\@/)) return null; - if (line.match(/\\ No newline/)) return null; - else return indent + line; - } - function notBlank(line) { - return line != null; - } - msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(4); - return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); -} - -/** - * Return a character diff for `err`. - * - * @param {Error} err - * @return {String} - * @api private - */ - -function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str){ - if (str.added) return colorLines('diff added', str.value); - if (str.removed) return colorLines('diff removed', str.value); - return str.value; - }).join(''); -} - -/** - * Returns a string with all invisible characters in plain text - * - * @param {String} line - * @return {String} - * @api private - */ -function escapeInvisibles(line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @param {String} name - * @param {String} str - * @return {String} - * @api private - */ - -function colorLines(name, str) { - return str.split('\n').map(function(str){ - return color(name, str); - }).join('\n'); -} - -/** - * Check that a / b have the same type. - * - * @param {Object} a - * @param {Object} b - * @return {Boolean} - * @api private - */ - -function sameType(a, b) { - a = Object.prototype.toString.call(a); - b = Object.prototype.toString.call(b); - return a == b; -} - -}); // module: reporters/base.js - -require.register("reporters/doc.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Doc`. - */ - -exports = module.exports = Doc; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Doc(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , indents = 2; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('suite', function(suite){ - if (suite.root) return; - ++indents; - console.log('%s
', indent()); - ++indents; - console.log('%s

%s

', indent(), utils.escape(suite.title)); - console.log('%s
', indent()); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - console.log('%s
', indent()); - --indents; - console.log('%s
', indent()); - --indents; - }); - - runner.on('pass', function(test){ - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - }); - - runner.on('fail', function(test, err){ - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - console.log('%s
%s
', indent(), utils.escape(err)); - }); -} - -}); // module: reporters/doc.js - -require.register("reporters/dot.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = Dot; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Dot(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , n = -1; - - runner.on('start', function(){ - process.stdout.write('\n '); - }); - - runner.on('pending', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - process.stdout.write(color('pending', Base.symbols.dot)); - }); - - runner.on('pass', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - if ('slow' == test.speed) { - process.stdout.write(color('bright yellow', Base.symbols.dot)); - } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); - } - }); - - runner.on('fail', function(test, err){ - if (++n % width == 0) process.stdout.write('\n '); - process.stdout.write(color('fail', Base.symbols.dot)); - }); - - runner.on('end', function(){ - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Dot.prototype = new F; -Dot.prototype.constructor = Dot; - - -}); // module: reporters/dot.js - -require.register("reporters/html-cov.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var JSONCov = require('./json-cov') - , fs = require('browser/fs'); - -/** - * Expose `HTMLCov`. - */ - -exports = module.exports = HTMLCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTMLCov(runner) { - var jade = require('jade') - , file = __dirname + '/templates/coverage.jade' - , str = fs.readFileSync(file, 'utf8') - , fn = jade.compile(str, { filename: file }) - , self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function(){ - process.stdout.write(fn({ - cov: self.cov - , coverageClass: coverageClass - })); - }); -} - -/** - * Return coverage class for `n`. - * - * @return {String} - * @api private - */ - -function coverageClass(n) { - if (n >= 75) return 'high'; - if (n >= 50) return 'medium'; - if (n >= 25) return 'low'; - return 'terrible'; -} - -}); // module: reporters/html-cov.js - -require.register("reporters/html.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , Progress = require('../browser/progress') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `HTML`. - */ - -exports = module.exports = HTML; - -/** - * Stats template. - */ - -var statsTemplate = ''; - -/** - * Initialize a new `HTML` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTML(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , stat = fragment(statsTemplate) - , items = stat.getElementsByTagName('li') - , passes = items[1].getElementsByTagName('em')[0] - , passesLink = items[1].getElementsByTagName('a')[0] - , failures = items[2].getElementsByTagName('em')[0] - , failuresLink = items[2].getElementsByTagName('a')[0] - , duration = items[3].getElementsByTagName('em')[0] - , canvas = stat.getElementsByTagName('canvas')[0] - , report = fragment('
    ') - , stack = [report] - , progress - , ctx - , root = document.getElementById('mocha'); - - if (canvas.getContext) { - var ratio = window.devicePixelRatio || 1; - canvas.style.width = canvas.width; - canvas.style.height = canvas.height; - canvas.width *= ratio; - canvas.height *= ratio; - ctx = canvas.getContext('2d'); - ctx.scale(ratio, ratio); - progress = new Progress; - } - - if (!root) return error('#mocha div missing, add it to your document'); - - // pass toggle - on(passesLink, 'click', function(){ - unhide(); - var name = /pass/.test(report.className) ? '' : ' pass'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test pass'); - }); - - // failure toggle - on(failuresLink, 'click', function(){ - unhide(); - var name = /fail/.test(report.className) ? '' : ' fail'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test fail'); - }); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) progress.size(40); - - runner.on('suite', function(suite){ - if (suite.root) return; - - // suite - var url = self.suiteURL(suite); - var el = fragment('
  • %s

  • ', url, escape(suite.title)); - - // container - stack[0].appendChild(el); - stack.unshift(document.createElement('ul')); - el.appendChild(stack[0]); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - stack.shift(); - }); - - runner.on('fail', function(test, err){ - if ('hook' == test.type) runner.emit('test end', test); - }); - - runner.on('test end', function(test){ - // TODO: add to stats - var percent = stats.tests / this.total * 100 | 0; - if (progress) progress.update(percent).draw(ctx); - - // update stats - var ms = new Date - stats.start; - text(passes, stats.passes); - text(failures, stats.failures); - text(duration, (ms / 1000).toFixed(2)); - - // test - if ('passed' == test.state) { - var url = self.testURL(test); - var el = fragment('
  • %e%ems β€£

  • ', test.speed, test.title, test.duration, url); - } else if (test.pending) { - var el = fragment('
  • %e

  • ', test.title); - } else { - var el = fragment('
  • %e β€£

  • ', test.title, encodeURIComponent(test.fullTitle())); - var str = test.err.stack || test.err.toString(); - - // FF / Opera do not add the message - if (!~str.indexOf(test.err.message)) { - str = test.err.message + '\n' + str; - } - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if ('[object Error]' == str) str = test.err.message; - - // Safari doesn't give you a stack. Let's at least provide a source line. - if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { - str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; - } - - el.appendChild(fragment('
    %e
    ', str)); - } - - // toggle code - // TODO: defer - if (!test.pending) { - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function(){ - pre.style.display = 'none' == pre.style.display - ? 'block' - : 'none'; - }); - - var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); - el.appendChild(pre); - pre.style.display = 'none'; - } - - // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) stack[0].appendChild(el); - }); -} - -/** - * Makes a URL, preserving querystring ("search") parameters. - * @param {string} s - * @returns {string} your new URL - */ -var makeUrl = function makeUrl(s) { - var search = window.location.search; - return (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s); -}; - -/** - * Provide suite URL - * - * @param {Object} [suite] - */ -HTML.prototype.suiteURL = function(suite){ - return makeUrl(suite.fullTitle()); -}; - -/** - * Provide test URL - * - * @param {Object} [test] - */ - -HTML.prototype.testURL = function(test){ - return makeUrl(test.fullTitle()); -}; - -/** - * Display error `msg`. - */ - -function error(msg) { - document.body.appendChild(fragment('
    %s
    ', msg)); -} - -/** - * Return a DOM fragment from `html`. - */ - -function fragment(html) { - var args = arguments - , div = document.createElement('div') - , i = 1; - - div.innerHTML = html.replace(/%([se])/g, function(_, type){ - switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); - } - }); - - return div.firstChild; -} - -/** - * Check for suites that do not have elements - * with `classname`, and hide them. - */ - -function hideSuitesWithout(classname) { - var suites = document.getElementsByClassName('suite'); - for (var i = 0; i < suites.length; i++) { - var els = suites[i].getElementsByClassName(classname); - if (0 == els.length) suites[i].className += ' hidden'; - } -} - -/** - * Unhide .hidden suites. - */ - -function unhide() { - var els = document.getElementsByClassName('suite hidden'); - for (var i = 0; i < els.length; ++i) { - els[i].className = els[i].className.replace('suite hidden', 'suite'); - } -} - -/** - * Set `el` text to `str`. - */ - -function text(el, str) { - if (el.textContent) { - el.textContent = str; - } else { - el.innerText = str; - } -} - -/** - * Listen on `event` with callback `fn`. - */ - -function on(el, event, fn) { - if (el.addEventListener) { - el.addEventListener(event, fn, false); - } else { - el.attachEvent('on' + event, fn); - } -} - -}); // module: reporters/html.js - -require.register("reporters/index.js", function(module, exports, require){ -exports.Base = require('./base'); -exports.Dot = require('./dot'); -exports.Doc = require('./doc'); -exports.TAP = require('./tap'); -exports.JSON = require('./json'); -exports.HTML = require('./html'); -exports.List = require('./list'); -exports.Min = require('./min'); -exports.Spec = require('./spec'); -exports.Nyan = require('./nyan'); -exports.XUnit = require('./xunit'); -exports.Markdown = require('./markdown'); -exports.Progress = require('./progress'); -exports.Landing = require('./landing'); -exports.JSONCov = require('./json-cov'); -exports.HTMLCov = require('./html-cov'); -exports.JSONStream = require('./json-stream'); - -}); // module: reporters/index.js - -require.register("reporters/json-cov.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSONCov`. - */ - -exports = module.exports = JSONCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @param {Boolean} output - * @api public - */ - -function JSONCov(runner, output) { - var self = this - , output = 1 == arguments.length ? true : output; - - Base.call(this, runner); - - var tests = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('end', function(){ - var cov = global._$jscoverage || {}; - var result = self.cov = map(cov); - result.stats = self.stats; - result.tests = tests.map(clean); - result.failures = failures.map(clean); - result.passes = passes.map(clean); - if (!output) return; - process.stdout.write(JSON.stringify(result, null, 2 )); - }); -} - -/** - * Map jscoverage data to a JSON structure - * suitable for reporting. - * - * @param {Object} cov - * @return {Object} - * @api private - */ - -function map(cov) { - var ret = { - instrumentation: 'node-jscoverage' - , sloc: 0 - , hits: 0 - , misses: 0 - , coverage: 0 - , files: [] - }; - - for (var filename in cov) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - - ret.files.sort(function(a, b) { - return a.filename.localeCompare(b.filename); - }); - - if (ret.sloc > 0) { - ret.coverage = (ret.hits / ret.sloc) * 100; - } - - return ret; -} - -/** - * Map jscoverage data for a single source file - * to a JSON structure suitable for reporting. - * - * @param {String} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - * @api private - */ - -function coverage(filename, data) { - var ret = { - filename: filename, - coverage: 0, - hits: 0, - misses: 0, - sloc: 0, - source: {} - }; - - data.source.forEach(function(line, num){ - num++; - - if (data[num] === 0) { - ret.misses++; - ret.sloc++; - } else if (data[num] !== undefined) { - ret.hits++; - ret.sloc++; - } - - ret.source[num] = { - source: line - , coverage: data[num] === undefined - ? '' - : data[num] - }; - }); - - ret.coverage = ret.hits / ret.sloc * 100; - - return ret; -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} - -}); // module: reporters/json-cov.js - -require.register("reporters/json-stream.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total; - - runner.on('start', function(){ - console.log(JSON.stringify(['start', { total: total }])); - }); - - runner.on('pass', function(test){ - console.log(JSON.stringify(['pass', clean(test)])); - }); - - runner.on('fail', function(test, err){ - test = clean(test); - test.err = err.message; - console.log(JSON.stringify(['fail', test])); - }); - - runner.on('end', function(){ - process.stdout.write(JSON.stringify(['end', self.stats])); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} - -}); // module: reporters/json-stream.js - -require.register("reporters/json.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `JSON`. - */ - -exports = module.exports = JSONReporter; - -/** - * Initialize a new `JSON` reporter. - * - * @param {Runner} runner - * @api public - */ - -function JSONReporter(runner) { - var self = this; - Base.call(this, runner); - - var tests = [] - , pending = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('pending', function(test){ - pending.push(test); - }); - - runner.on('end', function(){ - var obj = { - stats: self.stats, - tests: tests.map(clean), - pending: pending.map(clean), - failures: failures.map(clean), - passes: passes.map(clean) - }; - - runner.testResults = obj; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title, - fullTitle: test.fullTitle(), - duration: test.duration, - err: errorJSON(test.err || {}) - } -} - -/** - * Transform `error` into a JSON object. - * @param {Error} err - * @return {Object} - */ - -function errorJSON(err) { - var res = {}; - Object.getOwnPropertyNames(err).forEach(function(key) { - res[key] = err[key]; - }, err); - return res; -} - -}); // module: reporters/json.js - -require.register("reporters/landing.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Landing`. - */ - -exports = module.exports = Landing; - -/** - * Airplane color. - */ - -Base.colors.plane = 0; - -/** - * Airplane crash color. - */ - -Base.colors['plane crash'] = 31; - -/** - * Runway color. - */ - -Base.colors.runway = 90; - -/** - * Initialize a new `Landing` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Landing(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , total = runner.total - , stream = process.stdout - , plane = color('plane', '✈') - , crashed = -1 - , n = 0; - - function runway() { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function(){ - stream.write('\n\n\n '); - cursor.hide(); - }); - - runner.on('test end', function(test){ - // check if the plane crashed - var col = -1 == crashed - ? width * ++n / total | 0 - : crashed; - - // show the crash - if ('failed' == test.state) { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\u001b['+(width+1)+'D\u001b[2A'); - stream.write(runway()); - stream.write('\n '); - stream.write(color('runway', Array(col).join('β‹…'))); - stream.write(plane) - stream.write(color('runway', Array(width - col).join('β‹…') + '\n')); - stream.write(runway()); - stream.write('\u001b[0m'); - }); - - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Landing.prototype = new F; -Landing.prototype.constructor = Landing; - - -}); // module: reporters/landing.js - -require.register("reporters/list.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 0; - - runner.on('start', function(){ - console.log(); - }); - - runner.on('test', function(test){ - process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); - }); - - runner.on('pending', function(test){ - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); - console.log(fmt, test.fullTitle()); - }); - - runner.on('pass', function(test){ - var fmt = color('checkmark', ' '+Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -List.prototype = new F; -List.prototype.constructor = List; - - -}); // module: reporters/list.js - -require.register("reporters/markdown.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Markdown`. - */ - -exports = module.exports = Markdown; - -/** - * Initialize a new `Markdown` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Markdown(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , level = 0 - , buf = ''; - - function title(str) { - return Array(level).join('#') + ' ' + str; - } - - function indent() { - return Array(level).join(' '); - } - - function mapTOC(suite, obj) { - var ret = obj; - obj = obj[suite.title] = obj[suite.title] || { suite: suite }; - suite.suites.forEach(function(suite){ - mapTOC(suite, obj); - }); - return ret; - } - - function stringifyTOC(obj, level) { - ++level; - var buf = ''; - var link; - for (var key in obj) { - if ('suite' == key) continue; - if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - if (key) buf += Array(level).join(' ') + link; - buf += stringifyTOC(obj[key], level); - } - --level; - return buf; - } - - function generateTOC(suite) { - var obj = mapTOC(suite, {}); - return stringifyTOC(obj, 0); - } - - generateTOC(runner.suite); - - runner.on('suite', function(suite){ - ++level; - var slug = utils.slug(suite.fullTitle()); - buf += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function(suite){ - --level; - }); - - runner.on('pass', function(test){ - var code = utils.clean(test.fn.toString()); - buf += test.title + '.\n'; - buf += '\n```js\n'; - buf += code + '\n'; - buf += '```\n\n'; - }); - - runner.on('end', function(){ - process.stdout.write('# TOC\n'); - process.stdout.write(generateTOC(runner.suite)); - process.stdout.write(buf); - }); -} - -}); // module: reporters/markdown.js - -require.register("reporters/min.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Min`. - */ - -exports = module.exports = Min; - -/** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @param {Runner} runner - * @api public - */ - -function Min(runner) { - Base.call(this, runner); - - runner.on('start', function(){ - // clear screen - process.stdout.write('\u001b[2J'); - // set cursor position - process.stdout.write('\u001b[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Min.prototype = new F; -Min.prototype.constructor = Min; - - -}); // module: reporters/min.js - -require.register("reporters/nyan.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = NyanCat; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function NyanCat(runner) { - Base.call(this, runner); - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , rainbowColors = this.rainbowColors = self.generateColors() - , colorIndex = this.colorIndex = 0 - , numerOfLines = this.numberOfLines = 4 - , trajectories = this.trajectories = [[], [], [], []] - , nyanCatWidth = this.nyanCatWidth = 11 - , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) - , scoreboardWidth = this.scoreboardWidth = 5 - , tick = this.tick = 0 - , n = 0; - - runner.on('start', function(){ - Base.cursor.hide(); - self.draw(); - }); - - runner.on('pending', function(test){ - self.draw(); - }); - - runner.on('pass', function(test){ - self.draw(); - }); - - runner.on('fail', function(test, err){ - self.draw(); - }); - - runner.on('end', function(){ - Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) write('\n'); - self.epilogue(); - }); -} - -/** - * Draw the nyan cat - * - * @api private - */ - -NyanCat.prototype.draw = function(){ - this.appendRainbow(); - this.drawScoreboard(); - this.drawRainbow(); - this.drawNyanCat(); - this.tick = !this.tick; -}; - -/** - * Draw the "scoreboard" showing the number - * of passes, failures and pending tests. - * - * @api private - */ - -NyanCat.prototype.drawScoreboard = function(){ - var stats = this.stats; - var colors = Base.colors; - - function draw(color, n) { - write(' '); - write('\u001b[' + color + 'm' + n + '\u001b[0m'); - write('\n'); - } - - draw(colors.green, stats.passes); - draw(colors.fail, stats.failures); - draw(colors.pending, stats.pending); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Append the rainbow. - * - * @api private - */ - -NyanCat.prototype.appendRainbow = function(){ - var segment = this.tick ? '_' : '-'; - var rainbowified = this.rainbowify(segment); - - for (var index = 0; index < this.numberOfLines; index++) { - var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); - trajectory.push(rainbowified); - } -}; - -/** - * Draw the rainbow. - * - * @api private - */ - -NyanCat.prototype.drawRainbow = function(){ - var self = this; - - this.trajectories.forEach(function(line, index) { - write('\u001b[' + self.scoreboardWidth + 'C'); - write(line.join('')); - write('\n'); - }); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw the nyan cat - * - * @api private - */ - -NyanCat.prototype.drawNyanCat = function() { - var self = this; - var startWidth = this.scoreboardWidth + this.trajectories[0].length; - var color = '\u001b[' + startWidth + 'C'; - var padding = ''; - - write(color); - write('_,------,'); - write('\n'); - - write(color); - padding = self.tick ? ' ' : ' '; - write('_|' + padding + '/\\_/\\ '); - write('\n'); - - write(color); - padding = self.tick ? '_' : '__'; - var tail = self.tick ? '~' : '^'; - var face; - write(tail + '|' + padding + this.face() + ' '); - write('\n'); - - write(color); - padding = self.tick ? ' ' : ' '; - write(padding + '"" "" '); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw nyan cat face. - * - * @return {String} - * @api private - */ - -NyanCat.prototype.face = function() { - var stats = this.stats; - if (stats.failures) { - return '( x .x)'; - } else if (stats.pending) { - return '( o .o)'; - } else if(stats.passes) { - return '( ^ .^)'; - } else { - return '( - .-)'; - } -}; - -/** - * Move cursor up `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorUp = function(n) { - write('\u001b[' + n + 'A'); -}; - -/** - * Move cursor down `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorDown = function(n) { - write('\u001b[' + n + 'B'); -}; - -/** - * Generate rainbow colors. - * - * @return {Array} - * @api private - */ - -NyanCat.prototype.generateColors = function(){ - var colors = []; - - for (var i = 0; i < (6 * 7); i++) { - var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); - var r = Math.floor(3 * Math.sin(n) + 3); - var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); - var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); - colors.push(36 * r + 6 * g + b + 16); - } - - return colors; -}; - -/** - * Apply rainbow to the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -NyanCat.prototype.rainbowify = function(str){ - var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; - this.colorIndex += 1; - return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; -}; - -/** - * Stdout helper. - */ - -function write(string) { - process.stdout.write(string); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -NyanCat.prototype = new F; -NyanCat.prototype.constructor = NyanCat; - - -}); // module: reporters/nyan.js - -require.register("reporters/progress.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Progress`. - */ - -exports = module.exports = Progress; - -/** - * General progress bar color. - */ - -Base.colors.progress = 90; - -/** - * Initialize a new `Progress` bar test reporter. - * - * @param {Runner} runner - * @param {Object} options - * @api public - */ - -function Progress(runner, options) { - Base.call(this, runner); - - var self = this - , options = options || {} - , stats = this.stats - , width = Base.window.width * .50 | 0 - , total = runner.total - , complete = 0 - , max = Math.max - , lastN = -1; - - // default chars - options.open = options.open || '['; - options.complete = options.complete || 'β–¬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; - - // tests started - runner.on('start', function(){ - console.log(); - cursor.hide(); - }); - - // tests complete - runner.on('test end', function(){ - complete++; - var incomplete = total - complete - , percent = complete / total - , n = width * percent | 0 - , i = width - n; - - if (lastN === n && !options.verbose) { - // Don't re-render the line if it hasn't changed - return; - } - lastN = n; - - cursor.CR(); - process.stdout.write('\u001b[J'); - process.stdout.write(color('progress', ' ' + options.open)); - process.stdout.write(Array(n).join(options.complete)); - process.stdout.write(Array(i).join(options.incomplete)); - process.stdout.write(color('progress', options.close)); - if (options.verbose) { - process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); - } - }); - - // tests are complete, output some stats - // and the failures if any - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Progress.prototype = new F; -Progress.prototype.constructor = Progress; - - -}); // module: reporters/progress.js - -require.register("reporters/spec.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Spec`. - */ - -exports = module.exports = Spec; - -/** - * Initialize a new `Spec` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Spec(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , indents = 0 - , n = 0; - - function indent() { - return Array(indents).join(' ') - } - - runner.on('start', function(){ - console.log(); - }); - - runner.on('suite', function(suite){ - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', function(suite){ - --indents; - if (1 == indents) console.log(); - }); - - runner.on('pending', function(test){ - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function(test){ - if ('fast' == test.speed) { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s '); - cursor.CR(); - console.log(fmt, test.title); - } else { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s ') - + color(test.speed, '(%dms)'); - cursor.CR(); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Spec.prototype = new F; -Spec.prototype.constructor = Spec; - - -}); // module: reporters/spec.js - -require.register("reporters/tap.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `TAP`. - */ - -exports = module.exports = TAP; - -/** - * Initialize a new `TAP` reporter. - * - * @param {Runner} runner - * @api public - */ - -function TAP(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 1 - , passes = 0 - , failures = 0; - - runner.on('start', function(){ - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); - }); - - runner.on('test end', function(){ - ++n; - }); - - runner.on('pending', function(test){ - console.log('ok %d %s # SKIP -', n, title(test)); - }); - - runner.on('pass', function(test){ - passes++; - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function(test, err){ - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); - }); - - runner.on('end', function(){ - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); - }); -} - -/** - * Return a TAP-safe title of `test` - * - * @param {Object} test - * @return {String} - * @api private - */ - -function title(test) { - return test.fullTitle().replace(/#/g, ''); -} - -}); // module: reporters/tap.js - -require.register("reporters/xunit.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @param {Runner} runner - * @api public - */ - -function XUnit(runner) { - Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; - - runner.on('pending', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - tests.push(test); - }); - - runner.on('fail', function(test){ - tests.push(test); - }); - - runner.on('end', function(){ - console.log(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skipped: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: (stats.duration / 1000) || 0 - }, false)); - - tests.forEach(test); - console.log(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -XUnit.prototype = new F; -XUnit.prototype.constructor = XUnit; - - -/** - * Output tag for the given `test.` - */ - -function test(test) { - var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: (test.duration / 1000) || 0 - }; - - if ('failed' == test.state) { - var err = test.err; - console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack)))); - } else if (test.pending) { - console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - console.log(tag('testcase', attrs, true) ); - } -} - -/** - * HTML tag helper. - */ - -function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; - - for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; -} - -}); // module: reporters/xunit.js - -require.register("runnable.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runnable') - , milliseconds = require('./ms'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Object#toString(). - */ - -var toString = Object.prototype.toString; - -/** - * Expose `Runnable`. - */ - -module.exports = Runnable; - -/** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = ! this.async; - this._timeout = 2000; - this._slow = 75; - this._enableTimeouts = true; - this.timedOut = false; - this._trace = new Error('done() called multiple times') -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Runnable.prototype = new F; -Runnable.prototype.constructor = Runnable; - - -/** - * Set & get timeout `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if (ms === 0) this._enableTimeouts = false; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) this.resetTimeout(); - return this; -}; - -/** - * Set & get slow `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._slow = ms; - return this; -}; - -/** - * Set and & get timeout `enabled`. - * - * @param {Boolean} enabled - * @return {Runnable|Boolean} enabled or self - * @api private - */ - -Runnable.prototype.enableTimeouts = function(enabled){ - if (arguments.length === 0) return this._enableTimeouts; - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Runnable.prototype.fullTitle = function(){ - return this.parent.fullTitle() + ' ' + this.title; -}; - -/** - * Clear the timeout. - * - * @api private - */ - -Runnable.prototype.clearTimeout = function(){ - clearTimeout(this.timer); -}; - -/** - * Inspect the runnable void of private properties. - * - * @return {String} - * @api private - */ - -Runnable.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_' == key[0]) return; - if ('parent' == key) return '#'; - if ('ctx' == key) return '#'; - return val; - }, 2); -}; - -/** - * Reset the timeout. - * - * @api private - */ - -Runnable.prototype.resetTimeout = function(){ - var self = this; - var ms = this.timeout() || 1e9; - - if (!this._enableTimeouts) return; - this.clearTimeout(); - this.timer = setTimeout(function(){ - if (!self._enableTimeouts) return; - self.callback(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); -}; - -/** - * Whitelist these globals for this test run - * - * @api private - */ -Runnable.prototype.globals = function(arr){ - var self = this; - this._allowedGlobals = arr; -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runnable.prototype.run = function(fn){ - var self = this - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - // Some times the ctx exists but it is not runnable - if (ctx && ctx.runnable) ctx.runnable(this); - - // called multiple times - function multiple(err) { - if (emitted) return; - emitted = true; - self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); - } - - // finished - function done(err) { - var ms = self.timeout(); - if (self.timedOut) return; - if (finished) return multiple(err || self._trace); - self.clearTimeout(); - self.duration = new Date - start; - finished = true; - if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded'); - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // explicit async with `done` argument - if (this.async) { - this.resetTimeout(); - - try { - this.fn.call(ctx, function(err){ - if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); - if (null != err) { - if (Object.prototype.toString.call(err) === '[object Object]') { - return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err))); - } else { - return done(new Error('done() invoked with non-Error: ' + err)); - } - } - done(); - }); - } catch (err) { - done(err); - } - return; - } - - if (this.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()`')); - } - - // sync or promise-returning - try { - if (this.pending) { - done(); - } else { - callFn(this.fn); - } - } catch (err) { - done(err); - } - - function callFn(fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result - .then(function() { - done() - }, - function(reason) { - done(reason || new Error('Promise rejected with no or falsy reason')) - }); - } else { - done(); - } - } -}; - -}); // module: runnable.js - -require.register("runner.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runner') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys; - -/** - * Non-enumerable globals. - */ - -var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date' -]; - -/** - * Expose `Runner`. - */ - -module.exports = Runner; - -/** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public - */ - -function Runner(suite) { - var self = this; - this._globals = []; - this._abort = false; - this.suite = suite; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function(test){ self.checkGlobals(test); }); - this.on('hook end', function(hook){ self.checkGlobals(hook); }); - this.grep(/.*/); - this.globals(this.globalProps().concat(extraGlobals())); -} - -/** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - * - * @param {Function} fn - * @api private - */ - -Runner.immediately = global.setImmediate || process.nextTick; - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Runner.prototype = new F; -Runner.prototype.constructor = Runner; - - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.grep = function(re, invert){ - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; -}; - -/** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - */ - -Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test){ - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (match) total++; - }); - - return total; -}; - -/** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ - -Runner.prototype.globalProps = function() { - var props = utils.keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~utils.indexOf(props, globals[i])) continue; - props.push(globals[i]); - } - - return props; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; - debug('globals %j', arr); - this._globals = this._globals.concat(arr); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; - var ok = this._globals; - - var globals = this.globalProps(); - var leaks; - - if (test) { - ok = ok.concat(test._allowedGlobals || []); - } - - if(this.prevGlobalsLength == globals.length) return; - this.prevGlobalsLength = globals.length; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } -}; - -/** - * Fail the given `test`. - * - * @param {Test} test - * @param {Error} err - * @api private - */ - -Runner.prototype.fail = function(test, err){ - ++this.failures; - test.state = 'failed'; - - if ('string' == typeof err) { - err = new Error('the string "' + err + '" was thrown, throw an Error :)'); - } - - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @param {Hook} hook - * @param {Error} err - * @api private - */ - -Runner.prototype.failHook = function(hook, err){ - this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @param {String} name - * @param {Function} function - * @api private - */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , self = this - , timer; - - function next(i) { - var hook = hooks[i]; - if (!hook) return fn(); - if (self.failures && suite.bail()) return fn(); - self.currentRunnable = hook; - - hook.ctx.currentTest = self.test; - - self.emit('hook', hook); - - hook.on('error', function(err){ - self.failHook(hook, err); - }); - - hook.run(function(err){ - hook.removeAllListeners('error'); - var testError = hook.error(); - if (testError) self.fail(self.test, testError); - if (err) { - self.failHook(hook, err); - - // stop executing hooks, notify callee of hook err - return fn(err); - } - self.emit('hook end', hook); - delete hook.ctx.currentTest; - next(++i); - }); - } - - Runner.immediately(function(){ - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @param {String} name - * @param {Array} suites - * @param {Function} fn - * @api private - */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err){ - if (err) { - var errSuite = self.suite; - self.suite = orig; - return fn(err, errSuite); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); -}; - -/** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookUp = function(name, fn){ - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); -}; - -/** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookDown = function(name, fn){ - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); -}; - -/** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ - -Runner.prototype.parents = function(){ - var suite = this.suite - , suites = []; - while (suite = suite.parent) suites.push(suite); - return suites; -}; - -/** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTest = function(fn){ - var test = this.test - , self = this; - - if (this.asyncOnly) test.asyncOnly = true; - - try { - test.on('error', function(err){ - self.fail(test, err); - }); - test.run(fn); - } catch (err) { - fn(err); - } -}; - -/** - * Run tests in the given `suite` and invoke - * the callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests.slice() - , test; - - - function hookErr(err, errSuite, after) { - // before/after Each hook for errSuite failed: - var orig = self.suite; - - // for failed 'after each' hook start from errSuite parent, - // otherwise start from errSuite itself - self.suite = after ? errSuite.parent : errSuite; - - if (self.suite) { - // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { - self.suite = orig; - // some hooks may fail even now - if (err2) return hookErr(err2, errSuite2, true); - // report error suite - fn(errSuite); - }); - } else { - // there is no need calling other 'after each' hooks - self.suite = orig; - fn(errSuite); - } - } - - function next(err, errSuite) { - // if we bail after first err - if (self.failures && suite._bail) return fn(); - - if (self._abort) return fn(); - - if (err) return hookErr(err, errSuite, true); - - // next test - test = tests.shift(); - - // all done - if (!test) return fn(); - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (!match) return next(); - - // pending - if (test.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite){ - - if (err) return hookErr(err, errSuite, false); - - self.currentRunnable = self.test; - self.runTest(function(err){ - test = self.test; - - if (err) { - self.fail(test, err); - self.emit('test end', test); - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - next(); -}; - -/** - * Run the given `suite` and invoke the - * callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; - - debug('run suite %s', suite.fullTitle()); - - if (!total) return fn(); - - this.emit('suite', this.suite = suite); - - function next(errSuite) { - if (errSuite) { - // current suite failed on a hook from errSuite - if (errSuite == suite) { - // if errSuite is current suite - // continue to the next sibling suite - return done(); - } else { - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); - } - } - - if (self._abort) return done(); - - var curr = suite.suites[i++]; - if (!curr) return done(); - self.runSuite(curr, next); - } - - function done(errSuite) { - self.suite = suite; - self.hook('afterAll', function(){ - self.emit('suite end', suite); - fn(errSuite); - }); - } - - this.hook('beforeAll', function(err){ - if (err) return done(); - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - -Runner.prototype.uncaught = function(err){ - if (err) { - debug('uncaught exception %s', err !== function () { - return this; - }.call(err) ? err : ( err.message || err )); - } else { - debug('uncaught undefined exception'); - err = new Error('Caught undefined error, did you throw without specifying what?'); - } - err.uncaught = true; - - var runnable = this.currentRunnable; - if (!runnable) return; - - var wasAlreadyDone = runnable.state; - this.fail(runnable, err); - - runnable.clearTimeout(); - - if (wasAlreadyDone) return; - - // recover from test - if ('test' == runnable.type) { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // bail on hooks - this.emit('end'); -}; - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.run = function(fn){ - var self = this - , fn = fn || function(){}; - - function uncaught(err){ - self.uncaught(err); - } - - debug('start'); - - // callback - this.on('end', function(){ - debug('end'); - process.removeListener('uncaughtException', uncaught); - fn(self.failures); - }); - - // run suites - this.emit('start'); - this.runSuite(this.suite, function(){ - debug('finished running'); - self.emit('end'); - }); - - // uncaught exception - process.on('uncaughtException', uncaught); - - return this; -}; - -/** - * Cleanly abort execution - * - * @return {Runner} for chaining - * @api public - */ -Runner.prototype.abort = function(){ - debug('aborting'); - this._abort = true; -}; - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @param {Array} ok - * @param {Array} globals - * @return {Array} - * @api private - */ - -function filterLeaks(ok, globals) { - return filter(globals, function(key){ - // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) return false; - - // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method not init at first - // it is assigned in some seconds - if (global.navigator && /^getInterface/.test(key)) return false; - - // an iframe could be approached by window[iframeIndex] - // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && /^\d+/.test(key)) return false; - - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) return false; - - var matched = filter(ok, function(ok){ - if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); - return key == ok; - }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); - }); -} - -/** - * Array of globals dependent on the environment. - * - * @return {Array} - * @api private - */ - - function extraGlobals() { - if (typeof(process) === 'object' && - typeof(process.version) === 'string') { - - var nodeVersion = process.version.split('.').reduce(function(a, v) { - return a << 8 | v; - }); - - // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } - - return []; - } - -}); // module: runner.js - -require.register("suite.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:suite') - , milliseconds = require('./ms') - , utils = require('./utils') - , Hook = require('./hook'); - -/** - * Expose `Suite`. - */ - -exports = module.exports = Suite; - -/** - * Create a new `Suite` with the given `title` - * and parent `Suite`. When a suite with the - * same title is already present, that suite - * is returned to provide nicer reporter - * and more flexible meta-testing. - * - * @param {Suite} parent - * @param {String} title - * @return {Suite} - * @api public - */ - -exports.create = function(parent, title){ - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - if (parent.pending) suite.pending = true; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; - -/** - * Initialize a new `Suite` with the given - * `title` and `ctx`. - * - * @param {String} title - * @param {Context} ctx - * @api private - */ - -function Suite(title, parentContext) { - this.title = title; - var context = function() {}; - context.prototype = parentContext; - this.ctx = new context(); - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._enableTimeouts = true; - this._slow = 75; - this._bail = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Suite.prototype = new F; -Suite.prototype.constructor = Suite; - - -/** - * Return a clone of this `Suite`. - * - * @return {Suite} - * @api private - */ - -Suite.prototype.clone = function(){ - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if (ms === 0) this._enableTimeouts = false; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Set timeout `enabled`. - * - * @param {Boolean} enabled - * @return {Suite|Boolean} self or enabled - * @api private - */ - -Suite.prototype.enableTimeouts = function(enabled){ - if (arguments.length === 0) return this._enableTimeouts; - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; -}; - -/** - * Set slow `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('slow %d', ms); - this._slow = ms; - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @parma {Boolean} bail - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @param {Suite} suite - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addSuite = function(suite){ - suite.parent = this; - suite.timeout(this.timeout()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @param {Test} test - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addTest = function(test){ - test.parent = this; - test.timeout(this.timeout()); - test.enableTimeouts(this.enableTimeouts()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Suite.prototype.fullTitle = function(){ - if (this.parent) { - var full = this.parent.fullTitle(); - if (full) return full + ' ' + this.title; - } - return this.title; -}; - -/** - * Return the total number of tests. - * - * @return {Number} - * @api public - */ - -Suite.prototype.total = function(){ - return utils.reduce(this.suites, function(sum, suite){ - return sum + suite.total(); - }, 0) + this.tests.length; -}; - -/** - * Iterates through each suite recursively to find - * all tests. Applies a function in the format - * `fn(test)`. - * - * @param {Function} fn - * @return {Suite} - * @api private - */ - -Suite.prototype.eachTest = function(fn){ - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ - suite.eachTest(fn); - }); - return this; -}; - -}); // module: suite.js - -require.register("test.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -function F(){}; -F.prototype = Runnable.prototype; -Test.prototype = new F; -Test.prototype.constructor = Test; - - -}); // module: test.js - -require.register("utils.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var fs = require('browser/fs') - , path = require('browser/path') - , basename = path.basename - , exists = fs.existsSync || path.existsSync - , glob = require('browser/glob') - , join = path.join - , debug = require('browser/debug')('mocha:watch'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -/** - * Escape special characters in the given string of html. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.forEach = function(arr, fn, scope){ - for (var i = 0, l = arr.length; i < l; i++) - fn.call(scope, arr[i], i); -}; - -/** - * Array#map (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.map = function(arr, fn, scope){ - var result = []; - for (var i = 0, l = arr.length; i < l; i++) - result.push(fn.call(scope, arr[i], i)); - return result; -}; - -/** - * Array#indexOf (<=IE8) - * - * @parma {Array} arr - * @param {Object} obj to find index of - * @param {Number} start - * @api private - */ - -exports.indexOf = function(arr, obj, start){ - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) - return i; - } - return -1; -}; - -/** - * Array#reduce (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} initial value - * @api private - */ - -exports.reduce = function(arr, fn, val){ - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @api private - */ - -exports.filter = function(arr, fn){ - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) ret.push(val); - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @param {Object} obj - * @return {Array} keys - * @api private - */ - -exports.keys = Object.keys || function(obj) { - var keys = [] - , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; -}; - -/** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @param {Array} files - * @param {Function} fn - * @api private - */ - -exports.watch = function(files, fn){ - var options = { interval: 100 }; - files.forEach(function(file){ - debug('file %s', file); - fs.watchFile(file, options, function(curr, prev){ - if (prev.mtime < curr.mtime) fn(file); - }); - }); -}; - -/** - * Ignored files. - */ - -function ignored(path){ - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @return {Array} - * @api private - */ - -exports.files = function(dir, ext, ret){ - ret = ret || []; - ext = ext || ['js']; - - var re = new RegExp('\\.(' + ext.join('|') + ')$'); - - fs.readdirSync(dir) - .filter(ignored) - .forEach(function(path){ - path = join(dir, path); - if (fs.statSync(path).isDirectory()) { - exports.files(path, ext, ret); - } else if (path.match(re)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.slug = function(str){ - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, - * and re-indent for pre whitespace. - */ - -exports.clean = function(str) { - str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') - .replace(/^function *\(.*\) *{|\(.*\) *=> *{?/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length - , tabs = str.match(/^\n?(\t*)/)[1].length - , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); - - str = str.replace(re, ''); - - return exports.trim(str); -}; - -/** - * Trim the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.trim = function(str){ - return str.replace(/^\s+|\s+$/g, ''); -}; - -/** - * Parse the given `qs`. - * - * @param {String} qs - * @return {Object} - * @api private - */ - -exports.parseQuery = function(qs){ - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ - var i = pair.indexOf('=') - , key = pair.slice(0, i) - , val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); -}; - -/** - * Highlight the given string of `js`. - * - * @param {String} js - * @return {String} - * @api private - */ - -function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') -} - -/** - * Highlight the contents of tag `name`. - * - * @param {String} name - * @api private - */ - -exports.highlightTags = function(name) { - var code = document.getElementById('mocha').getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } -}; - - -/** - * Stringify `obj`. - * - * @param {Object} obj - * @return {String} - * @api private - */ - -exports.stringify = function(obj) { - if (obj instanceof RegExp) return obj.toString(); - return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1'); -}; - -/** - * Return a new object that has the keys in sorted order. - * @param {Object} obj - * @param {Array} [stack] - * @return {Object} - * @api private - */ - -exports.canonicalize = function(obj, stack) { - stack = stack || []; - - if (exports.indexOf(stack, obj) !== -1) return '[Circular]'; - - var canonicalizedObj; - - if ({}.toString.call(obj) === '[object Array]') { - stack.push(obj); - canonicalizedObj = exports.map(obj, function (item) { - return exports.canonicalize(item, stack); - }); - stack.pop(); - } else if (typeof obj === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - exports.forEach(exports.keys(obj).sort(), function (key) { - canonicalizedObj[key] = exports.canonicalize(obj[key], stack); - }); - stack.pop(); - } else { - canonicalizedObj = obj; - } - - return canonicalizedObj; - }; - -/** - * Lookup file names at the given `path`. - */ -exports.lookupFiles = function lookupFiles(path, extensions, recursive) { - var files = []; - var re = new RegExp('\\.(' + extensions.join('|') + ')$'); - - if (!exists(path)) { - if (exists(path + '.js')) { - path += '.js'; - } else { - files = glob.sync(path); - if (!files.length) throw new Error("cannot resolve path (or pattern) '" + path + "'"); - return files; - } - } - - try { - var stat = fs.statSync(path); - if (stat.isFile()) return path; - } - catch (ignored) { - return; - } - - fs.readdirSync(path).forEach(function(file){ - file = join(path, file); - try { - var stat = fs.statSync(file); - if (stat.isDirectory()) { - if (recursive) { - files = files.concat(lookupFiles(file, extensions, recursive)); - } - return; - } - } - catch (ignored) { - return; - } - if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return; - files.push(file); - }); - - return files; -}; - -}); // module: utils.js -// The global object is "self" in Web Workers. -var global = (function() { return this; })(); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; - -/** - * Node shims. - * - * These are meant only to allow - * mocha.js to run untouched, not - * to allow running node code in - * the browser. - */ - -var process = {}; -process.exit = function(status){}; -process.stdout = {}; - -var uncaughtExceptionHandlers = []; - -var originalOnerrorHandler = global.onerror; - -/** - * Remove uncaughtException listener. - * Revert to original onerror handler if previously defined. - */ - -process.removeListener = function(e, fn){ - if ('uncaughtException' == e) { - if (originalOnerrorHandler) { - global.onerror = originalOnerrorHandler; - } else { - global.onerror = function() {}; - } - var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); - if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } - } -}; - -/** - * Implements uncaughtException listener. - */ - -process.on = function(e, fn){ - if ('uncaughtException' == e) { - global.onerror = function(err, url, line){ - fn(new Error(err + ' (' + url + ':' + line + ')')); - return true; - }; - uncaughtExceptionHandlers.push(fn); - } -}; - -/** - * Expose mocha. - */ - -var Mocha = global.Mocha = require('mocha'), - mocha = global.mocha = new Mocha({ reporter: 'html' }); - -// The BDD UI is registered by default, but no UI will be functional in the -// browser without an explicit call to the overridden `mocha.ui` (see below). -// Ensure that this default UI does not expose its methods to the global scope. -mocha.suite.removeAllListeners('pre-require'); - -var immediateQueue = [] - , immediateTimeout; - -function timeslice() { - var immediateStart = new Date().getTime(); - while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { - immediateQueue.shift()(); - } - if (immediateQueue.length) { - immediateTimeout = setTimeout(timeslice, 0); - } else { - immediateTimeout = null; - } -} - -/** - * High-performance override of Runner.immediately. - */ - -Mocha.Runner.immediately = function(callback) { - immediateQueue.push(callback); - if (!immediateTimeout) { - immediateTimeout = setTimeout(timeslice, 0); - } -}; - -/** - * Function to allow assertion libraries to throw errors directly into mocha. - * This is useful when running tests in a browser because window.onerror will - * only receive the 'message' attribute of the Error. - */ -mocha.throwError = function(err) { - Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { - fn(err); - }); - throw err; -}; - -/** - * Override ui to ensure that the ui functions are initialized. - * Normally this would happen in Mocha.prototype.loadFiles. - */ - -mocha.ui = function(ui){ - Mocha.prototype.ui.call(this, ui); - this.suite.emit('pre-require', global, null, this); - return this; -}; - -/** - * Setup mocha with the given setting options. - */ - -mocha.setup = function(opts){ - if ('string' == typeof opts) opts = { ui: opts }; - for (var opt in opts) this[opt](opts[opt]); - return this; -}; - -/** - * Run mocha, returning the Runner. - */ - -mocha.run = function(fn){ - var options = mocha.options; - mocha.globals('location'); - - var query = Mocha.utils.parseQuery(global.location.search || ''); - if (query.grep) mocha.grep(query.grep); - if (query.invert) mocha.invert(); - - return Mocha.prototype.run.call(mocha, function(err){ - // The DOM Document is not available in Web Workers. - var document = global.document; - if (document && document.getElementById('mocha') && options.noHighlighting !== true) { - Mocha.utils.highlightTags('code'); - } - if (fn) fn(err); - }); -}; - -/** - * Expose the process shim. - */ - -Mocha.process = process; -})(); diff --git a/npm-packages/meteor-promise/test/run.sh b/npm-packages/meteor-promise/test/run.sh deleted file mode 100755 index bfa4a9fcaf..0000000000 --- a/npm-packages/meteor-promise/test/run.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u - -mocha \ - --harmony \ - --reporter spec \ - --full-trace \ - test/tests.js - -USE_GLOBAL_PROMISE=1 \ -mocha \ - --harmony \ - --reporter spec \ - --full-trace \ - test/tests.js diff --git a/npm-packages/meteor-promise/test/tests.js b/npm-packages/meteor-promise/test/tests.js deleted file mode 100644 index 5fbb872121..0000000000 --- a/npm-packages/meteor-promise/test/tests.js +++ /dev/null @@ -1,411 +0,0 @@ -var assert = require("assert"); -var Fiber = require("fibers"); -var Future = require("fibers/future"); -var Promise = process.env.USE_GLOBAL_PROMISE - ? global.Promise - : require("promise/lib/es6-extensions"); - -if (! Promise) { - process.exit(0); -} - -require("../promise_server.js").makeCompatible(Promise, Fiber); - -function wait(ms) { - var self = this; - var args = Array.prototype.slice.call(arguments, 1); - - return new Promise(function (resolve) { - setTimeout(function () { - resolve.apply(self, args); - }, ms); - }); -} - -describe("Promise.await", function () { - it("should work inside an existing Fiber", Promise.async(function () { - assert.strictEqual(Promise.await(42), 42); - assert.strictEqual(Promise.await(Promise.resolve("asdf")), "asdf"); - - var obj = {}; - assert.strictEqual(Promise.resolve(obj).await(), obj); - })); - - it("should not switch Fibers", Promise.async(function () { - var originalFiber = Fiber.current; - assert.ok(originalFiber instanceof Fiber); - var promise = Promise.resolve(0); - - for (var i = 0; i < 100; ++i) { - promise = promise.then(function (count) { - assert.ok(Fiber.current instanceof Fiber); - assert.notStrictEqual(Fiber.current, originalFiber); - return count + 1; - }); - } - - assert.strictEqual(Promise.await(promise), 100); - assert.strictEqual(Fiber.current, originalFiber); - })); - - it("should throw rejection reasons", Promise.async(function () { - var reason = new Error("reason"); - try { - Promise.await(Promise.reject(reason)); - assert.ok(false, "should have thrown"); - } catch (error) { - assert.strictEqual(error, reason); - } - })); - - it("should not hang when inner promise returned from callback", Promise.async(function () { - function go(n) { - return n === 0 - ? Promise.resolve("done") - : wait(0, n - 1).then(go); - } - - var results = Promise.all([ - wait(50, "a").then(function (a) { - return wait(100, a + "b").then(function (ab) { - return wait(2, ab + "c"); - }); - }), - go(10), - go(20) - ]).await(); - - assert.deepEqual(results, [ - "abc", - "done", - "done" - ]); - })); -}); - -describe("Promise.awaitAll", function () { - it("should await multiple promises", Promise.async(function () { - assert.deepEqual(Promise.awaitAll([ - 123, - Promise.resolve("oyez"), - new Promise(function (resolve) { - process.nextTick(function () { - resolve("resolved"); - }); - }) - ]), [123, "oyez", "resolved"]); - })); -}); - -describe("Promise.async", function () { - it("should create a new Fiber", function () { - var self = this; - - var parent = Promise.async(function () { - var parentFiber = Fiber.current; - assert.ok(parentFiber instanceof Fiber); - - var childFibers = []; - var child = Promise.async(function (arg) { - assert.strictEqual(this, self); - - var childFiber = Fiber.current; - assert.ok(childFiber instanceof Fiber); - assert.notStrictEqual(childFiber, parentFiber); - - assert.strictEqual(childFibers.indexOf(childFiber), -1); - childFibers.push(childFiber); - - return Promise.await(arg); - }); - - return Promise.all([ - child.call(this, 1), - child.call(this, 2), - child.call(this, 3) - ]); - }); - - return parent.call(this).then(function (results) { - assert.deepEqual(results, [1, 2, 3]); - }); - }); - - it("should be able to reuse Fiber.current", function () { - var self = this; - - var parent = Promise.async(function () { - var parentFiber = Fiber.current; - assert.ok(parentFiber instanceof Fiber); - - var childFibers = []; - var child = Promise.async(function (arg) { - assert.strictEqual(this, self); - - var childFiber = Fiber.current; - assert.ok(childFiber instanceof Fiber); - assert.strictEqual(childFiber, parentFiber); - - childFibers.forEach(function (otherChildFiber) { - assert.strictEqual(childFiber, otherChildFiber); - }); - childFibers.push(childFiber); - - return Promise.await(arg); - }, true); - - return Promise.all([ - child.call(this, 1), - child.call(this, 2), - child.call(this, 3) - ]); - }); - - return parent.call(this).then(function (results) { - assert.deepEqual(results, [1, 2, 3]); - }); - }); -}); - -describe("Promise.then callbacks", function () { - it("should always run in a fiber", Promise.async(function () { - var parentFiber = Fiber.current; - assert.ok(parentFiber instanceof Fiber); - - var dynamics = { user: "ben" }; - parentFiber._meteorDynamics = dynamics; - - function checkCallbackFiber() { - assert.ok(Fiber.current instanceof Fiber); - assert.deepEqual(Fiber.current._meteorDynamics, dynamics); - } - - return Promise.resolve("result").then(function (result) { - assert.strictEqual(result, "result"); - checkCallbackFiber(); - throw new Error("friendly exception"); - }).catch(function (error) { - assert.strictEqual(error.message, "friendly exception"); - checkCallbackFiber(); - }); - })); - - it("should not double-wrap callbacks", Promise.async(function () { - // Consume all fibers currently in the pool, so that we can detect how many - // new fibers are created after that point. - var done = new Future(); - var origCount = Fiber.fibersCreated; - - while (Fiber.fibersCreated == origCount) { - // Force creation of a new fiber that blocks until we're done. - var ready = new Future(); - Promise.asyncApply(function () { - ready.return(); - done.wait(); - }); - ready.wait(); // Make sure fiber is running before we continue. - } - - // OK, we're now in a situation where a Promise.then() should create - // *one* new fiber. - var baseCount = Fiber.fibersCreated; - - // Create some named no-op promises and callbacks. I'm assigning names - // to these so that the comments below are easier to read. - var promise1 = Promise.resolve(); - var promise2 = Promise.resolve(); - var returnPromise2 = function () { return promise2; }; - var cb = function () {}; - - // Make sure this didn't create any fibers. - assert.strictEqual(baseCount, Fiber.fibersCreated); - - // This should create one fiber, and return it to the pool. - // Note that you can remove these two lines and the test still works and - // tests the right thing. This is just checking my assumptions. - promise1.then(returnPromise2).await(); - assert.strictEqual(baseCount + 1, Fiber.fibersCreated); - - // This should NOT create a another fiber. It should reuse the fiber - // created by the above block. However, if callback double-wrapping - // is not prevented, then cb will end up being wrapped *twice*, and - // thus *two* fibers will be created at the same time. - // - // What happens is: - // * .then(cb) wraps cb (let's call the wrapped version wcb) and passes - // it on to the Promise implementation. - // * On next tick, promise1 "completes", so returnPromise2() is called. - // * Since it returns a promise (promise2), the Promise implementation - // calls promise2.then(wcb) -- forwarding the callback on to the next - // promise in the chain. - // * Our monkey-patched .then() is used here. If we don't detect that - // the callback is already wrapped, we'll end up wrapping it again! - var promise3 = promise1.then(returnPromise2); - promise3.then(cb).await(); - - // If we double-wrapped the callback, then fibersCreated will end up - // being baseCount + 2 instead of baseCount + 1. - assert.strictEqual(baseCount + 1, Fiber.fibersCreated); - - done.return(); - })); -}); - -describe("FiberPool", function () { - it("should still work when the target size is 1 or 0", function () { - var fiberPool = require("../fiber_pool.js").makePool(); - - return fiberPool.setTargetFiberCount(1).run({ - callback: function () { - assert.ok(Fiber.current instanceof Fiber); - return Fiber.current; - } - }, Promise).then(function (firstFiber) { - return fiberPool.run({ - callback: function () { - assert.ok(Fiber.current instanceof Fiber); - assert.strictEqual(Fiber.current, firstFiber); - fiberPool.drain(); - return Fiber.current; - } - }, Promise); - }).then(function (secondFiber) { - return fiberPool.run({ - callback: function () { - assert.ok(Fiber.current instanceof Fiber); - assert.notStrictEqual(Fiber.current, secondFiber); - } - }, Promise); - }); - }); - - it("should ignore bogus fiber.run arguments", function () { - var fiberPool = require("../fiber_pool.js").makePool(); - var fiber; - - return fiberPool.setTargetFiberCount(1).run({ - callback() { - fiber = Fiber.current; - } - }, Promise).then(() => { - assert.ok(Fiber.current instanceof Fiber); - assert.notStrictEqual(Fiber.current, fiber); - fiber.run("bogus"); - }); - }); -}); - -describe("dynamic environment", function () { - it("should be restored to cloned values", Promise.async(function () { - var fiber = Fiber.current; - assert.ok(fiber instanceof Fiber); - - var asdf = fiber._asdf = [1, /* hole */, 3]; - var expected = new Error("expected"); - var promise = Promise.resolve(asdf).then(function (asdf) { - var fiber = Fiber.current; - assert.notStrictEqual(asdf, fiber._asdf); - assert.deepEqual(asdf, fiber._asdf); - fiber._asdf.push(4); - throw expected; - }).catch(function (error) { - assert.strictEqual(error, expected); - var fiber = Fiber.current; - assert.notStrictEqual(asdf, fiber._asdf); - assert.deepEqual(asdf, fiber._asdf); - assert.strictEqual(asdf.length, 3); - }); - - // Own properties should have been cloned when .then and .catch were - // called, so deleting this property here should have no impact on the - // behavior of the callbacks. - delete fiber._asdf; - - return promise; - })); -}); - -describe("uncaught exceptions", function () { - it("should be emitted via process.domain", function (done) { - var domain = require("domain").create(); - var expected = new Error("expected"); - var fiber = new Fiber(function () { - Promise.await("asdf"); - throw expected; - }); - - function onError(error) { - assert.strictEqual(error, expected); - done(); - } - - domain.on("error", onError); - - domain.run(function () { - fiber.run(); - }); - }); -}); - -describe("promise_client.js", function () { - it("should use Meteor.bindEnvironment", function () { - var savedMeteor = global.Meteor; - var calledBindEnvironment = false; - var calledBoundFunction = false; - - global.Meteor = { - bindEnvironment: function (handler) { - calledBindEnvironment = true; - return function () { - calledBoundFunction = true; - return handler.apply(this, arguments); - }; - } - }; - - var Promise = require("promise"); - var desc = Object.getOwnPropertyDescriptor(Promise.prototype, "then"); - desc.writable = true; - Object.defineProperty(Promise.prototype, "then", desc); - require("../promise_client.js").makeCompatible(Promise); - - var p = Promise.resolve(1234).then(function (value) { - assert.strictEqual(value, 1234); - assert.strictEqual(calledBindEnvironment, true); - assert.strictEqual(calledBoundFunction, true); - global.Meteor = savedMeteor; - }); - - assert.strictEqual(calledBindEnvironment, true); - assert.strictEqual(calledBoundFunction, false); - - return p; - }); -}); - -describe("stack traces", function () { - it("should reflect awaiting context(s) as well", Promise.async(function test() { - function inner() { - throw new Error("oyez"); - } - - var middle = Promise.async(function middle() { - return Promise.await(new Promise(inner)); - }); - - var outer = Promise.async(function outer() { - return Promise.await(middle()); - }); - - return outer().catch(function (error) { - assert.strictEqual(error.message, "oyez"); - - var sections = error.stack.split("=> awaited here:"); - assert.strictEqual(sections.length, 3); - - assert.notStrictEqual(sections[0].indexOf("at inner"), -1); - assert.notStrictEqual(sections[1].indexOf("at middle"), -1); - assert.notStrictEqual(sections[2].indexOf("at outer"), -1); - }); - })); -}); diff --git a/package-lock.json b/package-lock.json index bcbccd466f..ea3a5d33e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4652 +1,5040 @@ { "name": "meteor", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.52.tgz", - "integrity": "sha1-GSSDv6DR5GfBAVccIQKcy3SvKAE=", - "dev": true, - "requires": { - "@babel/highlight": "7.0.0-beta.52" + "packages": { + "": { + "name": "meteor", + "version": "0.0.1", + "license": "MIT", + "devDependencies": { + "@babel/core": "^7.21.3", + "@babel/eslint-parser": "^7.21.3", + "@babel/eslint-plugin": "^7.19.1", + "@babel/preset-react": "^7.18.6", + "@types/lodash.isempty": "^4.4.9", + "@types/node": "^18.16.18", + "@types/sockjs": "^0.3.36", + "@types/sockjs-client": "^1.5.4", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-vazco": "^7.1.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "prettier": "^2.8.8", + "typescript": "^5.4.5" } }, - "@babel/generator": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.52.tgz", - "integrity": "sha1-JpaPEvrYGM2XTISbKGtDfh6MzZE=", + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.52", - "jsesc": "^2.5.1", - "lodash": "^4.17.5", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-function-name": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.52.tgz", - "integrity": "sha1-qGelj/VxsldysteZsyhmBYVzxFA=", + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dev": true, - "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.52", - "@babel/template": "7.0.0-beta.52", - "@babel/types": "7.0.0-beta.52" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.52.tgz", - "integrity": "sha1-HAzaWOC3X0XpLq+9j+GJpO7pK3Q=", + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.52" + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.52.tgz", - "integrity": "sha1-SqxPMOpjhK82duBLUkZydjLkYN8=", + "node_modules/@babel/core": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.52" + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.52.tgz", - "integrity": "sha1-7ySTFDLwYVXnvDnNuKaze0oos9A=", + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/parser": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.52.tgz", - "integrity": "sha1-TpNbYs2b+HK9N7zx9j2C/nsCN6I=", - "dev": true - }, - "@babel/runtime": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.13.tgz", - "integrity": "sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==", + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/runtime-corejs3": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.13.tgz", - "integrity": "sha512-8fSpqYRETHATtNitsCXq8QQbKJP31/KnDl2Wz2Vtui9nKzjss2ysuZtyVsWjBtvkeEFo346gkwjYPab1hvrXkQ==", + "node_modules/@babel/core/node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/template": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.52.tgz", - "integrity": "sha1-ROGPrDglH1f5JRHWdI8JWrAvmW4=", + "node_modules/@babel/core/node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.52", - "@babel/parser": "7.0.0-beta.52", - "@babel/types": "7.0.0-beta.52", - "lodash": "^4.17.5" + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/traverse": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.52.tgz", - "integrity": "sha1-m4uplPcmTZhHhYrS/uzCc4xeLvM=", + "node_modules/@babel/core/node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.52", - "@babel/generator": "7.0.0-beta.52", - "@babel/helper-function-name": "7.0.0-beta.52", - "@babel/helper-split-export-declaration": "7.0.0-beta.52", - "@babel/parser": "7.0.0-beta.52", - "@babel/types": "7.0.0-beta.52", - "debug": "^3.1.0", - "globals": "^11.1.0", - "invariant": "^2.2.0", - "lodash": "^4.17.5" + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/types": { - "version": "7.0.0-beta.52", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.52.tgz", - "integrity": "sha1-o+ViCxU0slOlCrzyIitSDiOxbaI=", + "node_modules/@babel/core/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.5", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/traverse": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@meteorjs/eslint-config-meteor": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@meteorjs/eslint-config-meteor/-/eslint-config-meteor-1.0.5.tgz", - "integrity": "sha1-iMFN+7Si+iJY//SInM2N3Q7MsEs=", + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "@quave/eslint-config-quave": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@quave/eslint-config-quave/-/eslint-config-quave-1.0.3.tgz", - "integrity": "sha512-acFcwHYu22Q900BHMjswu/qZDDWgtXGlXSJljSoohanG2iyOcpSKDo5KwR1MUAI3HelGfvTNGlcdrYS4veFWfQ==", + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "requires": { - "@meteorjs/eslint-config-meteor": "^1.0.5", - "babel-eslint": "^9.0.0-beta.3", - "eslint": "^5.6.0", - "eslint-config-airbnb": "^17.1.0", - "eslint-config-prettier": "^3.1.0", - "eslint-import-resolver-meteor": "^0.4.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-jest": "^21.26.2", - "eslint-plugin-jsx-a11y": "^6.1.1", - "eslint-plugin-meteor": "^5.1.0", - "eslint-plugin-react": "^7.11.1", - "eslint-plugin-react-hooks": "^3.0.0", - "husky": "^3.1.0", - "lint-staged": "7.3.0", - "prettier-eslint": "^8.8.2" + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "@samverschueren/stream-to-observable": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", - "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/eslint-parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz", + "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==", "dev": true, - "requires": { - "any-observable": "^0.3.0" + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" } }, - "@types/json5": { + "node_modules/@babel/eslint-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz", + "integrity": "sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/traverse": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helpers/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/@babel/helpers/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx/node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "@types/node": { - "version": "14.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.6.tgz", - "integrity": "sha512-iBxsxU7eswQDGhlr3AiamBxOssaYxbM+NKXVil8jg9yFXvrfEFbDumLD/2dMTB+zYyg7w+Xjt8yuxfdbUHAtcQ==", + "node_modules/@types/lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==", "dev": true }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "node_modules/@types/lodash.isempty": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@types/lodash.isempty/-/lodash.isempty-4.4.9.tgz", + "integrity": "sha512-DPSFfnT2JmZiAWNWOU8IRZws/Ha6zyGF5m06TydfsY+0dVoQqby2J61Na2QU4YtwiZ+moC6cJS6zWYBJq4wBVw==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/sockjs-client": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/sockjs-client/-/sockjs-client-1.5.4.tgz", + "integrity": "sha512-zk+uFZeWyvJ5ZFkLIwoGA/DfJ+pYzcZ8eH4H/EILCm2OBZyHH6Hkdna1/UWL/CFruh5wj6ES7g75SvUB0VsH5w==", "dev": true }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "ajv": { + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "requires": { + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { + "dependencies": { "color-convert": "^1.9.0" - } - }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", - "is-string": "^1.0.5" - } - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "axe-core": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.2.tgz", - "integrity": "sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==", - "dev": true - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "engines": { + "node": ">=4" } }, - "babel-eslint": { - "version": "9.0.0-beta.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-9.0.0-beta.3.tgz", - "integrity": "sha512-niiSqeVysX9Hr3KjCzqz8XEQmVKeqQV7Xf2uaOyCMl6Z88IyE3k3ofXBMcEO0B8ATFHgc73Dfyx9hUaddDplag==", - "dev": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.52", - "@babel/parser": "7.0.0-beta.52", - "@babel/traverse": "7.0.0-beta.52", - "@babel/types": "7.0.0-beta.52", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "dequal": "^2.0.3" } }, - "brace-expansion": { + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" + "fill-range": "^7.1.1" }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } + "engines": { + "node": ">=8" } }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, - "requires": { - "caller-callsite": "^2.0.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "callsites": { + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "chalk": { + "node_modules/caniuse-lite": { + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "engines": { + "node": ">=4" } }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { + "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "requires": { + "dependencies": { "color-name": "1.1.3" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "common-tags": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", - "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "confusing-browser-globals": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", - "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true - }, - "core-js-pure": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.3.tgz", - "integrity": "sha512-V5qQZVAr9K0xu7jXg1M7qTEwuxUgqr7dUOezGaNa7i+Xn9oXAU/d1fzqD9ObuwpVQOaorO5s70ckyi1woP9lVA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, "dependencies": { - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "damerau-levenshtein": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", - "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", - "dev": true + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "debug": { + "node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { + "dependencies": { "ms": "^2.1.1" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "doctrine": { + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "requires": { + "dependencies": { "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "node_modules/electron-to-chromium": { + "version": "1.4.615", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", + "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==", "dev": true }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.18.0-next.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", - "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.1", - "object-inspect": "^1.9.0", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.3", - "string.prototype.trimstart": "^1.0.3" + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "es-to-primitive": { + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, - "requires": { + "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "escape-string-regexp": { + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/highlight": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", - "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "eslint-config-airbnb": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.1.tgz", - "integrity": "sha512-xCu//8a/aWqagKljt+1/qAM62BYZeNq04HmdevG5yUGWpja0I/xhqd6GdLRch5oetEGFiJAnvtGuTEAese53Qg==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^13.2.0", - "object.assign": "^4.1.0", - "object.entries": "^1.1.0" - } - }, - "eslint-config-airbnb-base": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz", - "integrity": "sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.5", - "object.assign": "^4.1.0", - "object.entries": "^1.1.0" - } - }, - "eslint-config-prettier": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz", - "integrity": "sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - } - }, - "eslint-import-resolver-meteor": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-meteor/-/eslint-import-resolver-meteor-0.4.0.tgz", - "integrity": "sha1-yGhjhAghIIz4EzxczlGQnCamFWk=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "resolve": "^1.1.6" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "bin": { + "eslint": "bin/eslint.js" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "eslint-plugin-jest": { - "version": "21.27.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.27.2.tgz", - "integrity": "sha512-0E4OIgBJVlAmf1KfYFtZ3gYxgUzC5Eb3Jzmrc9ikI1OY+/cM8Kh72Ti7KfpeHNeD3HJNf9SmEfmvQLIz44Hrhw==", - "dev": true - }, - "eslint-plugin-jsx-a11y": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", - "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "node_modules/eslint-config-vazco": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-vazco/-/eslint-config-vazco-7.3.0.tgz", + "integrity": "sha512-OK8xVmrSxkd+Jl2OAvhwVquAMP5Xanz4mMxrBvPdtv2Ld25xI9CsbPNsFoRHOoBsu5sS5EYUdvpRy7tFk2R6Dg==", "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "aria-query": "^4.2.2", - "array-includes": "^3.1.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.0.2", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.6", - "emoji-regex": "^9.0.0", - "has": "^1.0.3", - "jsx-ast-utils": "^3.1.0", - "language-tags": "^1.0.5" + "engines": { + "node": ">=8", + "npm": ">=6" }, + "peerDependencies": { + "@babel/core": "^7.22.5", + "@babel/eslint-parser": "^7.22.5", + "@babel/eslint-plugin": "^7.22.5", + "@babel/preset-react": "^7.22.5", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "@typescript-eslint/parser": "^5.59.11", + "eslint": "^8.43.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "prettier": "^2.8.8", + "typescript": "^5.1.3" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, "dependencies": { - "emoji-regex": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.1.tgz", - "integrity": "sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg==", - "dev": true + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true } } }, - "eslint-plugin-meteor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-meteor/-/eslint-plugin-meteor-5.2.0.tgz", - "integrity": "sha512-bHzs/0BwHdKcBbX7tYrSnBaMG+1i2f1wy8k6H/sBBsERD/yifmBUrNLiPyZkIvyVUeI8OaZw8U9fsMvLP5GhIg==", + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", "dev": true, - "requires": { - "invariant": "2.2.4" + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "eslint-plugin-react": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", - "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flatmap": "^1.2.3", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "object.entries": "^1.1.2", - "object.fromentries": "^2.0.2", - "object.values": "^1.1.1", - "prop-types": "^15.7.2", - "resolve": "^1.18.1", - "string.prototype.matchall": "^4.0.2" + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true } } }, - "eslint-plugin-react-hooks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-3.0.0.tgz", - "integrity": "sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw==", - "dev": true - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "requires": { + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { "estraverse": "^5.1.0" }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } + "engines": { + "node": ">=0.10" } }, - "esrecurse": { + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "requires": { + "dependencies": { "estraverse": "^5.2.0" }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } + "engines": { + "node": ">=4.0" } }, - "estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "dev": true, + "engines": { + "node": ">=4.0" + } }, - "esutils": { + "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-json-stable-stringify": { + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "reusify": "^1.0.4" } }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, - "requires": { - "locate-path": "^2.0.0" + "dependencies": { + "is-callable": "^1.1.3" } }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, - "requires": { - "pump": "^3.0.0" + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "requires": { + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "globals": { + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, - "requires": { - "function-bind": "^1.1.1" + "engines": { + "node": ">=4" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "husky": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz", - "integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "requires": { - "chalk": "^2.4.2", - "ci-info": "^2.0.0", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.2.0", - "run-node": "^1.0.0", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/highlight": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", - "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - } - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "import-fresh": { + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "requires": { + "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "requires": { + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-extglob": { + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "engines": { + "node": ">=0.10.0" } }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-windows": { + "node_modules/is-finalizationregistry": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { + "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", - "dev": true - }, - "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" } }, - "js-tokens": { + "node_modules/js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", "dev": true }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "jsesc": { + "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "requires": { + "dependencies": { "minimist": "^1.2.0" - } - }, - "jsx-ast-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", - "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", - "dev": true, - "requires": { - "array-includes": "^3.1.2", - "object.assign": "^4.1.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "language-subtag-registry": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", - "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", - "dev": true - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", - "dev": true, - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "lint-staged": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-7.3.0.tgz", - "integrity": "sha512-AXk40M9DAiPi7f4tdJggwuKIViUplYtVj1os1MVEteW7qOkU50EOehayCfO9TsoGK24o/EsWb41yrEgfJDDjCw==", - "dev": true, - "requires": { - "chalk": "^2.3.1", - "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", - "debug": "^3.1.0", - "dedent": "^0.7.0", - "execa": "^0.9.0", - "find-parent-dir": "^0.3.0", - "is-glob": "^4.0.0", - "is-windows": "^1.0.2", - "jest-validate": "^23.5.0", - "listr": "^0.14.1", - "lodash": "^4.17.5", - "log-symbols": "^2.2.0", - "micromatch": "^3.1.8", - "npm-which": "^3.0.1", - "p-map": "^1.1.1", - "path-is-inside": "^1.0.2", - "pify": "^3.0.0", - "please-upgrade-node": "^3.0.2", - "staged-git-files": "1.1.1", - "string-argv": "^0.0.2", - "stringify-object": "^3.2.2" }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "bin": { + "json5": "lib/cli.js" } }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" } }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", "dev": true }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" } }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "lodash.merge": { + "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" - } - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "dev": true - }, - "loglevel-colored-level-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", - "integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "loglevel": "^1.4.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "loose-envify": { + "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "requires": { - "minimist": "^1.2.5" + "engines": { + "node": ">= 8" } }, - "ms": { + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", - "dev": true, - "requires": { - "which": "^1.2.10" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", - "dev": true, - "requires": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "engines": { + "node": ">=0.10.0" } }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "object-keys": { + "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, - "requires": { - "isobject": "^3.0.0" + "engines": { + "node": ">= 0.4" } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.entries": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "object.fromentries": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", - "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, - "requires": { - "isobject": "^3.0.1" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, - "object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "once": { + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, - "requires": { - "mimic-fn": "^1.0.0" + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { + "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { + "dependencies": { "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "requires": { - "error-ex": "^1.2.0" + "engines": { + "node": ">=8" } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "requires": { - "pify": "^2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "requires": { - "find-up": "^2.1.0" + "engines": { + "node": ">=8" } }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "requires": { - "semver-compare": "^1.0.0" + "engines": { + "node": ">=8" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true - }, - "prettier-eslint": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.8.2.tgz", - "integrity": "sha512-2UzApPuxi2yRoyMlXMazgR6UcH9DKJhNgCviIwY3ixZ9THWSSrUww5vkiZ3C48WvpFl1M1y/oU63deSy1puWEA==", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "common-tags": "^1.4.0", - "dlv": "^1.1.0", - "eslint": "^4.0.0", - "indent-string": "^3.2.0", - "lodash.merge": "^4.6.0", - "loglevel-colored-level-prefix": "^1.0.0", - "prettier": "^1.7.0", - "pretty-format": "^23.0.1", - "require-relative": "^0.8.7", - "typescript": "^2.5.1", - "typescript-eslint-parser": "^16.0.0", - "vue-eslint-parser": "^2.0.2" + "engines": { + "node": ">=8.6" }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - } - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - } + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { + "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "engines": { + "node": ">=6" } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "react-is": { + "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "require-relative": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", - "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", - "dev": true - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, "dependencies": { - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - } + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve-from": { + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "engines": { + "node": ">=4" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "*" - } - }, - "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "side-channel": { + "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "slash": { + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "engines": { + "node": ">=8" } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "staged-git-files": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.1.tgz", - "integrity": "sha512-H89UNKr1rQJvI1c/PIR3kiAMBV23yvR7LItZiV74HWZwzt7f3YHuujJ9nJZlt58WlFox7XQsOahexwk7nTe69A==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string-argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", - "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.matchall": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", - "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has-symbols": "^1.0.1", - "internal-slot": "^1.0.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3" + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-bom": { + "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { + "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "text-table": { + "node_modules/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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-fast-properties": { + "node_modules/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=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { + "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", + "json5": "^1.0.2", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, - "tslib": { + "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", - "dev": true - }, - "typescript-eslint-parser": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-16.0.1.tgz", - "integrity": "sha512-IKawLTu4A2xN3aN/cPLxvZ0bhxZHILGDKTZWvWNJ3sLNhJ3PjfMEDQmR2VMpdRPrmWOadgWXRwjLBzSA8AGsaQ==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - }, "dependencies": { - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "union-value": { + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "uri-js": { + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vue-eslint-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", - "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.2", - "esquery": "^1.0.0", - "lodash": "^4.17.4" - }, "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "wrappy": { + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true } } } diff --git a/package.json b/package.json index c701631f53..ff1baa3e4c 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,87 @@ { "name": "meteor", "version": "0.0.1", - "description": "Used to apply Prettier and ESLint manually", + "description": "Meteor's main repository, containing the Meteor tool, core packages, and documentation.", "repository": { "type": "git", "url": "git+https://github.com/meteor/meteor.git" }, - "author": "Filipe NΓ©vola", "license": "MIT", "bugs": { "url": "https://github.com/meteor/meteor/issues" }, - "homepage": "https://github.com/meteor/meteor#readme", + "homepage": "https://www.meteor.com/", "devDependencies": { - "@quave/eslint-config-quave": "^1.0.3", - "@types/node": "^14.17.6" + "@babel/core": "^7.21.3", + "@babel/eslint-parser": "^7.21.3", + "@babel/eslint-plugin": "^7.19.1", + "@babel/preset-react": "^7.18.6", + "@types/lodash.isempty": "^4.4.9", + "@types/node": "^18.16.18", + "@types/sockjs": "^0.3.36", + "@types/sockjs-client": "^1.5.4", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-vazco": "^7.1.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "prettier": "^2.8.8", + "typescript": "^5.4.5" + }, + "scripts": { + "test:idle-bot": "node --test .github/scripts/__tests__/inactive-issues.test.js" + }, + "jshintConfig": { + "esversion": 11 + }, + "prettier": { + "semi": true, + "singleQuote": false }, "eslintConfig": { - "extends": [ - "@quave/quave" - ], + "extends": "vazco", "rules": { "global-require": "off", "no-console": "off", "camelcase": "warn", "consistent-return": "off", - "quotes": "warn", + "quotes": [ + "warn", + "single", + { + "allowTemplateLiterals": true + } + ], "no-shadow": [ "error", { - "allow": ["resolve"] + "allow": [ + "resolve" + ] } ], "no-use-before-define": "warn", - "import/no-unresolved": "warn" + "import/no-unresolved": "warn", + "require-await": "warn", + "space-before-function-paren": [ + "warn", + { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + } + ], + "complexity": "off", + "func-names": "off", + "no-undef": "warn", + "curly": "off", + "sort-imports": "off" } } } diff --git a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json b/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index f79e8e6683..0000000000 --- a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "lockfileVersion": 1, - "dependencies": { - "@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" - }, - "@types/notp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/notp/-/notp-2.0.2.tgz", - "integrity": "sha512-JUcVYN9Tmw0AjoAfvjslS4hbv39fPBbZdftBK3b50g5z/DmhLsu6cd0UOEBiQuMwy2FirshF2Gk9gAvfWjshMw==" - }, - "node-2fa": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/node-2fa/-/node-2fa-2.0.3.tgz", - "integrity": "sha512-PQldrOhjuoZyoydMvMSctllPN1ZPZ1/NwkEcgYwY9faVqE/OymxR+3awPpbWZxm6acLKqvmNqQmdqTsqYyflFw==" - }, - "notp": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/notp/-/notp-2.0.3.tgz", - "integrity": "sha512-oBig/2uqkjQ5AkBuw4QJYwkEWa/q+zHxI5/I5z6IeP2NT0alpJFsP/trrfCC+9xOAgQSZXssNi962kp5KBmypQ==" - }, - "qrcode-svg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/qrcode-svg/-/qrcode-svg-1.1.0.tgz", - "integrity": "sha512-XyQCIXux1zEIA3NPb0AeR8UMYvXZzWEhgdBgBjH9gO7M48H9uoHzviNz8pXw3UzrAcxRRRn9gxHewAVK7bn9qw==" - }, - "thirty-two": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==" - }, - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } -} diff --git a/packages/accounts-2fa/2fa-server.js b/packages/accounts-2fa/2fa-server.js index 111a655999..801233d294 100644 --- a/packages/accounts-2fa/2fa-server.js +++ b/packages/accounts-2fa/2fa-server.js @@ -13,8 +13,8 @@ Accounts._check2faEnabled = user => { ); }; -Accounts._is2faEnabledForUser = () => { - const user = Meteor.user(); +Accounts._is2faEnabledForUser = async () => { + const user = await Meteor.userAsync(); if (!user) { throw new Meteor.Error('no-logged-user', 'No user logged in.'); } @@ -34,9 +34,9 @@ Accounts._isTokenValid = (secret, code) => { }; Meteor.methods({ - generate2faActivationQrCode(appName) { + async generate2faActivationQrCode(appName) { check(appName, String); - const user = Meteor.user(); + const user = await Meteor.userAsync(); if (!user) { throw new Meteor.Error( @@ -59,7 +59,7 @@ Meteor.methods({ }); const svg = new QRCode(uri).svg(); - Meteor.users.update( + await Meteor.users.updateAsync( { _id: user._id }, { $set: { @@ -72,9 +72,9 @@ Meteor.methods({ return { svg, secret, uri }; }, - enableUser2fa(code) { + async enableUser2fa(code) { check(code, String); - const user = Meteor.user(); + const user = await Meteor.userAsync(); if (!user) { throw new Meteor.Error(400, 'No user logged in.'); @@ -94,7 +94,7 @@ Meteor.methods({ Accounts._handleError('Invalid 2FA code', true, 'invalid-2fa-code'); } - Meteor.users.update( + await Meteor.users.updateAsync( { _id: user._id }, { $set: { @@ -106,14 +106,14 @@ Meteor.methods({ } ); }, - disableUser2fa() { + async disableUser2fa() { const userId = Meteor.userId(); if (!userId) { throw new Meteor.Error(400, 'No user logged in.'); } - Meteor.users.update( + await Meteor.users.updateAsync( { _id: userId }, { $unset: { @@ -122,8 +122,8 @@ Meteor.methods({ } ); }, - has2faEnabled() { - return Accounts._is2faEnabledForUser(); + async has2faEnabled() { + return await Accounts._is2faEnabledForUser(); }, }); diff --git a/packages/accounts-2fa/package.js b/packages/accounts-2fa/package.js index 46919f0325..52efca1c3b 100644 --- a/packages/accounts-2fa/package.js +++ b/packages/accounts-2fa/package.js @@ -1,37 +1,37 @@ Package.describe({ - version: '2.0.2', + version: "3.0.1", summary: - 'Package used to enable two factor authentication through OTP protocol', + "Package used to enable two factor authentication through OTP protocol", }); Npm.depends({ - 'node-2fa': '2.0.3', - 'qrcode-svg': '1.1.0', + "node-2fa": "2.0.3", + "qrcode-svg": "1.1.0", }); -Package.onUse(function(api) { - api.use(['accounts-base'], ['client', 'server']); +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.imply("accounts-base", ["client", "server"]); - api.use('ecmascript'); - api.use('check', 'server'); + api.use("ecmascript"); + api.use("check", "server"); - api.addFiles(['2fa-client.js'], 'client'); - api.addFiles(['2fa-server.js'], 'server'); + api.addFiles(["2fa-client.js"], "client"); + api.addFiles(["2fa-server.js"], "server"); }); -Package.onTest(function(api) { +Package.onTest(function (api) { api.use([ - 'accounts-base', - 'accounts-password', - 'ecmascript', - 'tinytest', - 'random', - 'accounts-2fa', + "accounts-base", + "accounts-password", + "ecmascript", + "tinytest", + "random", + "accounts-2fa", ]); - api.mainModule('server_tests.js', 'server'); - api.mainModule('client_tests.js', 'client'); + api.mainModule("server_tests.js", "server"); + api.mainModule("client_tests.js", "client"); }); diff --git a/packages/accounts-2fa/server_tests.js b/packages/accounts-2fa/server_tests.js index 8a95fc5602..c3887db9ed 100644 --- a/packages/accounts-2fa/server_tests.js +++ b/packages/accounts-2fa/server_tests.js @@ -1,15 +1,16 @@ import { Accounts } from 'meteor/accounts-base'; import { Random } from 'meteor/random'; -const findUserById = id => Meteor.users.findOne(id); +const findUserById = + async id => await Meteor.users.findOneAsync(id); -Tinytest.add('account - 2fa - has2faEnabled - server', test => { +Tinytest.addAsync('account - 2fa - has2faEnabled - server', async test => { // Create users - const userWithout2FA = Accounts.insertUserDoc( + const userWithout2FA = await Accounts.insertUserDoc( {}, { emails: [{ address: `${Random.id()}@meteorapp.com`, verified: true }] } ); - const userWith2FA = Accounts.insertUserDoc( + const userWith2FA = await Accounts.insertUserDoc( {}, { emails: [{ address: `${Random.id()}@meteorapp.com`, verified: true }], @@ -19,10 +20,10 @@ Tinytest.add('account - 2fa - has2faEnabled - server', test => { } ); - test.equal(Accounts._check2faEnabled(findUserById(userWithout2FA)), false); - test.equal(Accounts._check2faEnabled(findUserById(userWith2FA)), true); + test.equal(Accounts._check2faEnabled(await findUserById(userWithout2FA)), false); + test.equal(Accounts._check2faEnabled(await findUserById(userWith2FA)), true); // cleanup - Accounts.users.remove(userWithout2FA); - Accounts.users.remove(userWith2FA); + await Accounts.users.removeAsync(userWithout2FA); + await Accounts.users.removeAsync(userWith2FA); }); diff --git a/packages/accounts-base/accounts-base.d.ts b/packages/accounts-base/accounts-base.d.ts index 1e1ae22c09..6aa2a58e2a 100644 --- a/packages/accounts-base/accounts-base.d.ts +++ b/packages/accounts-base/accounts-base.d.ts @@ -1,10 +1,12 @@ import { Mongo } from 'meteor/mongo'; import { Meteor } from 'meteor/meteor'; import { Configuration } from 'meteor/service-configuration'; +import { DDP } from 'meteor/ddp'; export interface URLS { resetPassword: (token: string) => string; verifyEmail: (token: string) => string; + loginToken: (token: string) => string; enrollAccount: (token: string) => string; } @@ -15,6 +17,16 @@ export interface EmailFields { html?: ((user: Meteor.User, url: string) => string) | undefined; } +export interface AccountsClientOptions { + connection?: DDP.DDPStatic; + ddpUrl?: string; +} + +export class AccountsClient { + constructor(options?: AccountsClientOptions); + connection: DDP.DDPStatic; +} + export namespace Accounts { var urls: URLS; @@ -36,7 +48,7 @@ export namespace Accounts { profile?: Meteor.UserProfile | undefined; }, callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): string; + ): Promise; function createUserAsync( options: { @@ -48,16 +60,39 @@ export namespace Accounts { callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void ): Promise; + function createUserVerifyingEmail( + options: { + username?: string | undefined; + email?: string | undefined; + password?: string | undefined; + profile?: Meteor.UserProfile | undefined; + }, + callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void + ): Promise; + function config(options: { sendVerificationEmail?: boolean | undefined; forbidClientAccountCreation?: boolean | undefined; restrictCreationByEmailDomain?: string | Function | undefined; + loginExpiration?: number | undefined; loginExpirationInDays?: number | undefined; oauthSecretKey?: string | undefined; + passwordResetTokenExpiration?: number | undefined; passwordResetTokenExpirationInDays?: number | undefined; + passwordEnrollTokenExpiration?: number | undefined; passwordEnrollTokenExpirationInDays?: number | undefined; ambiguousErrorMessages?: boolean | undefined; + bcryptRounds?: number | undefined; + argon2Enabled?: string | false; + argon2Type?: string | undefined; + argon2TimeCost: number | undefined; + argon2MemoryCost: number | undefined; + argon2Parallelism: number | undefined; defaultFieldSelector?: { [key: string]: 0 | 1 } | undefined; + collection?: string | undefined; + loginTokenExpirationHours?: number | undefined; + tokenSequenceLength?: number | undefined; + clientStorage?: 'session' | 'local'; }): void; function onLogin( @@ -84,23 +119,23 @@ export namespace Accounts { oldPassword: string, newPassword: string, callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; function forgotPassword( options: { email?: string | undefined }, callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; function resetPassword( token: string, newPassword: string, callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; function verifyEmail( token: string, callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; function onEmailVerificationLink(callback: Function): void; @@ -114,11 +149,11 @@ export namespace Accounts { function logout( callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; function logoutOtherClients( callback?: (error?: Error | Meteor.Error | Meteor.TypedError) => void - ): void; + ): Promise; type PasswordSignupField = 'USERNAME_AND_EMAIL' | 'USERNAME_AND_OPTIONAL_EMAIL' | 'USERNAME_ONLY' | 'EMAIL_ONLY'; type PasswordlessSignupField = 'USERNAME_AND_EMAIL' | 'EMAIL_ONLY'; @@ -150,9 +185,11 @@ export interface EmailTemplates { export namespace Accounts { var emailTemplates: EmailTemplates; - function addEmail(userId: string, newEmail: string, verified?: boolean): void; + function addEmailAsync(userId: string, newEmail: string, verified?: boolean): Promise; - function removeEmail(userId: string, email: string): void; + function removeEmail(userId: string, email: string): Promise; + + function replaceEmailAsync(userId: string, oldEmail: string, newEmail: string, verified?: boolean): Promise; function onCreateUser( func: (options: { profile?: {} | undefined }, user: Meteor.User) => void @@ -161,41 +198,52 @@ export namespace Accounts { function findUserByEmail( email: string, options?: { fields?: Mongo.FieldSpecifier | undefined } - ): Meteor.User | null | undefined; + ): Promise; function findUserByUsername( username: string, options?: { fields?: Mongo.FieldSpecifier | undefined } - ): Meteor.User | null | undefined; + ): Promise; + + interface SendEmailOptions { + from: string; + to: string; + subject: string; + text: string; + html: string; + headers?: Header | undefined; + } + + interface SendEmailResult { + email: string; + user: Meteor.User; + token: string; + url: string; + options: SendEmailOptions; + } function sendEnrollmentEmail( userId: string, email?: string, extraTokenData?: Record, extraParams?: Record - ): void; + ): Promise; function sendResetPasswordEmail( userId: string, email?: string, extraTokenData?: Record, extraParams?: Record - ): void; + ): Promise; function sendVerificationEmail( userId: string, email?: string, extraTokenData?: Record, extraParams?: Record - ): void; + ): Promise; - function setUsername(userId: string, newUsername: string): void; - - function setPassword( - userId: string, - newPassword: string, - options?: { logout?: boolean | undefined } - ): void; + function setUsername(userId: string, newUsername: string): Promise; function setPasswordAsync( userId: string, @@ -324,22 +372,22 @@ export namespace Accounts { type Password = | string | { - digest: string; - algorithm: 'sha-256'; - }; + digest: string; + algorithm: 'sha-256'; + }; /** * - * Check whether the provided password matches the bcrypt'ed password in + * Check whether the provided password matches the encrypted password in * the database user record. `password` can be a string (in which case - * it will be run through SHA256 before bcrypt) or an object with - * properties `digest` and `algorithm` (in which case we bcrypt + * it will be run through SHA256 before bcrypt or argon2) or an object with + * properties `digest` and `algorithm` (in which case we bcrypt/argon2 * `password.digest`). */ - function _checkPassword( + function _checkPasswordAsync( user: Meteor.User, password: Password - ): { userId: string; error?: any }; + ): Promise<{ userId: string; error?: any }> } export namespace Accounts { diff --git a/packages/accounts-base/accounts_client.js b/packages/accounts-base/accounts_client.js index 842e927ad9..aef200ed39 100644 --- a/packages/accounts-base/accounts_client.js +++ b/packages/accounts-base/accounts_client.js @@ -9,6 +9,7 @@ import {AccountsCommon} from "./accounts_common.js"; * @param {Object} options an object with fields: * @param {Object} options.connection Optional DDP connection to reuse. * @param {String} options.ddpUrl Optional URL for creating a new DDP connection. + * @param {'session' | 'local'} options.clientStorage Optional Define what kind of storage you want for credentials on the client. Default is 'local' to use `localStorage`. Set to 'session' to use session storage. */ export class AccountsClient extends AccountsCommon { constructor(options) { @@ -26,6 +27,8 @@ export class AccountsClient extends AccountsCommon { this.savedHash = window.location.hash; this._initUrlMatching(); + this.initStorageLocation(); + // Defined in localstorage_token.js. this._initLocalStorage(); @@ -37,6 +40,17 @@ export class AccountsClient extends AccountsCommon { this._loginCallbacksCalled = false; } + initStorageLocation(options) { + // Determine whether to use local or session storage to storage credentials and anything else. + this.storageLocation = (options?.clientStorage === 'session' || Meteor.settings?.public?.packages?.accounts?.clientStorage === 'session') ? window.sessionStorage : Meteor._localStorage; + } + + config(options) { + super.config(options); + + this.initStorageLocation(options); + } + /// /// CURRENT USER /// @@ -119,18 +133,21 @@ export class AccountsClient extends AccountsCommon { */ logout(callback) { this._loggingOut.set(true); - this.connection.apply('logout', [], { + + this.connection.applyAsync('logout', [], { + // TODO[FIBERS]: Look this { wait: true } later. wait: true - }, (error, result) => { - this._loggingOut.set(false); - this._loginCallbacksCalled = false; - if (error) { - callback && callback(error); - } else { + }) + .then((result) => { + this._loggingOut.set(false); + this._loginCallbacksCalled = false; this.makeClientLoggedOut(); callback && callback(); - } - }); + }) + .catch((e) => { + this._loggingOut.set(false); + callback && callback(e); + }); } /** @@ -226,13 +243,14 @@ export class AccountsClient extends AccountsCommon { const loginCallbacks = ({ error, loginDetails }) => { if (!called) { called = true; - this._loginCallbacksCalled = true; if (!error) { this._onLoginHook.forEach(callback => { callback(loginDetails); return true; }); + this._loginCallbacksCalled = true; } else { + this._loginCallbacksCalled = false; this._onLoginFailureHook.forEach(callback => { callback({ error }); return true; @@ -344,33 +362,47 @@ export class AccountsClient extends AccountsCommon { // Note that we need to call this even if _suppressLoggingIn is true, // because it could be matching a _setLoggingIn(true) from a // half-completed pre-reconnect login method. - this._setLoggingIn(false); if (error || !result) { error = error || new Error( `No result from call to ${options.methodName}` ); loginCallbacks({ error }); + this._setLoggingIn(false); return; } try { options.validateResult(result); } catch (e) { loginCallbacks({ error: e }); + this._setLoggingIn(false); return; } // Make the client logged in. (The user data should already be loaded!) this.makeClientLoggedIn(result.id, result.token, result.tokenExpires); - loginCallbacks({ loginDetails: result }); + + // use Tracker to make we sure have a user before calling the callbacks + Tracker.autorun(async (computation) => { + const user = await Tracker.withComputation(computation, () => + Meteor.userAsync(), + ); + + if (user) { + loginCallbacks({ loginDetails: result }); + this._setLoggingIn(false); + computation.stop(); + } + }); + }; if (!options._suppressLoggingIn) { this._setLoggingIn(true); } - this.connection.apply( + this.connection.applyAsync( options.methodName, options.methodArguments, - { wait: true, onResultReceived: onResultReceived }, + { wait: true, onResultReceived }, loggedInAndDataReadyCallback); } @@ -496,11 +528,11 @@ export class AccountsClient extends AccountsCommon { }; _storeLoginToken(userId, token, tokenExpires) { - Meteor._localStorage.setItem(this.USER_ID_KEY, userId); - Meteor._localStorage.setItem(this.LOGIN_TOKEN_KEY, token); + this.storageLocation.setItem(this.USER_ID_KEY, userId); + this.storageLocation.setItem(this.LOGIN_TOKEN_KEY, token); if (! tokenExpires) tokenExpires = this._tokenExpiration(new Date()); - Meteor._localStorage.setItem(this.LOGIN_TOKEN_EXPIRES_KEY, tokenExpires); + this.storageLocation.setItem(this.LOGIN_TOKEN_EXPIRES_KEY, tokenExpires); // to ensure that the localstorage poller doesn't end up trying to // connect a second time @@ -508,9 +540,9 @@ export class AccountsClient extends AccountsCommon { }; _unstoreLoginToken() { - Meteor._localStorage.removeItem(this.USER_ID_KEY); - Meteor._localStorage.removeItem(this.LOGIN_TOKEN_KEY); - Meteor._localStorage.removeItem(this.LOGIN_TOKEN_EXPIRES_KEY); + this.storageLocation.removeItem(this.USER_ID_KEY); + this.storageLocation.removeItem(this.LOGIN_TOKEN_KEY); + this.storageLocation.removeItem(this.LOGIN_TOKEN_EXPIRES_KEY); // to ensure that the localstorage poller doesn't end up trying to // connect a second time @@ -520,15 +552,15 @@ export class AccountsClient extends AccountsCommon { // This is private, but it is exported for now because it is used by a // test in accounts-password. _storedLoginToken() { - return Meteor._localStorage.getItem(this.LOGIN_TOKEN_KEY); + return this.storageLocation.getItem(this.LOGIN_TOKEN_KEY); }; _storedLoginTokenExpires() { - return Meteor._localStorage.getItem(this.LOGIN_TOKEN_EXPIRES_KEY); + return this.storageLocation.getItem(this.LOGIN_TOKEN_EXPIRES_KEY); }; _storedUserId() { - return Meteor._localStorage.getItem(this.USER_ID_KEY); + return this.storageLocation.getItem(this.USER_ID_KEY); }; _unstoreLoginTokenIfExpiresSoon() { @@ -657,7 +689,7 @@ export class AccountsClient extends AccountsCommon { /** * @summary Register a function to call when a reset password link is clicked * in an email sent by - * [`Accounts.sendResetPasswordEmail`](#accounts_sendresetpasswordemail). + * [`Accounts.sendResetPasswordEmail`](#Accounts-sendResetPasswordEmail). * This function should be called in top-level code, not inside * `Meteor.startup()`. * @memberof! Accounts @@ -665,7 +697,7 @@ export class AccountsClient extends AccountsCommon { * @param {Function} callback The function to call. It is given two arguments: * * 1. `token`: A password reset token that can be passed to - * [`Accounts.resetPassword`](#accounts_resetpassword). + * [`Accounts.resetPassword`](#Accounts-resetPassword). * 2. `done`: A function to call when the password reset UI flow is complete. The normal * login process is suspended until this function is called, so that the * password for user A can be reset even if user B was logged in. @@ -683,7 +715,7 @@ export class AccountsClient extends AccountsCommon { /** * @summary Register a function to call when an email verification link is * clicked in an email sent by - * [`Accounts.sendVerificationEmail`](#accounts_sendverificationemail). + * [`Accounts.sendVerificationEmail`](#Accounts-sendVerificationEmail). * This function should be called in top-level code, not inside * `Meteor.startup()`. * @memberof! Accounts @@ -691,7 +723,7 @@ export class AccountsClient extends AccountsCommon { * @param {Function} callback The function to call. It is given two arguments: * * 1. `token`: An email verification token that can be passed to - * [`Accounts.verifyEmail`](#accounts_verifyemail). + * [`Accounts.verifyEmail`](#Accounts-verifyEmail). * 2. `done`: A function to call when the email verification UI flow is complete. * The normal login process is suspended until this function is called, so * that the user can be notified that they are verifying their email before @@ -710,7 +742,7 @@ export class AccountsClient extends AccountsCommon { /** * @summary Register a function to call when an account enrollment link is * clicked in an email sent by - * [`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail). + * [`Accounts.sendEnrollmentEmail`](#Accounts-sendEnrollmentEmail). * This function should be called in top-level code, not inside * `Meteor.startup()`. * @memberof! Accounts @@ -718,7 +750,7 @@ export class AccountsClient extends AccountsCommon { * @param {Function} callback The function to call. It is given two arguments: * * 1. `token`: A password reset token that can be passed to - * [`Accounts.resetPassword`](#accounts_resetpassword) to give the newly + * [`Accounts.resetPassword`](#Accounts-resetPassword) to give the newly * enrolled account a password. * 2. `done`: A function to call when the enrollment UI flow is complete. * The normal login process is suspended until this function is called, so that @@ -734,7 +766,7 @@ export class AccountsClient extends AccountsCommon { this._accountsCallbacks["enroll-account"] = callback; }; -}; +} /** * @summary True if a login method (such as `Meteor.loginWithPassword`, diff --git a/packages/accounts-base/accounts_client_tests.js b/packages/accounts-base/accounts_client_tests.js index 880a71e4fe..f5466216f5 100644 --- a/packages/accounts-base/accounts_client_tests.js +++ b/packages/accounts-base/accounts_client_tests.js @@ -1,4 +1,5 @@ import {Accounts} from "meteor/accounts-base"; +import { AccountsClient } from './accounts_client'; const username = 'jsmith'; const password = 'password'; @@ -36,9 +37,9 @@ const createUserAndLogout = (test, done, nextTests) => { }, }, () => { - Meteor.logout(() => { + Meteor.logout(async () => { // Make sure we're logged out - test.isFalse(Meteor.user()); + test.isFalse(await Meteor.userAsync()); // Handle next tests nextTests(test, done); }); @@ -47,13 +48,13 @@ const createUserAndLogout = (test, done, nextTests) => { }; const removeTestUser = done => { - Meteor.call('removeAccountsTestUser', username, () => { + Meteor.callAsync('removeAccountsTestUser', username).then(() => { done(); }); }; const forceEnableUser2fa = done => { - Meteor.call('forceEnableUser2fa', { username }, secret2fa, (err, token) => { + Meteor.callAsync('forceEnableUser2fa', { username }, secret2fa).then((token) => { done(token); }); }; @@ -245,13 +246,13 @@ Tinytest.addAsync( ); -Tinytest.addAsync( + 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()); + Meteor.loginWithPasswordAnd2faCode(username, password, 'ABC', async e => { + test.isFalse(await Meteor.user()); test.equal(e.reason, 'Invalid 2FA code'); removeTestUser(done); }); @@ -304,3 +305,64 @@ Tinytest.addAsync( } ); +Tinytest.addAsync('accounts - storage', + async function(test) { + const expectWhenSessionStorage = () => { + test.isNotUndefined(sessionStorage.getItem('Meteor.loginToken')); + test.isNull(localStorage.getItem('Meteor.loginToken')); + }; + const expectWhenLocalStorage = () => { + test.isNotUndefined(localStorage.getItem('Meteor.loginToken')); + test.isNull(sessionStorage.getItem('Meteor.loginToken')); + }; + + const testCases = [{ + clientStorage: undefined, + expectStorage: expectWhenLocalStorage, + }, { + clientStorage: 'local', + expectStorage: expectWhenLocalStorage, + }, { + clientStorage: 'session', + expectStorage: expectWhenSessionStorage, + }]; + for await (const testCase of testCases) { + await new Promise(resolve => { + sessionStorage.clear(); + localStorage.clear(); + + const { clientStorage, expectStorage } = testCase; + Accounts.config({ clientStorage }); + test.equal(Accounts._options.clientStorage, clientStorage); + + // Login a user and test that tokens are in expected storage + logoutAndCreateUser(test, resolve, () => { + Accounts.logout(); + expectStorage(); + removeTestUser(resolve); + }); + }); + } + }); + +Tinytest.addAsync('accounts - should only start subscription when connected', async function (test) { + const { conn, messages, cleanup } = await captureConnectionMessagesClient(test); + + const acc = new AccountsClient({ + connection: conn, + }) + + acc.callLoginMethod() + + await Meteor._sleepForMs(100); + + // The sub call needs to come right after `connect` since this is when `status().connected` gets to be true and + // not after `connected` as it is based on the socket connection status. + const expectedMessages = ['connect', 'method', 'sub', 'connected', 'updated', 'result', 'ready'] + + const parsedMessages = messages.map(m => m.msg).filter(Boolean).filter(m => m !== 'added') + + test.equal(parsedMessages, expectedMessages) + + cleanup() +}); \ No newline at end of file diff --git a/packages/accounts-base/accounts_common.js b/packages/accounts-base/accounts_common.js index 1906a3dfd0..48234064d8 100644 --- a/packages/accounts-base/accounts_common.js +++ b/packages/accounts-base/accounts_common.js @@ -4,19 +4,28 @@ import { Meteor } from 'meteor/meteor'; const VALID_CONFIG_KEYS = [ 'sendVerificationEmail', 'forbidClientAccountCreation', - 'passwordEnrollTokenExpiration', - 'passwordEnrollTokenExpirationInDays', 'restrictCreationByEmailDomain', - 'loginExpirationInDays', 'loginExpiration', + 'loginExpirationInDays', + 'oauthSecretKey', 'passwordResetTokenExpirationInDays', 'passwordResetTokenExpiration', + 'passwordEnrollTokenExpirationInDays', + 'passwordEnrollTokenExpiration', 'ambiguousErrorMessages', 'bcryptRounds', + 'argon2Enabled', + 'argon2Type', + 'argon2TimeCost', + 'argon2MemoryCost', + 'argon2Parallelism', 'defaultFieldSelector', + 'collection', 'loginTokenExpirationHours', 'tokenSequenceLength', - 'collection', + 'clientStorage', + 'ddpUrl', + 'connection', ]; /** @@ -32,9 +41,16 @@ const VALID_CONFIG_KEYS = [ */ export class AccountsCommon { constructor(options) { + // Validate config options keys + for (const key of Object.keys(options)) { + if (!VALID_CONFIG_KEYS.includes(key)) { + console.error(`Accounts.config: Invalid key: ${key}`); + } + } + // Currently this is read directly by packages like accounts-password // and accounts-ui-unstyled. - this._options = {}; + this._options = options || {}; // Note that setting this.connection = null causes this.users to be a // LocalCollection, which is not what we want. @@ -147,15 +163,27 @@ export class AccountsCommon { } /** - * @summary Get the current user record, or `null` if no user is logged in. A reactive data source. + * @summary Get the current user record, or `null` if no user is logged in. A reactive data source. In the server this fuction returns a promise. * @locus Anywhere * @param {Object} [options] * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. */ user(options) { - const userId = this.userId(); + if (Meteor.isServer) { + console.warn([ + "`Meteor.user()` is deprecated on the server side.", + " To fetch the current user record on the server,", + " use `Meteor.userAsync()` instead.", + ].join("\n")); + } + + const self = this; + const userId = self.userId(); + const findOne = (...args) => Meteor.isClient + ? self.users.findOne(...args) + : self.users.findOneAsync(...args); return userId - ? this.users.findOne(userId, this._addDefaultFieldSelector(options)) + ? findOne(userId, this._addDefaultFieldSelector(options)) : null; } @@ -171,61 +199,46 @@ export class AccountsCommon { ? this.users.findOneAsync(userId, this._addDefaultFieldSelector(options)) : null; } - // Set up config for the accounts system. Call this on both the client - // and the server. - // - // Note that this method gets overridden on AccountsServer.prototype, but - // the overriding method calls the overridden method. - // - // XXX we should add some enforcement that this is called on both the - // client and the server. Otherwise, a user can - // 'forbidClientAccountCreation' only on the client and while it looks - // like their app is secure, the server will still accept createUser - // calls. https://github.com/meteor/meteor/issues/828 - // - // @param options {Object} an object with fields: - // - sendVerificationEmail {Boolean} - // Send email address verification emails to new users created from - // client signups. - // - forbidClientAccountCreation {Boolean} - // Do not allow clients to create accounts directly. - // - restrictCreationByEmailDomain {Function or String} - // Require created users to have an email matching the function or - // having the string as domain. - // - loginExpirationInDays {Number} - // Number of days since login until a user is logged out (login token - // expires). - // - collection {String|Mongo.Collection} - // A collection name or a Mongo.Collection object to hold the users. - // - passwordResetTokenExpirationInDays {Number} - // Number of days since password reset token creation until the - // token cannt be used any longer (password reset token expires). - // - ambiguousErrorMessages {Boolean} - // Return ambiguous error messages from login failures to prevent - // user enumeration. - // - bcryptRounds {Number} - // Allows override of number of bcrypt rounds (aka work factor) used - // to store passwords. /** * @summary Set global accounts options. You can also set these in `Meteor.settings.packages.accounts` without the need to call this function. * @locus Anywhere * @param {Object} options * @param {Boolean} options.sendVerificationEmail New users with an email address will receive an address verification email. - * @param {Boolean} options.forbidClientAccountCreation Calls to [`createUser`](#accounts_createuser) from the client will be rejected. In addition, if you are using [accounts-ui](#accountsui), the "Create account" link will not be available. + * @param {Boolean} options.forbidClientAccountCreation Calls to [`createUser`](#accounts_createuser) from the client will be rejected. In addition, if you are using [accounts-ui](#accountsui), the "Create account" link will not be available. **Important**: This option must be set on both the client and server to take full effect. If only set on the server, account creation will be blocked but the UI will still show the "Create account" link. * @param {String | Function} options.restrictCreationByEmailDomain If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: `Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })`. - * @param {Number} options.loginExpirationInDays The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to `null` to disable login expiration. * @param {Number} options.loginExpiration The number of milliseconds from when a user logs in until their token expires and they are logged out, for a more granular control. If `loginExpirationInDays` is set, it takes precedent. + * @param {Number} options.loginExpirationInDays The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to `null` to disable login expiration. * @param {String} options.oauthSecretKey When using the `oauth-encryption` package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specified on the server. See packages/oauth-encryption/README.md for details. * @param {Number} options.passwordResetTokenExpirationInDays The number of days from when a link to reset password is sent until token expires and user can't reset password with the link anymore. Defaults to 3. * @param {Number} options.passwordResetTokenExpiration The number of milliseconds from when a link to reset password is sent until token expires and user can't reset password with the link anymore. If `passwordResetTokenExpirationInDays` is set, it takes precedent. * @param {Number} options.passwordEnrollTokenExpirationInDays The number of days from when a link to set initial password is sent until token expires and user can't set password with the link anymore. Defaults to 30. * @param {Number} options.passwordEnrollTokenExpiration The number of milliseconds from when a link to set initial password is sent until token expires and user can't set password with the link anymore. If `passwordEnrollTokenExpirationInDays` is set, it takes precedent. - * @param {Boolean} options.ambiguousErrorMessages Return ambiguous error messages from login failures to prevent user enumeration. Defaults to false. + * @param {Boolean} options.ambiguousErrorMessages Return ambiguous error messages from login failures to prevent user enumeration. Defaults to `true`. + * @param {Number} options.bcryptRounds Allows override of number of bcrypt rounds (aka work factor) used to store passwords. The default is 10. + * @param {Boolean} options.argon2Enabled Enable argon2 algorithm usage in replacement for bcrypt. The default is `false`. + * @param {'argon2id' | 'argon2i' | 'argon2d'} options.argon2Type Allows override of the argon2 algorithm type. The default is `argon2id`. + * @param {Number} options.argon2TimeCost Allows override of number of argon2 iterations (aka time cost) used to store passwords. The default is 2. + * @param {Number} options.argon2MemoryCost Allows override of the amount of memory (in KiB) used by the argon2 algorithm. The default is 19456 (19MB). + * @param {Number} options.argon2Parallelism Allows override of the number of threads used by the argon2 algorithm. The default is 1. * @param {MongoFieldSpecifier} options.defaultFieldSelector To exclude by default large custom fields from `Meteor.user()` and `Meteor.findUserBy...()` functions when called without a field selector, and all `onLogin`, `onLoginFailure` and `onLogout` callbacks. Example: `Accounts.config({ defaultFieldSelector: { myBigArray: 0 }})`. Beware when using this. If, for instance, you do not include `email` when excluding the fields, you can have problems with functions like `forgotPassword` that will break because they won't have the required data available. It's recommend that you always keep the fields `_id`, `username`, and `email`. * @param {String|Mongo.Collection} options.collection A collection name or a Mongo.Collection object to hold the users. * @param {Number} options.loginTokenExpirationHours When using the package `accounts-2fa`, use this to set the amount of time a token sent is valid. As it's just a number, you can use, for example, 0.5 to make the token valid for just half hour. The default is 1 hour. * @param {Number} options.tokenSequenceLength When using the package `accounts-2fa`, use this to the size of the token sequence generated. The default is 6. + * @param {'session' | 'local'} options.clientStorage By default login credentials are stored in local storage, setting this to true will switch to using session storage. + * + * @example + * // For UI-related options like forbidClientAccountCreation, call Accounts.config on both client and server + * // Create a shared configuration file (e.g., lib/accounts-config.js): + * import { Accounts } from 'meteor/accounts-base'; + * + * Accounts.config({ + * forbidClientAccountCreation: true, + * sendVerificationEmail: true, + * }); + * + * // Then import this file in both client/main.js and server/main.js: + * // import '../lib/accounts-config.js'; */ config(options) { // We don't want users to accidentally only call Accounts.config on the @@ -266,24 +279,23 @@ export class AccountsCommon { } // Validate config options keys - Object.keys(options).forEach(key => { + for (const key of Object.keys(options)) { if (!VALID_CONFIG_KEYS.includes(key)) { - // TODO Consider just logging a debug message instead to allow for additional keys in the settings here? - throw new Meteor.Error(`Accounts.config: Invalid key: ${key}`); + console.error(`Accounts.config: Invalid key: ${key}`); } - }); + } // set values in Accounts._options - VALID_CONFIG_KEYS.forEach(key => { + for (const key of VALID_CONFIG_KEYS) { if (key in options) { if (key in this._options) { - if (key !== 'collection') { + if (key !== 'collection' && (Meteor.isTest && key !== 'clientStorage')) { throw new Meteor.Error(`Can't set \`${key}\` more than once`); } } this._options[key] = options[key]; } - }); + } if (options.collection && options.collection !== this.users._name && options.collection !== this.users) { this.users = this._initializeCollection(options); @@ -415,14 +427,14 @@ export class AccountsCommon { /** * @summary Get the current user id, or `null` if no user is logged in. A reactive data source. - * @locus Anywhere but publish functions + * @locus Anywhere * @importFromPackage meteor */ Meteor.userId = () => Accounts.userId(); /** * @summary Get the current user record, or `null` if no user is logged in. A reactive data source. - * @locus Anywhere but publish functions + * @locus Anywhere * @importFromPackage meteor * @param {Object} [options] * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. @@ -431,7 +443,7 @@ Meteor.user = options => Accounts.user(options); /** * @summary Get the current user record, or `null` if no user is logged in. A reactive data source. - * @locus Anywhere but publish functions + * @locus Anywhere * @importFromPackage meteor * @param {Object} [options] * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. diff --git a/packages/accounts-base/accounts_reconnect_tests.js b/packages/accounts-base/accounts_reconnect_tests.js index 064821538f..8341cf0a5d 100644 --- a/packages/accounts-base/accounts_reconnect_tests.js +++ b/packages/accounts-base/accounts_reconnect_tests.js @@ -1,8 +1,11 @@ if (Meteor.isServer) { Meteor.methods({ - getConnectionUserId: function() { + getConnectionUserId: function () { return this.userId; - } + }, + logCurrentUserId: function () { + return this.userId; + }, }); } @@ -128,4 +131,38 @@ if (Meteor.isClient) { }); } ); + // Make sure this is issue is fixed: https://forums.meteor.com/t/back-from-offline-method-does-not-apply-on-server-side/61619 + // PR #13221 + Tinytest.addAsync( + "accounts - user is in the server as soon as we reconnect", + (test, done) => { + loginAsUser1(async (err) => { + test.isUndefined(err, "Unexpected error logging in as user1"); + test.isTrue(Meteor.userId(), "User should be logged in"); + + let userId = await Meteor.callAsync("logCurrentUserId"); + test.isTrue( + userId, + "userId exists in the server while connecting is up" + ); + // 1. Disconnect client and server + Meteor.disconnect(); + test.isFalse(Meteor.status().connected); + + // 2. Invoke a method call after the disconnection + Meteor.callAsync("logCurrentUserId") + .then((id) => { + // 4. the server should still return an id after connection + test.isTrue(Meteor.status().connected); + test.isTrue(id, 'userId exists in the server after reconnect'); + }) + .finally(done); + + setTimeout(() => { + // 3. reconnect the client and server after some time + Meteor.reconnect(); + }, 1000); + }); + } + ); } diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index c304ff772e..6f0ba2098e 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1,5 +1,5 @@ import crypto from 'crypto'; -import { Meteor } from 'meteor/meteor' +import { Meteor } from 'meteor/meteor'; import { AccountsCommon, EXPIRE_TOKENS_INTERVAL_MS, @@ -14,6 +14,7 @@ const NonEmptyString = Match.Where(x => { return x.length > 0; }); + /** * @summary Constructor for the `Accounts` namespace on the server. * @locus Server @@ -71,8 +72,6 @@ export class AccountsServer extends AccountsCommon { // list of all registered handlers. this._loginHandlers = []; - - setupUsersCollection(this.users); setupDefaultLoginHandlers(this); setExpireTokensInterval(this); @@ -85,6 +84,11 @@ export class AccountsServer extends AccountsCommon { this._skipCaseInsensitiveChecksForTest = {}; + // Helper function to resolve promises if needed + this._resolvePromise = async (value) => { + return Meteor._isPromise(value) ? await value : value; + }; + this.urls = { resetPassword: (token, extraParams) => this.buildEmailUrl(`#/reset-password/${token}`, extraParams), verifyEmail: (token, extraParams) => this.buildEmailUrl(`#/verify-email/${token}`, extraParams), @@ -126,6 +130,10 @@ export class AccountsServer extends AccountsCommon { return currentInvocation.userId; } + async init() { + await setupUsersCollection(this.users); + } + /// /// LOGIN HOOKS /// @@ -178,7 +186,7 @@ export class AccountsServer extends AccountsCommon { } this._onCreateLoginTokenHook = func; - }; + } /** * @summary Customize new user creation. @@ -219,11 +227,11 @@ export class AccountsServer extends AccountsCommon { this._additionalFindUserOnExternalLogin = func; } - _validateLogin(connection, attempt) { - this._validateLoginHook.forEach(callback => { + async _validateLogin(connection, attempt) { + await this._validateLoginHook.forEachAsync(async (callback) => { let ret; try { - ret = callback(cloneAttemptWithConnection(connection, attempt)); + ret = await callback(cloneAttemptWithConnection(connection, attempt)); } catch (e) { attempt.allowed = false; @@ -245,25 +253,25 @@ export class AccountsServer extends AccountsCommon { }); }; - _successfulLogin(connection, attempt) { - this._onLoginHook.each(callback => { - callback(cloneAttemptWithConnection(connection, attempt)); + async _successfulLogin(connection, attempt) { + await this._onLoginHook.forEachAsync(async (callback) => { + await callback(cloneAttemptWithConnection(connection, attempt)); return true; }); }; - _failedLogin(connection, attempt) { - this._onLoginFailureHook.each(callback => { - callback(cloneAttemptWithConnection(connection, attempt)); + async _failedLogin(connection, attempt) { + await this._onLoginFailureHook.forEachAsync(async (callback) => { + await callback(cloneAttemptWithConnection(connection, attempt)); return true; }); }; - _successfulLogout(connection, userId) { + async _successfulLogout(connection, userId) { // don't fetch the user object unless there are some callbacks registered let user; - this._onLogoutHook.each(callback => { - if (!user && userId) user = this.users.findOne(userId, {fields: this._options.defaultFieldSelector}); + await this._onLogoutHook.forEachAsync(async callback => { + if (!user && userId) user = await this.users.findOneAsync(userId, { fields: this._options.defaultFieldSelector }); callback({ user, connection }); return true; }); @@ -294,12 +302,12 @@ export class AccountsServer extends AccountsCommon { return {$and: [{$or: orClause}, caseInsensitiveClause]}; } - _findUserByQuery = (query, options) => { + _findUserByQuery = async (query, options) => { let user = null; if (query.id) { // default field selector is added within getUserById() - user = Meteor.users.findOne(query.id, this._addDefaultFieldSelector(options)); + user = await Meteor.users.findOneAsync(query.id, this._addDefaultFieldSelector(options)); } else { options = this._addDefaultFieldSelector(options); let fieldName; @@ -315,11 +323,11 @@ export class AccountsServer extends AccountsCommon { } let selector = {}; selector[fieldName] = fieldValue; - user = Meteor.users.findOne(selector, options); + user = await Meteor.users.findOneAsync(selector, options); // If user is not found, try a case insensitive lookup if (!user) { selector = this._selectorForFastCaseInsensitiveLookup(fieldName, fieldValue); - const candidateUsers = Meteor.users.find(selector, { ...options, limit: 2 }).fetch(); + const candidateUsers = await Meteor.users.find(selector, { ...options, limit: 2 }).fetchAsync(); // No match if multiple candidates are found if (candidateUsers.length === 1) { user = candidateUsers[0]; @@ -330,6 +338,32 @@ export class AccountsServer extends AccountsCommon { return user; } + /** + * @summary Find a user by one of their email addresses. + * @locus Server + * @param {String} email The email address to look for + * @param {Object} [options] + * @param {Object} options.fields Limit the fields to return from the user document + * @returns {Promise} A user if found, else null + * @memberof Accounts + * @importFromPackage accounts-base + */ + findUserByEmail = async (email, options) => + await this._findUserByQuery({ email }, options); + + /** + * @summary Find a user by their username. + * @locus Server + * @param {String} username The username to look for + * @param {Object} [options] + * @param {Object} options.fields Limit the fields to return from the user document + * @returns {Promise} A user if found, else null + * @memberof Accounts + * @importFromPackage accounts-base + */ + findUserByUsername = async (username, options) => + await this._findUserByQuery({ username }, options); + /// /// LOGIN METHODS /// @@ -399,10 +433,10 @@ export class AccountsServer extends AccountsCommon { // indicates that the login token has already been inserted into the // database and doesn't need to be inserted again. (It's used by the // "resume" login handler). - _loginUser(methodInvocation, userId, stampedLoginToken) { + async _loginUser(methodInvocation, userId, stampedLoginToken) { if (! stampedLoginToken) { stampedLoginToken = this._generateStampedLoginToken(); - this._insertLoginToken(userId, stampedLoginToken); + await this._insertLoginToken(userId, stampedLoginToken); } // This order (and the avoidance of yields) is important to make @@ -419,7 +453,7 @@ export class AccountsServer extends AccountsCommon { ) ); - methodInvocation.setUserId(userId); + await methodInvocation.setUserId(userId); return { id: userId, @@ -452,7 +486,7 @@ export class AccountsServer extends AccountsCommon { let user; if (result.userId) - user = this.users.findOne(result.userId, {fields: this._options.defaultFieldSelector}); + user = await this.users.findOneAsync(result.userId, {fields: this._options.defaultFieldSelector}); const attempt = { type: result.type || "unknown", @@ -470,23 +504,24 @@ export class AccountsServer extends AccountsCommon { // _validateLogin may mutate `attempt` by adding an error and changing allowed // to false, but that's the only change it can make (and the user's callbacks // only get a clone of `attempt`). - this._validateLogin(methodInvocation.connection, attempt); + await this._validateLogin(methodInvocation.connection, attempt); if (attempt.allowed) { + const o = await this._loginUser( + methodInvocation, + result.userId, + result.stampedLoginToken + ) const ret = { - ...this._loginUser( - methodInvocation, - result.userId, - result.stampedLoginToken - ), + ...o, ...result.options }; ret.type = attempt.type; - this._successfulLogin(methodInvocation.connection, attempt); + await this._successfulLogin(methodInvocation.connection, attempt); return ret; } else { - this._failedLogin(methodInvocation.connection, attempt); + await this._failedLogin(methodInvocation.connection, attempt); throw attempt.error; } }; @@ -518,7 +553,7 @@ export class AccountsServer extends AccountsCommon { // is no corresponding method for a successful login; methods that can // succeed at logging a user in should always be actual login methods // (using either Accounts._loginMethod or Accounts.registerLoginHandler). - _reportLoginFailure( + async _reportLoginFailure( methodInvocation, methodName, methodArgs, @@ -533,11 +568,11 @@ export class AccountsServer extends AccountsCommon { }; if (result.userId) { - attempt.user = this.users.findOne(result.userId, {fields: this._options.defaultFieldSelector}); + attempt.user = this.users.findOneAsync(result.userId, {fields: this._options.defaultFieldSelector}); } - this._validateLogin(methodInvocation.connection, attempt); - this._failedLogin(methodInvocation.connection, attempt); + await this._validateLogin(methodInvocation.connection, attempt); + await this._failedLogin(methodInvocation.connection, attempt); // _validateLogin may mutate attempt to set a new error message. Return // the modified version. @@ -615,8 +650,8 @@ export class AccountsServer extends AccountsCommon { // Any connections associated with old-style unhashed tokens will be // in the process of becoming associated with hashed tokens and then // they'll get closed. - destroyToken(userId, loginToken) { - this.users.update(userId, { + async destroyToken(userId, loginToken) { + await this.users.updateAsync(userId, { $pull: { "services.resume.loginTokens": { $or: [ @@ -653,14 +688,14 @@ export class AccountsServer extends AccountsCommon { return await accounts._attemptLogin(this, "login", arguments, result); }; - methods.logout = function () { + methods.logout = async function () { const token = accounts._getLoginToken(this.connection.id); accounts._setLoginToken(this.userId, this.connection, null); if (token && this.userId) { - accounts.destroyToken(this.userId, token); + await accounts.destroyToken(this.userId, token); } - accounts._successfulLogout(this.connection, this.userId); - this.setUserId(null); + await accounts._successfulLogout(this.connection, this.userId); + await this.setUserId(null); }; // Generates a new login token with the same expiration as the @@ -671,8 +706,8 @@ export class AccountsServer extends AccountsCommon { // @returns Object // If successful, returns { token: , id: , // tokenExpires: }. - methods.getNewToken = function () { - const user = accounts.users.findOne(this.userId, { + methods.getNewToken = async function () { + const user = await accounts.users.findOneAsync(this.userId, { fields: { "services.resume.loginTokens": 1 } }); if (! this.userId || ! user) { @@ -691,19 +726,19 @@ export class AccountsServer extends AccountsCommon { } const newStampedToken = accounts._generateStampedLoginToken(); newStampedToken.when = currentStampedToken.when; - accounts._insertLoginToken(this.userId, newStampedToken); - return accounts._loginUser(this, this.userId, newStampedToken); + await accounts._insertLoginToken(this.userId, newStampedToken); + return await accounts._loginUser(this, this.userId, newStampedToken); }; // Removes all tokens except the token associated with the current // connection. Throws an error if the connection is not logged // in. Returns nothing on success. - methods.removeOtherTokens = function () { + methods.removeOtherTokens = async function () { if (! this.userId) { throw new Meteor.Error("You are not logged in."); } const currentToken = accounts._getLoginToken(this.connection.id); - accounts.users.update(this.userId, { + await accounts.users.updateAsync(this.userId, { $pull: { "services.resume.loginTokens": { hashedToken: { $ne: currentToken } } } @@ -712,7 +747,7 @@ export class AccountsServer extends AccountsCommon { // Allow a one-time configuration for a login service. Modifications // to this collection are also allowed in insecure mode. - methods.configureLoginService = (options) => { + methods.configureLoginService = async (options) => { check(options, Match.ObjectIncluding({service: String})); // Don't let random users configure a service we haven't added yet (so // that when we do later add it, it's set up with their configuration @@ -727,7 +762,8 @@ export class AccountsServer extends AccountsCommon { if (Package['service-configuration']) { const { ServiceConfiguration } = Package['service-configuration']; - if (ServiceConfiguration.configurations.findOne({service: options.service})) + const service = await ServiceConfiguration.configurations.findOneAsync({service: options.service}) + if (service) throw new Meteor.Error(403, `Service ${options.service} already configured`); if (Package["oauth-encryption"]) { @@ -736,7 +772,7 @@ export class AccountsServer extends AccountsCommon { options.secret = OAuthEncryption.seal(options.secret); } - ServiceConfiguration.configurations.insert(options); + await ServiceConfiguration.configurations.insertAsync(options); } }; @@ -897,10 +933,10 @@ export class AccountsServer extends AccountsCommon { // Using $addToSet avoids getting an index error if another client // logging in simultaneously has already inserted the new hashed // token. - _insertHashedLoginToken(userId, hashedToken, query) { + async _insertHashedLoginToken(userId, hashedToken, query) { query = query ? { ...query } : {}; query._id = userId; - this.users.update(query, { + await this.users.updateAsync(query, { $addToSet: { "services.resume.loginTokens": hashedToken } @@ -908,16 +944,22 @@ export class AccountsServer extends AccountsCommon { }; // Exported for tests. - _insertLoginToken(userId, stampedToken, query) { - this._insertHashedLoginToken( + async _insertLoginToken(userId, stampedToken, query) { + await this._insertHashedLoginToken( userId, this._hashStampedToken(stampedToken), query ); }; + /** + * + * @param userId + * @private + * @returns {Promise} + */ _clearAllLoginTokens(userId) { - this.users.update(userId, { + this.users.updateAsync(userId, { $set: { 'services.resume.loginTokens': [] } @@ -973,7 +1015,7 @@ export class AccountsServer extends AccountsCommon { // already -- in this case we just clean up the observe that we started). const myObserveNumber = ++this._nextUserObserveNumber; this._userObservesForConnections[connection.id] = myObserveNumber; - Meteor.defer(() => { + Meteor.defer(async () => { // If something else happened on this connection in the meantime (it got // closed, or another call to _setLoginToken happened), just do // nothing. We don't need to start an observe for an old connection or old @@ -986,7 +1028,7 @@ export class AccountsServer extends AccountsCommon { // Because we upgrade unhashed login tokens to hashed tokens at // login time, sessions will only be logged in with a hashed // token. Thus we only need to observe hashed tokens here. - const observe = this.users.find({ + const observe = await this.users.find({ _id: userId, 'services.resume.loginTokens.hashedToken': newToken }, { fields: { _id: 1 } }).observeChanges({ @@ -1045,7 +1087,7 @@ export class AccountsServer extends AccountsCommon { // tests. oldestValidDate is simulate expiring tokens without waiting // for them to actually expire. userId is used by tests to only expire // tokens for the test user. - _expirePasswordResetTokens(oldestValidDate, userId) { + async _expirePasswordResetTokens(oldestValidDate, userId) { const tokenLifetimeMs = this._getPasswordResetTokenLifetimeMs(); // when calling from a test with extra arguments, you must specify both! @@ -1063,7 +1105,7 @@ export class AccountsServer extends AccountsCommon { ] }; - expirePasswordToken(this, oldestValidDate, tokenFilter, userId); + await expirePasswordToken(this, oldestValidDate, tokenFilter, userId); } // Deletes expired password enroll tokens from the database. @@ -1072,7 +1114,7 @@ export class AccountsServer extends AccountsCommon { // tests. oldestValidDate is simulate expiring tokens without waiting // for them to actually expire. userId is used by tests to only expire // tokens for the test user. - _expirePasswordEnrollTokens(oldestValidDate, userId) { + async _expirePasswordEnrollTokens(oldestValidDate, userId) { const tokenLifetimeMs = this._getPasswordEnrollTokenLifetimeMs(); // when calling from a test with extra arguments, you must specify both! @@ -1087,7 +1129,7 @@ export class AccountsServer extends AccountsCommon { "services.password.enroll.reason": "enroll" }; - expirePasswordToken(this, oldestValidDate, tokenFilter, userId); + await expirePasswordToken(this, oldestValidDate, tokenFilter, userId); } // Deletes expired tokens from the database and closes all open connections @@ -1097,7 +1139,14 @@ export class AccountsServer extends AccountsCommon { // tests. oldestValidDate is simulate expiring tokens without waiting // for them to actually expire. userId is used by tests to only expire // tokens for the test user. - _expireTokens(oldestValidDate, userId) { + /** + * + * @param oldestValidDate + * @param userId + * @private + * @return {Promise} + */ + async _expireTokens(oldestValidDate, userId) { const tokenLifetimeMs = this._getTokenLifetimeMs(); // when calling from a test with extra arguments, you must specify both! @@ -1112,7 +1161,7 @@ export class AccountsServer extends AccountsCommon { // Backwards compatible with older versions of meteor that stored login token // timestamps as numbers. - this.users.update({ ...userFilter, + await this.users.updateAsync({ ...userFilter, $or: [ { "services.resume.loginTokens.when": { $lt: oldestValidDate } }, { "services.resume.loginTokens.when": { $lt: +oldestValidDate } } @@ -1149,7 +1198,7 @@ export class AccountsServer extends AccountsCommon { }; // Called by accounts-password - insertUserDoc(options, user) { + async insertUserDoc(options, user) { // - clone user document, to protect from modification // - add createdAt timestamp // - prepare an _id, so that you can modify other collections (eg @@ -1176,7 +1225,8 @@ export class AccountsServer extends AccountsCommon { let fullUser; if (this._onCreateUserHook) { - fullUser = this._onCreateUserHook(options, user); + // Allows _onCreateUserHook to be a promise returning func + fullUser = await this._onCreateUserHook(options, user); // This is *not* part of the API. We need this because we can't isolate // the global server environment between tests, meaning we can't test @@ -1187,14 +1237,14 @@ export class AccountsServer extends AccountsCommon { fullUser = defaultCreateUserHook(options, user); } - this._validateNewUserHooks.forEach(hook => { - if (! hook(fullUser)) + for await (const hook of this._validateNewUserHooks) { + if (! await hook(fullUser)) throw new Meteor.Error(403, "User validation failed"); - }); + } let userId; try { - userId = this.users.insert(fullUser); + userId = await this.users.insertAsync(fullUser); } catch (e) { // XXX string parsing sucks, maybe // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day @@ -1224,9 +1274,9 @@ export class AccountsServer extends AccountsCommon { /// CLEAN UP FOR `logoutOtherClients` /// - _deleteSavedTokensForUser(userId, tokensToDelete) { + async _deleteSavedTokensForUser(userId, tokensToDelete) { if (tokensToDelete) { - this.users.update(userId, { + await this.users.updateAsync(userId, { $unset: { "services.resume.haveLoginTokensToDelete": 1, "services.resume.loginTokensToDelete": 1 @@ -1245,16 +1295,24 @@ export class AccountsServer extends AccountsCommon { // shouldn't happen very often. We shouldn't put a delay here because // that would give a lot of power to an attacker with a stolen login // token and the ability to crash the server. - Meteor.startup(() => { - this.users.find({ + Meteor.startup(async () => { + const users = await this.users.find({ "services.resume.haveLoginTokensToDelete": true - }, {fields: { + }, { + fields: { "services.resume.loginTokensToDelete": 1 - }}).forEach(user => { + } + }) + users.forEach(user => { this._deleteSavedTokensForUser( user._id, user.services.resume.loginTokensToDelete - ); + ) + // We don't need to wait for this to complete. + .then(_ => _) + .catch(err => { + console.log(err); + }); }); }); }; @@ -1274,7 +1332,7 @@ export class AccountsServer extends AccountsCommon { // @returns {Object} Object with token and id keys, like the result // of the "login" method. // - updateOrCreateUserFromExternalService( + async updateOrCreateUserFromExternalService( serviceName, serviceData, options @@ -1309,17 +1367,15 @@ export class AccountsServer extends AccountsCommon { } else { selector[serviceIdKey] = serviceData.id; } - - let user = this.users.findOne(selector, {fields: this._options.defaultFieldSelector}); - + let user = await this.users.findOneAsync(selector, {fields: this._options.defaultFieldSelector}); // Check to see if the developer has a custom way to find the user outside // of the general selectors above. if (!user && this._additionalFindUserOnExternalLogin) { - user = this._additionalFindUserOnExternalLogin({serviceName, serviceData, options}) + user = await this._additionalFindUserOnExternalLogin({serviceName, serviceData, options}) } // Before continuing, run user hook to see if we should continue - if (this._beforeExternalLoginHook && !this._beforeExternalLoginHook(serviceName, serviceData, user)) { + if (this._beforeExternalLoginHook && !(await this._beforeExternalLoginHook(serviceName, serviceData, user))) { throw new Meteor.Error(403, "Login forbidden"); } @@ -1331,11 +1387,11 @@ export class AccountsServer extends AccountsCommon { // needed. let opts = user ? {} : options; if (this._onExternalLoginHook) { - opts = this._onExternalLoginHook(options, user); + opts = await this._onExternalLoginHook(options, user); } if (user) { - pinEncryptedFieldsToUser(serviceData, user._id); + await pinEncryptedFieldsToUser(serviceData, user._id); let setAttrs = {}; Object.keys(serviceData).forEach(key => @@ -1345,7 +1401,7 @@ export class AccountsServer extends AccountsCommon { // XXX Maybe we should re-use the selector above and notice if the update // touches nothing? setAttrs = { ...setAttrs, ...opts }; - this.users.update(user._id, { + await this.users.updateAsync(user._id, { $set: setAttrs }); @@ -1357,9 +1413,10 @@ export class AccountsServer extends AccountsCommon { // Create a new user with the service data. user = {services: {}}; user.services[serviceName] = serviceData; + const userId = await this.insertUserDoc(opts, user); return { type: serviceName, - userId: this.insertUserDoc(opts, user) + userId }; } }; @@ -1405,21 +1462,21 @@ export class AccountsServer extends AccountsCommon { * @returns {Object} Options which can be passed to `Email.send`. * @importFromPackage accounts-base */ - generateOptionsForEmail(email, user, url, reason, extra = {}){ + async generateOptionsForEmail(email, user, url, reason, extra = {}){ const options = { to: email, from: this.emailTemplates[reason].from - ? this.emailTemplates[reason].from(user) + ? await this.emailTemplates[reason].from(user) : this.emailTemplates.from, - subject: this.emailTemplates[reason].subject(user, url, extra), + subject: await this.emailTemplates[reason].subject(user, url, extra), }; if (typeof this.emailTemplates[reason].text === 'function') { - options.text = this.emailTemplates[reason].text(user, url, extra); + options.text = await this.emailTemplates[reason].text(user, url, extra); } if (typeof this.emailTemplates[reason].html === 'function') { - options.html = this.emailTemplates[reason].html(user, url, extra); + options.html = await this.emailTemplates[reason].html(user, url, extra); } if (typeof this.emailTemplates.headers === 'object') { @@ -1429,7 +1486,7 @@ export class AccountsServer extends AccountsCommon { return options; }; - _checkForCaseInsensitiveDuplicates( + async _checkForCaseInsensitiveDuplicates( fieldName, displayName, fieldValue, @@ -1443,7 +1500,7 @@ export class AccountsServer extends AccountsCommon { ); if (fieldValue && !skipCheck) { - const matchedUsers = Meteor.users + const matchedUsers = await Meteor.users .find( this._selectorForFastCaseInsensitiveLookup(fieldName, fieldValue), { @@ -1452,7 +1509,7 @@ export class AccountsServer extends AccountsCommon { limit: 2, } ) - .fetch(); + .fetchAsync(); if ( matchedUsers.length > 0 && @@ -1467,7 +1524,7 @@ export class AccountsServer extends AccountsCommon { } }; - _createUserCheckingDuplicates({ user, email, username, options }) { + async _createUserCheckingDuplicates({ user, email, username, options }) { const newUser = { ...user, ...(username ? { username } : {}), @@ -1475,28 +1532,29 @@ export class AccountsServer extends AccountsCommon { }; // Perform a case insensitive check before insert - this._checkForCaseInsensitiveDuplicates('username', 'Username', username); - this._checkForCaseInsensitiveDuplicates('emails.address', 'Email', email); + await this._checkForCaseInsensitiveDuplicates('username', 'Username', username); + await this._checkForCaseInsensitiveDuplicates('emails.address', 'Email', email); - const userId = this.insertUserDoc(options, newUser); + const userId = await this.insertUserDoc(options, newUser); // Perform another check after insert, in case a matching user has been // inserted in the meantime try { - this._checkForCaseInsensitiveDuplicates('username', 'Username', username, userId); - this._checkForCaseInsensitiveDuplicates('emails.address', 'Email', email, userId); + await this._checkForCaseInsensitiveDuplicates('username', 'Username', username, userId); + await this._checkForCaseInsensitiveDuplicates('emails.address', 'Email', email, userId); } catch (ex) { // Remove inserted user if the check fails - Meteor.users.remove(userId); + await Meteor.users.removeAsync(userId); throw ex; } return userId; } _handleError = (msg, throwError = true, errorCode = 403) => { + const isErrorAmbiguous = this._options.ambiguousErrorMessages ?? true; const error = new Meteor.Error( errorCode, - this._options.ambiguousErrorMessages - ? "Something went wrong. Please check your credentials." + isErrorAmbiguous + ? 'Something went wrong. Please check your credentials.' : msg ); if (throwError) { @@ -1549,7 +1607,7 @@ const setupDefaultLoginHandlers = accounts => { }; // Login handler for resume tokens. -const defaultResumeLoginHandler = (accounts, options) => { +const defaultResumeLoginHandler = async (accounts, options) => { if (!options.resume) return undefined; @@ -1560,7 +1618,7 @@ const defaultResumeLoginHandler = (accounts, options) => { // First look for just the new-style hashed login token, to avoid // sending the unhashed token to the database in a query if we don't // need to. - let user = accounts.users.findOne( + let user = await accounts.users.findOneAsync( {"services.resume.loginTokens.hashedToken": hashedToken}, {fields: {"services.resume.loginTokens.$": 1}}); @@ -1570,7 +1628,7 @@ const defaultResumeLoginHandler = (accounts, options) => { // the old-style token OR the new-style token, because another // client connection logging in simultaneously might have already // converted the token. - user = accounts.users.findOne({ + user = await accounts.users.findOneAsync({ $or: [ {"services.resume.loginTokens.hashedToken": hashedToken}, {"services.resume.loginTokens.token": options.resume} @@ -1589,13 +1647,13 @@ const defaultResumeLoginHandler = (accounts, options) => { // {hashedToken, when} for a hashed token or {token, when} for an // unhashed token. let oldUnhashedStyleToken; - let token = user.services.resume.loginTokens.find(token => + let token = await user.services.resume.loginTokens.find(token => token.hashedToken === hashedToken ); if (token) { oldUnhashedStyleToken = false; } else { - token = user.services.resume.loginTokens.find(token => + token = await user.services.resume.loginTokens.find(token => token.token === options.resume ); oldUnhashedStyleToken = true; @@ -1615,7 +1673,7 @@ const defaultResumeLoginHandler = (accounts, options) => { // after we read it). Using $addToSet avoids getting an index // error if another client logging in simultaneously has already // inserted the new hashed token. - accounts.users.update( + await accounts.users.updateAsync( { _id: user._id, "services.resume.loginTokens.token": options.resume @@ -1631,7 +1689,7 @@ const defaultResumeLoginHandler = (accounts, options) => { // Remove the old token *after* adding the new, since otherwise // another client trying to login between our removing the old and // adding the new wouldn't find a token to login with. - accounts.users.update(user._id, { + await accounts.users.updateAsync(user._id, { $pull: { "services.resume.loginTokens": { "token": options.resume } } @@ -1647,55 +1705,56 @@ const defaultResumeLoginHandler = (accounts, options) => { }; }; -const expirePasswordToken = ( - accounts, - oldestValidDate, - tokenFilter, - userId -) => { - // boolean value used to determine if this method was called from enroll account workflow - let isEnroll = false; - const userFilter = userId ? {_id: userId} : {}; - // check if this method was called from enroll account workflow - if(tokenFilter['services.password.enroll.reason']) { - isEnroll = true; - } - let resetRangeOr = { - $or: [ - { "services.password.reset.when": { $lt: oldestValidDate } }, - { "services.password.reset.when": { $lt: +oldestValidDate } } - ] - }; - if(isEnroll) { - resetRangeOr = { +const expirePasswordToken = + async ( + accounts, + oldestValidDate, + tokenFilter, + userId + ) => { + // boolean value used to determine if this method was called from enroll account workflow + let isEnroll = false; + const userFilter = userId ? { _id: userId } : {}; + // check if this method was called from enroll account workflow + if (tokenFilter['services.password.enroll.reason']) { + isEnroll = true; + } + let resetRangeOr = { $or: [ - { "services.password.enroll.when": { $lt: oldestValidDate } }, - { "services.password.enroll.when": { $lt: +oldestValidDate } } + { "services.password.reset.when": { $lt: oldestValidDate } }, + { "services.password.reset.when": { $lt: +oldestValidDate } } ] }; - } - const expireFilter = { $and: [tokenFilter, resetRangeOr] }; - if(isEnroll) { - accounts.users.update({...userFilter, ...expireFilter}, { - $unset: { - "services.password.enroll": "" - } - }, { multi: true }); - } else { - accounts.users.update({...userFilter, ...expireFilter}, { - $unset: { - "services.password.reset": "" - } - }, { multi: true }); - } + if (isEnroll) { + resetRangeOr = { + $or: [ + { "services.password.enroll.when": { $lt: oldestValidDate } }, + { "services.password.enroll.when": { $lt: +oldestValidDate } } + ] + }; + } + const expireFilter = { $and: [tokenFilter, resetRangeOr] }; + if (isEnroll) { + await accounts.users.updateAsync({ ...userFilter, ...expireFilter }, { + $unset: { + "services.password.enroll": "" + } + }, { multi: true }); + } else { + await accounts.users.updateAsync({ ...userFilter, ...expireFilter }, { + $unset: { + "services.password.reset": "" + } + }, { multi: true }); + } -}; + }; const setExpireTokensInterval = accounts => { - accounts.expireTokenInterval = Meteor.setInterval(() => { - accounts._expireTokens(); - accounts._expirePasswordResetTokens(); - accounts._expirePasswordEnrollTokens(); + accounts.expireTokenInterval = Meteor.setInterval(async () => { + await accounts._expireTokens(); + await accounts._expirePasswordResetTokens(); + await accounts._expirePasswordEnrollTokens(); }, EXPIRE_TOKENS_INTERVAL_MS); }; @@ -1756,7 +1815,7 @@ function defaultValidateNewUserHook(user) { } } -const setupUsersCollection = users => { +const setupUsersCollection = async users => { /// /// RESTRICTING WRITES TO USER OBJECTS /// @@ -1782,21 +1841,21 @@ const setupUsersCollection = users => { }); /// DEFAULT INDEXES ON USERS - users.createIndex('username', { unique: true, sparse: true }); - users.createIndex('emails.address', { unique: true, sparse: true }); - users.createIndex('services.resume.loginTokens.hashedToken', + await users.createIndexAsync('username', { unique: true, sparse: true }); + await users.createIndexAsync('emails.address', { unique: true, sparse: true }); + await users.createIndexAsync('services.resume.loginTokens.hashedToken', { unique: true, sparse: true }); - users.createIndex('services.resume.loginTokens.token', + await users.createIndexAsync('services.resume.loginTokens.token', { unique: true, sparse: true }); // For taking care of logoutOtherClients calls that crashed before the // tokens were deleted. - users.createIndex('services.resume.haveLoginTokensToDelete', + await users.createIndexAsync('services.resume.haveLoginTokensToDelete', { sparse: true }); // For expiring login tokens - users.createIndex("services.resume.loginTokens.when", { sparse: true }); + await users.createIndexAsync("services.resume.loginTokens.when", { sparse: true }); // For expiring password tokens - users.createIndex('services.password.reset.when', { sparse: true }); - users.createIndex('services.password.enroll.when', { sparse: true }); + await users.createIndexAsync('services.password.reset.when', { sparse: true }); + await users.createIndexAsync('services.password.enroll.when', { sparse: true }); }; @@ -1818,4 +1877,3 @@ const generateCasePermutationsForString = string => { } return permutations; } - diff --git a/packages/accounts-base/accounts_tests.js b/packages/accounts-base/accounts_tests.js index 3ed3e4f18b..1ad449e928 100644 --- a/packages/accounts-base/accounts_tests.js +++ b/packages/accounts-base/accounts_tests.js @@ -5,27 +5,19 @@ import { Accounts } from 'meteor/accounts-base'; import { Random } from 'meteor/random'; Meteor.methods({ - getCurrentLoginToken: function () { + getCurrentLoginToken: async function () { return Accounts._getLoginToken(this.connection.id); } }); -// XXX it'd be cool to also test that the right thing happens if options -// *are* validated, but Accounts._options is global state which makes this hard -// (impossible?) -Tinytest.add( - 'accounts - config validates keys', - test => test.throws(() => Accounts.config({foo: "bar"})) -); - -Tinytest.add('accounts - config - token lifetime', test => { +Tinytest.addAsync('accounts - config - token lifetime', async test => { const { loginExpirationInDays } = Accounts._options; Accounts._options.loginExpirationInDays = 2; test.equal(Accounts._getTokenLifetimeMs(), 2 * 24 * 60 * 60 * 1000); Accounts._options.loginExpirationInDays = loginExpirationInDays; }); -Tinytest.add('accounts - config - unexpiring tokens', test => { +Tinytest.addAsync('accounts - config - unexpiring tokens', async test => { const { loginExpirationInDays } = Accounts._options; // When setting loginExpirationInDays to null in the global Accounts @@ -53,7 +45,7 @@ Tinytest.add('accounts - config - unexpiring tokens', test => { Accounts._options.loginExpirationInDays = loginExpirationInDays; }); -Tinytest.add('accounts - config - default token lifetime', test => { +Tinytest.addAsync('accounts - config - default token lifetime', async test => { const options = Accounts._options; Accounts._options = {}; test.equal( @@ -63,11 +55,11 @@ Tinytest.add('accounts - config - default token lifetime', test => { Accounts._options = options; }); -Tinytest.add('accounts - config - defaultFieldSelector', test => { +Tinytest.addAsync('accounts - config - defaultFieldSelector', async test => { const options = Accounts._options; Accounts._options = {}; - const setValue = {bigArray: 0}; - Accounts.config({defaultFieldSelector: setValue}); + const setValue = { bigArray: 0 }; + Accounts.config({ defaultFieldSelector: setValue }); test.equal(Accounts._options.defaultFieldSelector, setValue); Accounts._options = options; }); @@ -78,154 +70,51 @@ Accounts.validateNewUser(user => { return true; }); -Tinytest.add('accounts - validateNewUser gets passed user with _id', test => { - const newUserId = Accounts.updateOrCreateUserFromExternalService('foobook', {id: Random.id()}).userId; - test.isTrue(newUserId in idsInValidateNewUser); +Tinytest.addAsync('accounts - validateNewUser gets passed user with _id', async test => { + const { userId } = await Accounts.updateOrCreateUserFromExternalService('foobook', { id: Random.id() }); + test.isTrue(userId in idsInValidateNewUser); }); -Tinytest.add('accounts - updateOrCreateUserFromExternalService - Facebook', test => { - const facebookId = Random.id(); - - // create an account with facebook - const uid1 = Accounts.updateOrCreateUserFromExternalService( - 'facebook', {id: facebookId, monkey: 42}, {profile: {foo: 1}}).id; - const users1 = Meteor.users.find({"services.facebook.id": facebookId}).fetch(); - test.length(users1, 1); - test.equal(users1[0].profile.foo, 1); - test.equal(users1[0].services.facebook.monkey, 42); - - // create again with the same id, see that we get the same user. - // it should update services.facebook but not profile. - const uid2 = Accounts.updateOrCreateUserFromExternalService( - 'facebook', {id: facebookId, llama: 50}, - {profile: {foo: 1000, bar: 2}}).id; - test.equal(uid1, uid2); - const users2 = Meteor.users.find({"services.facebook.id": facebookId}).fetch(); - test.length(users2, 1); - test.equal(users2[0].profile.foo, 1); - test.equal(users2[0].profile.bar, undefined); - test.equal(users2[0].services.facebook.llama, 50); - // make sure we *don't* lose values not passed this call to - // updateOrCreateUserFromExternalService - test.equal(users2[0].services.facebook.monkey, 42); - - // cleanup - Meteor.users.remove(uid1); -}); - -Tinytest.add('accounts - updateOrCreateUserFromExternalService - Meteor Developer', test => { - const developerId = Random.id(); - const uid1 = Accounts.updateOrCreateUserFromExternalService( - 'meteor-developer', - { id: developerId, username: 'meteor-developer' }, - { profile: { name: 'meteor-developer' } } - ).id; - const users1 = Meteor.users.find({ 'services.meteor-developer.id': developerId }).fetch(); - test.length(users1, 1); - test.equal(users1[0].profile.name, 'meteor-developer'); - - const uid2 = Accounts.updateOrCreateUserFromExternalService( - 'meteor-developer', - { id: developerId, username: 'meteor-developer' }, - { profile: { name: 'meteor-developer', username: 'developer' } } - ).id; - test.equal(uid1, uid2); - const users2 = Meteor.users.find({ 'services.meteor-developer.id': developerId }).fetch(); - test.length(users2, 1); - test.equal(users1[0].profile.name, 'meteor-developer'); - test.equal(users1[0].profile.username, undefined); - - // cleanup - Meteor.users.remove(uid1); -}); - -Tinytest.add('accounts - updateOrCreateUserFromExternalService - Weibo', test => { - const weiboId1 = Random.id(); - const weiboId2 = Random.id(); - - // users that have different service ids get different users - const uid1 = Accounts.updateOrCreateUserFromExternalService( - 'weibo', {id: weiboId1}, {profile: {foo: 1}}).id; - const uid2 = Accounts.updateOrCreateUserFromExternalService( - 'weibo', {id: weiboId2}, {profile: {bar: 2}}).id; - test.equal(Meteor.users.find({"services.weibo.id": {$in: [weiboId1, weiboId2]}}).count(), 2); - test.equal(Meteor.users.findOne({"services.weibo.id": weiboId1}).profile.foo, 1); - test.equal(Meteor.users.findOne({"services.weibo.id": weiboId1}).emails, undefined); - test.equal(Meteor.users.findOne({"services.weibo.id": weiboId2}).profile.bar, 2); - test.equal(Meteor.users.findOne({"services.weibo.id": weiboId2}).emails, undefined); - - // cleanup - Meteor.users.remove(uid1); - Meteor.users.remove(uid2); -}); - -Tinytest.add('accounts - updateOrCreateUserFromExternalService - Twitter', test => { - const twitterIdOld = parseInt(Random.hexString(4), 16); - const twitterIdNew = ''+twitterIdOld; - - // create an account with twitter using the old ID format of integer - const uid1 = Accounts.updateOrCreateUserFromExternalService( - 'twitter', {id: twitterIdOld, monkey: 42}, {profile: {foo: 1}}).id; - const users1 = Meteor.users.find({"services.twitter.id": twitterIdOld}).fetch(); - test.length(users1, 1); - test.equal(users1[0].profile.foo, 1); - test.equal(users1[0].services.twitter.monkey, 42); - - // Update the account with the new ID format of string - // test that the existing user is found, and that the ID - // gets updated to a string value - const uid2 = Accounts.updateOrCreateUserFromExternalService( - 'twitter', {id: twitterIdNew, monkey: 42}, {profile: {foo: 1}}).id; - test.equal(uid1, uid2); - const users2 = Meteor.users.find({"services.twitter.id": twitterIdNew}).fetch(); - test.length(users2, 1); - - // cleanup - Meteor.users.remove(uid1); -}); - - -Tinytest.add('accounts - insertUserDoc username', test => { +Tinytest.addAsync('accounts - insertUserDoc username', async test => { const userIn = { username: Random.id() }; // user does not already exist. create a user object with fields set. - const userId = Accounts.insertUserDoc( - {profile: {name: 'Foo Bar'}}, + const userId = await Accounts.insertUserDoc( + { profile: { name: 'Foo Bar' } }, userIn ); - const userOut = Meteor.users.findOne(userId); - + const userOut = await Meteor.users.findOneAsync(userId); test.equal(typeof userOut.createdAt, 'object'); test.equal(userOut.profile.name, 'Foo Bar'); test.equal(userOut.username, userIn.username); // run the hook again. now the user exists, so it throws an error. - test.throws( - () => Accounts.insertUserDoc({profile: {name: 'Foo Bar'}}, userIn), + await test.throwsAsync( + async () => await Accounts.insertUserDoc({ profile: { name: 'Foo Bar' } }, userIn), 'Username already exists.' ); // cleanup - Meteor.users.remove(userId); + await Meteor.users.removeAsync(userId); }); -Tinytest.add('accounts - insertUserDoc email', test => { +Tinytest.addAsync('accounts - insertUserDoc email', async test => { const email1 = Random.id(); const email2 = Random.id(); const email3 = Random.id(); const userIn = { - emails: [{address: email1, verified: false}, - {address: email2, verified: true}] + emails: [{ address: email1, verified: false }, + { address: email2, verified: true }] }; // user does not already exist. create a user object with fields set. - const userId = Accounts.insertUserDoc( - {profile: {name: 'Foo Bar'}}, + const userId = await Accounts.insertUserDoc( + { profile: { name: 'Foo Bar' } }, userIn ); - const userOut = Meteor.users.findOne(userId); + const userOut = await Meteor.users.findOneAsync(userId); test.equal(typeof userOut.createdAt, 'object'); test.equal(userOut.profile.name, 'Foo Bar'); @@ -233,43 +122,47 @@ Tinytest.add('accounts - insertUserDoc email', test => { // run the hook again with the exact same emails. // run the hook again. now the user exists, so it throws an error. - test.throws( - () => Accounts.insertUserDoc({profile: {name: 'Foo Bar'}}, userIn), + await test.throwsAsync( + async () => await Accounts.insertUserDoc({ profile: { name: 'Foo Bar' } }, userIn), 'Email already exists.' ); // now with only one of them. - test.throws(() => - Accounts.insertUserDoc({}, {emails: [{address: email1}]}), + await test.throwsAsync( + async () => + await Accounts.insertUserDoc({}, { emails: [{ address: email1 }] }), 'Email already exists.' ); - test.throws(() => - Accounts.insertUserDoc({}, {emails: [{address: email2}]}), + await test.throwsAsync( + async () => + await Accounts.insertUserDoc({}, { emails: [{ address: email2 }] }), 'Email already exists.' ); // a third email works. - const userId3 = Accounts.insertUserDoc( - {}, {emails: [{address: email3}]} + const userId3 = await Accounts.insertUserDoc( + {}, { emails: [{ address: email3 }] } ); - const user3 = Meteor.users.findOne(userId3); + const user3 = await Meteor.users.findOneAsync(userId3); test.equal(typeof user3.createdAt, 'object'); // cleanup - Meteor.users.remove(userId); - Meteor.users.remove(userId3); + await Meteor.users.removeAsync(userId); + await Meteor.users.removeAsync(userId3); }); // More token expiration tests are in accounts-password -Tinytest.addAsync('accounts - expire numeric token', (test, onComplete) => { +Tinytest.addAsync('accounts - expire numeric token', async (test, onComplete) => { const userIn = { username: Random.id() }; - const userId = Accounts.insertUserDoc({ profile: { - name: 'Foo Bar' - } }, userIn); + const userId = await Accounts.insertUserDoc({ + profile: { + name: 'Foo Bar' + } + }, userIn); const date = new Date(new Date() - 5000); - Meteor.users.update(userId, { + await Meteor.users.updateAsync(userId, { $set: { "services.resume.loginTokens": [{ hashedToken: Random.id(), @@ -280,59 +173,64 @@ Tinytest.addAsync('accounts - expire numeric token', (test, onComplete) => { }] } }); - const observe = Meteor.users.find(userId).observe({ + const observe = await Meteor.users.find(userId).observe({ changed: newUser => { if (newUser.services && newUser.services.resume && - (!newUser.services.resume.loginTokens || + (!newUser.services.resume.loginTokens || newUser.services.resume.loginTokens.length === 0)) { observe.stop(); onComplete(); } } }); - Accounts._expireTokens(new Date(), userId); + await Accounts._expireTokens(new Date(), userId); }); // Login tokens used to be stored unhashed in the database. We want // to make sure users can still login after upgrading. -const insertUnhashedLoginToken = (userId, stampedToken) => { - Meteor.users.update( +const insertUnhashedLoginToken = async (userId, stampedToken) => { + await Meteor.users.updateAsync( userId, - {$push: {'services.resume.loginTokens': stampedToken}} + { $push: { 'services.resume.loginTokens': stampedToken } } ); }; -Tinytest.addAsync('accounts - login token', (test, onComplete) => { +Tinytest.addAsync('accounts - login token', async (test) => { // Test that we can login when the database contains a leftover // old style unhashed login token. - const userId1 = Accounts.insertUserDoc({}, {username: Random.id()}); + const userId1 = + await Accounts.insertUserDoc({}, { username: Random.id() }); const stampedToken1 = Accounts._generateStampedLoginToken(); - insertUnhashedLoginToken(userId1, stampedToken1); + await insertUnhashedLoginToken(userId1, stampedToken1); let connection = DDP.connect(Meteor.absoluteUrl()); - connection.call('login', {resume: stampedToken1.token}); + await connection.callAsync('login', { resume: stampedToken1.token }); connection.disconnect(); // Steal the unhashed token from the database and use it to login. // This is a sanity check so that when we *can't* login with a // stolen *hashed* token, we know it's not a problem with the test. - const userId2 = Accounts.insertUserDoc({}, {username: Random.id()}); - insertUnhashedLoginToken(userId2, Accounts._generateStampedLoginToken()); - const stolenToken1 = Meteor.users.findOne(userId2).services.resume.loginTokens[0].token; + const userId2 = + await Accounts.insertUserDoc({}, { username: Random.id() }); + await insertUnhashedLoginToken(userId2, Accounts._generateStampedLoginToken()); + const user2 = await Meteor.users.findOneAsync(userId2); + const stolenToken1 = user2.services.resume.loginTokens[0].token; test.isTrue(stolenToken1); connection = DDP.connect(Meteor.absoluteUrl()); - connection.call('login', {resume: stolenToken1}); + await connection.callAsync('login', { resume: stolenToken1 }); connection.disconnect(); // Now do the same thing, this time with a stolen hashed token. - const userId3 = Accounts.insertUserDoc({}, {username: Random.id()}); - Accounts._insertLoginToken(userId3, Accounts._generateStampedLoginToken()); - const stolenToken2 = Meteor.users.findOne(userId3).services.resume.loginTokens[0].hashedToken; + const userId3 = + await Accounts.insertUserDoc({}, { username: Random.id() }); + await Accounts._insertLoginToken(userId3, Accounts._generateStampedLoginToken()); + const user3 = await Meteor.users.findOneAsync(userId3); + const stolenToken2 = user3.services.resume.loginTokens[0].hashedToken; test.isTrue(stolenToken2); connection = DDP.connect(Meteor.absoluteUrl()); // evil plan foiled - test.throws( - () => connection.call('login', {resume: stolenToken2}), + await test.throwsAsync( + async () => await connection.callAsync('login', { resume: stolenToken2 }), /You\'ve been logged out by the server/ ); connection.disconnect(); @@ -340,24 +238,25 @@ Tinytest.addAsync('accounts - login token', (test, onComplete) => { // Old style unhashed tokens are replaced by hashed tokens when // encountered. This means that after someone logins once, the // old unhashed token is no longer available to be stolen. - const userId4 = Accounts.insertUserDoc({}, {username: Random.id()}); + const userId4 = + await Accounts.insertUserDoc({}, { username: Random.id() }); const stampedToken2 = Accounts._generateStampedLoginToken(); - insertUnhashedLoginToken(userId4, stampedToken2); + await insertUnhashedLoginToken(userId4, stampedToken2); connection = DDP.connect(Meteor.absoluteUrl()); - connection.call('login', {resume: stampedToken2.token}); + await connection.callAsync('login', { resume: stampedToken2.token }); connection.disconnect(); // The token is no longer available to be stolen. - const stolenToken3 = Meteor.users.findOne(userId4).services.resume.loginTokens[0].token; + const user4 = await Meteor.users.findOneAsync(userId4); + const stolenToken3 = user4.services.resume.loginTokens[0].token; test.isFalse(stolenToken3); // After the upgrade, the client can still login with their original // unhashed login token. connection = DDP.connect(Meteor.absoluteUrl()); - connection.call('login', {resume: stampedToken2.token}); + await connection.callAsync('login', { resume: stampedToken2.token }); connection.disconnect(); - onComplete(); }); Tinytest.addAsync( @@ -381,59 +280,64 @@ Tinytest.addAsync( } ); -Tinytest.add('accounts - get new token', test => { +Tinytest.addAsync('accounts - get new token', async test => { // Test that the `getNewToken` method returns us a valid token, with // the same expiration as our original token. - const userId = Accounts.insertUserDoc({}, { username: Random.id() }); + const userId = await Accounts.insertUserDoc({}, { username: Random.id() }); const stampedToken = Accounts._generateStampedLoginToken(); - Accounts._insertLoginToken(userId, stampedToken); - const conn = DDP.connect(Meteor.absoluteUrl()); - conn.call('login', { resume: stampedToken.token }); - test.equal(conn.call('getCurrentLoginToken'), - Accounts._hashLoginToken(stampedToken.token)); + await Accounts._insertLoginToken(userId, stampedToken); - const newTokenResult = conn.call('getNewToken'); + const conn = DDP.connect(Meteor.absoluteUrl()); + await conn.callAsync('login', { resume: stampedToken.token }); + test.equal(await conn.callAsync('getCurrentLoginToken'), + Accounts._hashLoginToken(stampedToken.token)); + + const newTokenResult = await conn.callAsync('getNewToken'); test.equal(newTokenResult.tokenExpires, - Accounts._tokenExpiration(stampedToken.when)); - test.equal(conn.call('getCurrentLoginToken'), - Accounts._hashLoginToken(newTokenResult.token)); + Accounts._tokenExpiration(stampedToken.when)); + const token = await conn.callAsync('getCurrentLoginToken'); + test.equal(await conn.callAsync('getCurrentLoginToken'), + Accounts._hashLoginToken(newTokenResult.token)); conn.disconnect(); // A second connection should be able to log in with the new token // we got. const secondConn = DDP.connect(Meteor.absoluteUrl()); - secondConn.call('login', { resume: newTokenResult.token }); + await secondConn.callAsync('login', { resume: newTokenResult.token }); secondConn.disconnect(); } ); -Tinytest.addAsync('accounts - remove other tokens', (test, onComplete) => { +Tinytest.addAsync('accounts - remove other tokens', async (test) => { // Test that the `removeOtherTokens` method removes all tokens other // than the caller's token, thereby logging out and closing other // connections. - const userId = Accounts.insertUserDoc({}, { username: Random.id() }); + const userId = await Accounts.insertUserDoc({}, { username: Random.id() }); const stampedTokens = []; const conns = []; - for(let i = 0; i < 2; i++) { + for (let i = 0; i < 2; i++) { stampedTokens.push(Accounts._generateStampedLoginToken()); - Accounts._insertLoginToken(userId, stampedTokens[i]); + await Accounts._insertLoginToken(userId, stampedTokens[i]); const conn = DDP.connect(Meteor.absoluteUrl()); - conn.call('login', { resume: stampedTokens[i].token }); - test.equal(conn.call('getCurrentLoginToken'), - Accounts._hashLoginToken(stampedTokens[i].token)); + await conn.callAsync('login', { resume: stampedTokens[i].token }); + test.equal(await conn.callAsync('getCurrentLoginToken'), + Accounts._hashLoginToken(stampedTokens[i].token)); conns.push(conn); - }; + } + ; - conns[0].call('removeOtherTokens'); - simplePoll(() => { - const tokens = conns.map(conn => conn.call('getCurrentLoginToken')); - return ! tokens[1] && + await conns[0].callAsync('removeOtherTokens'); + simplePoll(async () => { + let tokens = []; + for (const conn of conns) { + tokens.push(await conn.callAsync('getCurrentLoginToken')); + } + return !tokens[1] && tokens[0] === Accounts._hashLoginToken(stampedTokens[0].token); }, () => { // success conns.forEach(conn => conn.disconnect()); - onComplete(); }, () => { // timed out throw new Error("accounts - remove other tokens timed out"); @@ -442,12 +346,12 @@ Tinytest.addAsync('accounts - remove other tokens', (test, onComplete) => { } ); -Tinytest.add( +Tinytest.addAsync( 'accounts - hook callbacks can access Meteor.userId()', - test => { - const userId = Accounts.insertUserDoc({}, { username: Random.id() }); + async test => { + const userId = await Accounts.insertUserDoc({}, { username: Random.id() }); const stampedToken = Accounts._generateStampedLoginToken(); - Accounts._insertLoginToken(userId, stampedToken); + await Accounts._insertLoginToken(userId, stampedToken); const validateStopper = Accounts.validateLoginAttempt(attempt => { test.equal(Meteor.userId(), validateAttemptExpectedUserId, "validateLoginAttempt"); @@ -469,20 +373,22 @@ Tinytest.add( // On a new connection, Meteor.userId() should be null until logged in. let validateAttemptExpectedUserId = null; const onLoginExpectedUserId = userId; - conn.call('login', { resume: stampedToken.token }); + await conn.callAsync('login', { resume: stampedToken.token }); // Now that the user is logged in on the connection, Meteor.userId() should // return that user. validateAttemptExpectedUserId = userId; - conn.call('login', { resume: stampedToken.token }); + await conn.callAsync('login', { resume: stampedToken.token }); // Trigger onLoginFailure callbacks const onLoginFailureExpectedUserId = userId; - test.throws(() => conn.call('login', { resume: "bogus" }), '403'); + await test.throwsAsync( + async () => + await conn.callAsync('login', { resume: "bogus" }), '403'); // Trigger onLogout callbacks const onLogoutExpectedUserId = userId; - conn.call('logout'); + await conn.callAsync('logout'); conn.disconnect(); validateStopper.stop(); @@ -492,17 +398,18 @@ Tinytest.add( } ); -Tinytest.add( +Tinytest.addAsync( 'accounts - hook callbacks obey options.defaultFieldSelector', - test => { + async test => { const ignoreFieldName = "bigArray"; - const userId = Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1] }); + const userId = + await Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1] }); const stampedToken = Accounts._generateStampedLoginToken(); - Accounts._insertLoginToken(userId, stampedToken); + await Accounts._insertLoginToken(userId, stampedToken); const options = Accounts._options; Accounts._options = {}; - Accounts.config({defaultFieldSelector: {[ignoreFieldName]: 0}}); - test.equal(Accounts._options.defaultFieldSelector, {[ignoreFieldName]: 0}, 'defaultFieldSelector'); + Accounts.config({ defaultFieldSelector: { [ignoreFieldName]: 0 } }); + test.equal(Accounts._options.defaultFieldSelector, { [ignoreFieldName]: 0 }, 'defaultFieldSelector'); const validateStopper = Accounts.validateLoginAttempt(attempt => { test.isUndefined(allowLogin != 'bogus' ? attempt.user[ignoreFieldName] : attempt.user, "validateLoginAttempt") @@ -522,23 +429,27 @@ Tinytest.add( // test a new connection let allowLogin = true; - conn.call('login', { resume: stampedToken.token }); + await conn.callAsync('login', { resume: stampedToken.token }); // Now that the user is logged in on the connection, Meteor.userId() should // return that user. - conn.call('login', { resume: stampedToken.token }); + await conn.callAsync('login', { resume: stampedToken.token }); // Trigger onLoginFailure callbacks, this will not include the user object allowLogin = 'bogus'; - test.throws(() => conn.call('login', { resume: "bogus" }), '403'); + await test.throwsAsync( + async () => + await conn.callAsync('login', { resume: "bogus" }), '403'); // test a forced login fail which WILL include the user object allowLogin = false; - test.throws(() => conn.call('login', { resume: stampedToken.token }), '403'); + await test.throwsAsync( + async () => + await conn.callAsync('login', { resume: stampedToken.token }), '403'); // Trigger onLogout callbacks const onLogoutExpectedUserId = userId; - conn.call('logout'); + await conn.callAsync('logout'); Accounts._options = options; conn.disconnect(); @@ -549,53 +460,55 @@ Tinytest.add( } ); -Tinytest.add( +Tinytest.addAsync( 'accounts - Meteor.user() obeys options.defaultFieldSelector', - test => { + async test => { const ignoreFieldName = "bigArray"; const customField = "customField"; - const userId = Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1], [customField]: 'test' }); + const userId = + await Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1], [customField]: 'test' }); const stampedToken = Accounts._generateStampedLoginToken(); - Accounts._insertLoginToken(userId, stampedToken); + await Accounts._insertLoginToken(userId, stampedToken); const options = Accounts._options; // stub Meteor.userId() so it works outside methods and returns the correct user: const origAccountsUserId = Accounts.userId; - Accounts.userId = () => userId; + Accounts.userId = + () => userId; Accounts._options = {}; // test the field is included by default - let user = Meteor.user(); + let user = await Meteor.userAsync(); test.isNotUndefined(user[ignoreFieldName], 'included by default'); // test the field is excluded - Accounts.config({defaultFieldSelector: {[ignoreFieldName]: 0}}); - user = Meteor.user(); + Accounts.config({ defaultFieldSelector: { [ignoreFieldName]: 0 } }); + user = await Meteor.userAsync(); test.isUndefined(user[ignoreFieldName], 'excluded'); - user = Meteor.user({}); + user = await Meteor.userAsync({}); test.isUndefined(user[ignoreFieldName], 'excluded {}'); // test the field can still be retrieved if required - user = Meteor.user({fields: {[ignoreFieldName]: 1}}); + user = await Meteor.userAsync({ fields: { [ignoreFieldName]: 1 } }); test.isNotUndefined(user[ignoreFieldName], 'field can be retrieved'); test.isUndefined(user.username, 'field can be retrieved username'); // test a combined negative field specifier - user = Meteor.user({fields: {username: 0}}); + user = await Meteor.userAsync({ fields: { username: 0 } }); test.isUndefined(user[ignoreFieldName], 'combined field selector'); test.isUndefined(user.username, 'combined field selector username'); // test an explicit request for the full user object - user = Meteor.user({fields: {}}); + user = await Meteor.userAsync({ fields: {} }); 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() + Accounts.config({ defaultFieldSelector: { [customField]: 1 } }); + user = await Meteor.userAsync() test.isNotUndefined(user[customField]); test.isUndefined(user.username); test.isUndefined(user[ignoreFieldName]); @@ -611,14 +524,16 @@ Tinytest.addAsync( async test => { const ignoreFieldName = "bigArray"; const customField = "customField"; - const userId = Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1], [customField]: 'test' }); + const userId = + await Accounts.insertUserDoc({}, { username: Random.id(), [ignoreFieldName]: [1], [customField]: 'test' }); const stampedToken = Accounts._generateStampedLoginToken(); - Accounts._insertLoginToken(userId, stampedToken); + await Accounts._insertLoginToken(userId, stampedToken); const options = Accounts._options; // stub Meteor.userId() so it works outside methods and returns the correct user: const origAccountsUserId = Accounts.userId; - Accounts.userId = () => userId; + Accounts.userId = + () => userId; Accounts._options = {}; @@ -661,21 +576,25 @@ Tinytest.addAsync( Accounts.userId = origAccountsUserId; } ); -Tinytest.add( +Tinytest.addAsync( 'accounts - verify onExternalLogin hook can update oauth user profiles', - test => { + async test => { // Verify user profile data is saved properly when not using the // onExternalLogin hook. let facebookId = Random.id(); - const uid1 = Accounts.updateOrCreateUserFromExternalService( + const u1 = await Accounts.updateOrCreateUserFromExternalService( 'facebook', { id: facebookId }, { profile: { foo: 1 } }, - ).userId; + ); const ignoreFieldName = "bigArray"; - const c = Meteor.users.update(uid1, {$set: {[ignoreFieldName]: [1]}}); + + const c = + await Meteor.users.updateAsync(u1.userId, { $set: { [ignoreFieldName]: [1] } }); + let users = - Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); + await Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); + test.length(users, 1); test.equal(users[0].profile.foo, 1); test.isNotUndefined(users[0][ignoreFieldName], 'ignoreField - before limit fields'); @@ -685,19 +604,19 @@ Tinytest.add( // Also verify that the user object is filtered by _options.defaultFieldSelector const accountsOptions = Accounts._options; Accounts._options = {}; - Accounts.config({defaultFieldSelector: {[ignoreFieldName]: 0}}); + Accounts.config({ defaultFieldSelector: { [ignoreFieldName]: 0 } }); Accounts.onExternalLogin((options, user) => { options.profile.foo = 2; test.isUndefined(users[ignoreFieldName], 'ignoreField - after limit fields'); return options; }); - Accounts.updateOrCreateUserFromExternalService( + await Accounts.updateOrCreateUserFromExternalService( 'facebook', { id: facebookId }, { profile: { foo: 1 } }, ); // test.isUndefined(users[0][ignoreFieldName], 'ignoreField - fields limited'); - users = Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); + users = await Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); test.length(users, 1); test.equal(users[0].profile.foo, 2); test.isNotUndefined(users[0][ignoreFieldName], 'ignoreField - still there'); @@ -705,139 +624,149 @@ Tinytest.add( // Verify user profile data can be modified using the onExternalLogin // hook, for new users. facebookId = Random.id(); - const uid2 = Accounts.updateOrCreateUserFromExternalService( + const u2 = await Accounts.updateOrCreateUserFromExternalService( 'facebook', { id: facebookId }, { profile: { foo: 3 } }, - ).userId; - users = Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); + ); + users = await Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); test.length(users, 1); test.equal(users[0].profile.foo, 2); // Cleanup - Meteor.users.remove(uid1); - Meteor.users.remove(uid2); + await Meteor.users.removeAsync(u1); + await Meteor.users.removeAsync(u2.userId); Accounts._onExternalLoginHook = null; Accounts._options = accountsOptions; } ); -Tinytest.add( - 'accounts - verify beforeExternalLogin hook can stop user login', - test => { - // Verify user data is saved properly when not using the - // beforeExternalLogin hook. - let facebookId = Random.id(); - const uid1 = Accounts.updateOrCreateUserFromExternalService( - 'facebook', - { id: facebookId }, - { profile: { foo: 1 } }, - ).userId; - const ignoreFieldName = "bigArray"; - const c = Meteor.users.update(uid1, {$set: {[ignoreFieldName]: [1]}}); - let users = - Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); - test.length(users, 1); - test.equal(users[0].profile.foo, 1); - test.isNotUndefined(users[0][ignoreFieldName], 'ignoreField - before limit fields'); +Tinytest.addAsync( + 'accounts - verify beforeExternalLogin hook can stop user login', + async test => { + // Verify user data is saved properly when not using the + // beforeExternalLogin hook. + let facebookId = Random.id(); - // Verify that when beforeExternalLogin returns false - // that an error throws and user is not saved - Accounts.beforeExternalLogin((serviceName, serviceData, user) => { - // Check that we get the correct data - test.equal(serviceName, 'facebook'); - test.equal(serviceData, { id: facebookId }); - test.equal(user._id, uid1); - return false - }); + const u = + await Accounts.updateOrCreateUserFromExternalService( + 'facebook', + { id: facebookId }, + { profile: { foo: 1 } }, + ); - test.throws(() => Accounts.updateOrCreateUserFromExternalService( - 'facebook', - { id: facebookId }, - { profile: { foo: 1 } }, + const ignoreFieldName = "bigArray"; + + const c = + await Meteor.users.updateAsync(u.userId, { $set: { [ignoreFieldName]: [1] } }); + + let users = + await Meteor.users.find({ 'services.facebook.id': facebookId }).fetch(); + + test.length(users, 1); + test.equal(users[0].profile.foo, 1); + test.isNotUndefined(users[0][ignoreFieldName], 'ignoreField - before limit fields'); + + // Verify that when beforeExternalLogin returns false + // that an error throws and user is not saved + Accounts.beforeExternalLogin((serviceName, serviceData, user) => { + // Check that we get the correct data + test.equal(serviceName, 'facebook'); + test.equal(serviceData, { id: facebookId }); + test.equal(user._id, u.userId); + return false + }); + + await test.throwsAsync( + async () => + await Accounts.updateOrCreateUserFromExternalService( + 'facebook', + { id: facebookId }, + { profile: { foo: 1 } }, )); - // Cleanup - Meteor.users.remove(uid1); - Accounts._beforeExternalLoginHook = null; - } -); - -Tinytest.add( - 'accounts - verify setAdditionalFindUserOnExternalLogin hook can provide user', - test => { - // 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', - { id: googleId, email: testEmail }, - { profile: { foo: 1 } }, - ).userId; - - test.equal(uid0, uid1) - - // Cleanup - if (uid1 !== uid0) { - Meteor.users.remove(uid0) - } - Meteor.users.remove(uid1); - Accounts.selectCustomUserOnExternalLogin = null; + // Cleanup + await Meteor.users.removeAsync(u.userId); + Accounts._beforeExternalLoginHook = null; } ); -if(Meteor.isServer) { - Tinytest.add('accounts - config - collection - mongo.collection', test => { +Tinytest.addAsync( + 'accounts - verify setAdditionalFindUserOnExternalLogin hook can provide user', + async test => { + // create test user, without a google service + const testEmail = "test@testdomain.com" + // being sure that the user is not already in the database + await Meteor.users.removeAsync({ "emails.address": testEmail }); + const uid0 = await Accounts.createUser({ email: testEmail }) + + // Verify that user is found from email and service merged + Accounts.setAdditionalFindUserOnExternalLogin(async ({ serviceName, serviceData }) => { + if (serviceName === "google") { + return await Accounts.findUserByEmail(serviceData.email) + } + }) + + let googleId = Random.id(); + const u1 = await Accounts.updateOrCreateUserFromExternalService( + 'google', + { id: googleId, email: testEmail }, + { profile: { foo: 1 } }, + ); + test.equal(uid0, u1.userId) + + // Cleanup + if (u1.userId !== uid0) { + await Meteor.users.removeAsync(uid0) + } + await Meteor.users.removeAsync(u1.userId); + Accounts.selectCustomUserOnExternalLogin = null; + } +); + +if (Meteor.isServer) { + Tinytest.addAsync('accounts - config - collection - mongo.collection', async test => { const origCollection = Accounts.users; // create same user in two different collections - should pass const email = "test-collection@testdomain.com" - const collection0 = new Mongo.Collection('test1'); + const collection0 = new Mongo.Collection(`test1_${Random.id()}`); Accounts.config({ collection: collection0, }) - const uid0 = Accounts.createUser({email}) - Meteor.users.remove(uid0); + const uid0 = await Accounts.createUser({email}) + await Meteor.users.removeAsync(uid0); - const collection1 = new Mongo.Collection('test2'); + const collection1 = new Mongo.Collection(`test2_${Random.id()}`); Accounts.config({ collection: collection1, }) - const uid1 = Accounts.createUser({email}) - Meteor.users.remove(uid1); + const uid1 = await Accounts.createUser({email}) + await Meteor.users.removeAsync(uid1); test.notEqual(uid0, uid1); Accounts.config({ collection: origCollection, }); }); - Tinytest.add('accounts - config - collection - name', test => { + Tinytest.addAsync('accounts - config - collection - name', async test => { const origCollection = Accounts.users; // create same user in two different collections - should pass const email = "test-collection@testdomain.com" Accounts.config({ - collection: 'collection0', + collection: `collection0_${Random.id()}`, }) - const uid0 = Accounts.createUser({email}) - Meteor.users.remove(uid0); + const uid0 = await Accounts.createUser({email}) + await Meteor.users.removeAsync(uid0); Accounts.config({ - collection: 'collection1', + collection: `collection1_${Random.id()}`, }) - const uid1 = Accounts.createUser({email}) - Meteor.users.remove(uid1); + const uid1 = await Accounts.createUser({email}) + await Meteor.users.removeAsync(uid1); test.notEqual(uid0, uid1); @@ -846,19 +775,185 @@ if(Meteor.isServer) { }); }); - Tinytest.add( - 'accounts - make sure that extra params to accounts urls are added', - test => { + Tinytest.addAsync( + 'accounts - urls work with sync resolution', + async test => { // No extra params const verifyEmailURL = new URL(Accounts.urls.verifyEmail('test')); test.equal(verifyEmailURL.searchParams.toString(), ""); // Extra params - const extraParams = { test: 'success'}; + const extraParams = { test: 'success' }; const resetPasswordURL = new URL(Accounts.urls.resetPassword('test', extraParams)); test.equal(resetPasswordURL.searchParams.get('test'), extraParams.test); const enrollAccountURL = new URL(Accounts.urls.enrollAccount('test', extraParams)); test.equal(enrollAccountURL.searchParams.get('test'), extraParams.test); } ); + + Tinytest.addAsync( + 'accounts - urls work with async resolution', + async test => { + // Save original urls + const originalUrls = Accounts.urls; + try { + // Override urls methods to return Promises + Accounts.urls = { + resetPassword: (token, extraParams) => + new Promise(resolve => resolve(originalUrls.resetPassword(token, extraParams))), + verifyEmail: (token, extraParams) => + new Promise(resolve => resolve(originalUrls.verifyEmail(token, extraParams))), + loginToken: (selector, token, extraParams) => + new Promise(resolve => resolve(originalUrls.loginToken(selector, token, extraParams))), + enrollAccount: (token, extraParams) => + new Promise(resolve => resolve(originalUrls.enrollAccount(token, extraParams))), + }; + + // Test with no extra params + const verifyEmailUrl = await Accounts.urls.verifyEmail('test'); + const verifyEmailURL = new URL(verifyEmailUrl); + test.equal(verifyEmailURL.searchParams.toString(), ""); + + // Test with extra params + const extraParams = { test: 'async-success' }; + const resetPasswordUrl = await Accounts.urls.resetPassword('test', extraParams); + const resetPasswordURL = new URL(resetPasswordUrl); + test.equal(resetPasswordURL.searchParams.get('test'), extraParams.test); + + const enrollAccountUrl = await Accounts.urls.enrollAccount('test', extraParams); + const enrollAccountURL = new URL(enrollAccountUrl); + test.equal(enrollAccountURL.searchParams.get('test'), extraParams.test); + + const loginTokenUrl = await Accounts.urls.loginToken('email', 'token', extraParams); + const loginTokenURL = new URL(loginTokenUrl); + test.equal(loginTokenURL.searchParams.get('test'), extraParams.test); + } finally { + // Restore original urls + Accounts.urls = originalUrls; + } + } + ); } + +Tinytest.addAsync('accounts - updateOrCreateUserFromExternalService - Facebook', async test => { + const facebookId = Random.id(); + + // create an account with facebook + const u1 = + await Accounts.updateOrCreateUserFromExternalService( + 'facebook', { id: facebookId, monkey: 42 }, { profile: { foo: 1 } }); + const users1 = + await Meteor.users.find({ "services.facebook.id": facebookId }).fetch(); + test.length(users1, 1); + test.equal(users1[0].profile.foo, 1); + test.equal(users1[0].services.facebook.monkey, 42); + + // create again with the same id, see that we get the same user. + // it should update services.facebook but not profile. + const u2 = + await Accounts.updateOrCreateUserFromExternalService( + 'facebook', { id: facebookId, llama: 50 }, + { profile: { foo: 1000, bar: 2 } }); + test.equal(u1.id, u2.id); + const users2 = + await Meteor.users.find({ "services.facebook.id": facebookId }).fetch(); + test.length(users2, 1); + test.equal(users2[0].profile.foo, 1); + test.equal(users2[0].profile.bar, undefined); + test.equal(users2[0].services.facebook.llama, 50); + // make sure we *don't* lose values not passed this call to + // updateOrCreateUserFromExternalService + test.equal(users2[0].services.facebook.monkey, 42); + + // cleanup + await Meteor.users.removeAsync(u1.id); +}); + +Tinytest.addAsync('accounts - updateOrCreateUserFromExternalService - Meteor Developer', async test => { + const developerId = + Random.id(); + const u1 = + await Accounts.updateOrCreateUserFromExternalService( + 'meteor-developer', + { id: developerId, username: 'meteor-developer' }, + { profile: { name: 'meteor-developer' } } + ); + const users1 = + await Meteor.users.find({ 'services.meteor-developer.id': developerId }).fetch(); + test.length(users1, 1); + test.equal(users1[0].profile.name, 'meteor-developer'); + + const u2 = + await Accounts.updateOrCreateUserFromExternalService( + 'meteor-developer', + { id: developerId, username: 'meteor-developer' }, + { profile: { name: 'meteor-developer', username: 'developer' } } + ); + test.equal(u1.id, u2.id); + const users2 = + await Meteor.users.find({ 'services.meteor-developer.id': developerId }).fetch(); + test.length(users2, 1); + test.equal(users1[0].profile.name, 'meteor-developer'); + test.equal(users1[0].profile.username, undefined); + + // cleanup + await Meteor.users.removeAsync(u1); +}); + +Tinytest.addAsync('accounts - updateOrCreateUserFromExternalService - Weibo', async test => { + const weiboId1 = + Random.id(); + const weiboId2 = + Random.id(); + + // users that have different service ids get different users + const u1 = + await Accounts.updateOrCreateUserFromExternalService( + 'weibo', { id: weiboId1 }, { profile: { foo: 1 } }); + const u2 = + await Accounts.updateOrCreateUserFromExternalService( + 'weibo', { id: weiboId2 }, { profile: { bar: 2 } }); + test.equal(await Meteor.users.find({ "services.weibo.id": { $in: [weiboId1, weiboId2] } }).countAsync(), 2); + + const user1 = + await Meteor.users.findOneAsync({ "services.weibo.id": weiboId1 }); + const user2 = + await Meteor.users.findOneAsync({ "services.weibo.id": weiboId2 }); + test.equal(user1.profile.foo, 1); + test.equal(user1.emails, undefined); + test.equal(user2.profile.bar, 2); + test.equal(user2.emails, undefined); + + // cleanup + Meteor.users.removeAsync(u1.id); + Meteor.users.removeAsync(u2.id); +}); + +Tinytest.addAsync('accounts - updateOrCreateUserFromExternalService - Twitter', async test => { + const twitterIdOld = parseInt(Random.hexString(4), 16); + const twitterIdNew = '' + twitterIdOld; + + // create an account with twitter using the old ID format of integer + const u1 = + await Accounts.updateOrCreateUserFromExternalService( + 'twitter', { id: twitterIdOld, monkey: 42 }, { profile: { foo: 1 } }); + const users1 = + await Meteor.users.find({ "services.twitter.id": twitterIdOld }).fetch(); + test.length(users1, 1); + test.equal(users1[0].profile.foo, 1); + test.equal(users1[0].services.twitter.monkey, 42); + + // Update the account with the new ID format of string + // test that the existing user is found, and that the ID + // gets updated to a string value + const u2 = + await Accounts.updateOrCreateUserFromExternalService( + 'twitter', { id: twitterIdNew, monkey: 42 }, { profile: { foo: 1 } }); + test.equal(u1.id, u2.id); + const users2 = + await Meteor.users.find({ "services.twitter.id": twitterIdNew }).fetch(); + test.length(users2, 1); + + // cleanup + await Meteor.users.removeAsync(u1.id); +}); diff --git a/packages/accounts-base/accounts_tests_setup.js b/packages/accounts-base/accounts_tests_setup.js index bd79562fe0..0e211828c0 100644 --- a/packages/accounts-base/accounts_tests_setup.js +++ b/packages/accounts-base/accounts_tests_setup.js @@ -1,25 +1,27 @@ -const getTokenFromSecret = ({ selector, secret: secretParam }) => { +const getTokenFromSecret = async ({ selector, secret: secretParam }) => { let secret = secretParam; if (!secret) { const { services: { twoFactorAuthentication } = {} } = - Meteor.users.findOne(selector) || {}; + await Meteor.users.findOneAsync(selector) || {}; if (!twoFactorAuthentication) { throw new Meteor.Error(500, 'twoFactorAuthentication not set.'); } secret = twoFactorAuthentication.secret; } - const { token } = Accounts._generate2faToken(secret); + const { token } = await Accounts._generate2faToken(secret); return token; }; +Accounts.config({ ambiguousErrorMessages: false }); + Meteor.methods({ - removeAccountsTestUser(username) { - Meteor.users.remove({ username }); + async removeAccountsTestUser(username) { + await Meteor.users.removeAsync({ username }); }, - forceEnableUser2fa(selector, secret) { - Meteor.users.update( + async forceEnableUser2fa(selector, secret) { + await Meteor.users.updateAsync( selector, { $set: { @@ -30,7 +32,7 @@ Meteor.methods({ }, } ); - return getTokenFromSecret({ selector, secret }); + return await getTokenFromSecret({ selector, secret }); }, getTokenFromSecret, }); diff --git a/packages/accounts-base/client_main.js b/packages/accounts-base/client_main.js index b3022e862a..09a9cf84f9 100644 --- a/packages/accounts-base/client_main.js +++ b/packages/accounts-base/client_main.js @@ -7,7 +7,7 @@ import { * @namespace Accounts * @summary The namespace for all client-side accounts-related methods. */ -Accounts = new AccountsClient(); +Accounts = new AccountsClient(Meteor.settings?.public?.packages?.accounts || {}); /** * @summary A [Mongo.Collection](#collections) containing user documents. diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index ad337c0c85..4190011694 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,67 +1,67 @@ Package.describe({ - summary: 'A user account system', - version: '2.2.8', + summary: "A user account system", + version: "3.1.2", }); -Package.onUse(api => { - api.use('ecmascript', ['client', 'server']); - api.use('ddp-rate-limiter'); - api.use('localstorage', 'client'); - api.use('tracker', 'client'); - api.use('check', 'server'); - api.use('random', ['client', 'server']); - api.use('ejson', 'server'); - api.use('callback-hook', ['client', 'server']); - api.use('reactive-var', 'client'); - api.use('url', ['client', 'server']); +Package.onUse((api) => { + api.use("ecmascript", ["client", "server"]); + api.use("ddp-rate-limiter"); + api.use("localstorage", "client"); + api.use("tracker", "client"); + api.use("check", "server"); + api.use("random", ["client", "server"]); + api.use("ejson", "server"); + api.use("callback-hook", ["client", "server"]); + api.use("reactive-var", "client"); + api.use("url", ["client", "server"]); // needed for getting the currently logged-in user and handling reconnects - api.use('ddp', ['client', 'server']); + api.use("ddp", ["client", "server"]); // need this because of the Meteor.users collection but in the future // we'd probably want to abstract this away - api.use('mongo', ['client', 'server']); + api.use("mongo", ["client", "server"]); // If the 'blaze' package is loaded, we'll define some helpers like // {{currentUser}}. If not, no biggie. - api.use('blaze@2.5.0', 'client', { weak: true }); + api.use("blaze", "client", { weak: true }); // Allow us to detect 'autopublish', and publish some Meteor.users fields if // it's loaded. - api.use('autopublish', 'server', { weak: true }); + api.use("autopublish", "server", { weak: true }); - api.use('oauth-encryption', 'server', { weak: true }); + api.use("oauth-encryption", "server", { weak: true }); // Though this "Accounts" symbol is the only official Package export for // the accounts-base package, modules that import accounts-base will // have access to anything added to the exports object of the main // module, including AccountsClient and AccountsServer (those symbols // just won't be automatically imported as "global" variables). - api.export('Accounts'); + api.export("Accounts"); // These main modules import all the other modules that comprise the // accounts-base package, and define exports that will be accessible to // modules that import the accounts-base package. - api.mainModule('server_main.js', 'server'); - api.mainModule('client_main.js', 'client'); + api.mainModule("server_main.js", "server"); + api.mainModule("client_main.js", "client"); - api.addAssets('accounts-base.d.ts', 'server'); + api.addAssets("accounts-base.d.ts", "server"); }); -Package.onTest(api => { +Package.onTest((api) => { api.use([ - 'accounts-base', - 'ecmascript', - 'tinytest', - 'random', - 'test-helpers', - 'oauth-encryption', - 'ddp', - 'accounts-password', - 'accounts-2fa', + "accounts-base", + "ecmascript", + "tinytest", + "random", + "test-helpers", + "oauth-encryption", + "ddp", + "accounts-password", + "accounts-2fa", ]); - api.addFiles('accounts_tests_setup.js', 'server'); - api.mainModule('server_tests.js', 'server'); - api.mainModule('client_tests.js', 'client'); + api.addFiles("accounts_tests_setup.js", "server"); + api.mainModule("server_tests.js", "server"); + api.mainModule("client_tests.js", "client"); }); diff --git a/packages/accounts-base/server_main.js b/packages/accounts-base/server_main.js index db5020fed5..a9ed15c950 100644 --- a/packages/accounts-base/server_main.js +++ b/packages/accounts-base/server_main.js @@ -4,7 +4,9 @@ import { AccountsServer } from "./accounts_server.js"; * @namespace Accounts * @summary The namespace for all server-side accounts-related methods. */ -Accounts = new AccountsServer(Meteor.server); +Accounts = new AccountsServer(Meteor.server, { ...Meteor.settings.packages?.accounts, ...Meteor.settings.packages?.['accounts-base'] }); +// TODO[FIBERS]: I need TLA +Accounts.init().then(); // Users table. Don't use the normal autopublish, since we want to hide // some fields. Code to autopublish this is in accounts_server.js. @@ -15,7 +17,7 @@ Accounts = new AccountsServer(Meteor.server); * @locus Anywhere * @type {Mongo.Collection} * @importFromPackage meteor -*/ + */ Meteor.users = Accounts.users; export { diff --git a/packages/accounts-facebook/package.js b/packages/accounts-facebook/package.js index 1b165cf35e..13d701f816 100644 --- a/packages/accounts-facebook/package.js +++ b/packages/accounts-facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Login service for Facebook accounts", - version: "1.3.3", + version: '1.3.4', }); Package.onUse(api => { diff --git a/packages/accounts-github/package.js b/packages/accounts-github/package.js index ea503d2ca7..50d65d0ac0 100644 --- a/packages/accounts-github/package.js +++ b/packages/accounts-github/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Login service for Github accounts', - version: '1.5.0', + version: '1.5.1', }); Package.onUse(api => { diff --git a/packages/accounts-google/package.js b/packages/accounts-google/package.js index b16ecfb2a4..664729b133 100644 --- a/packages/accounts-google/package.js +++ b/packages/accounts-google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Login service for Google accounts", - version: "1.4.0", + version: '1.4.1', }); Package.onUse(api => { diff --git a/packages/accounts-meetup/package.js b/packages/accounts-meetup/package.js index e98d130744..b120837533 100644 --- a/packages/accounts-meetup/package.js +++ b/packages/accounts-meetup/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Login service for Meetup accounts', - version: '1.5.0', + version: '1.5.1', }); Package.onUse(api => { diff --git a/packages/accounts-meteor-developer/package.js b/packages/accounts-meteor-developer/package.js index d08919e790..da2ff364dc 100644 --- a/packages/accounts-meteor-developer/package.js +++ b/packages/accounts-meteor-developer/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Login service for Meteor developer accounts', - version: '1.5.0', + version: '1.5.1', }); Package.onUse(api => { diff --git a/packages/accounts-oauth/oauth_client.js b/packages/accounts-oauth/oauth_client.js index d47736cc84..ad28401437 100644 --- a/packages/accounts-oauth/oauth_client.js +++ b/packages/accounts-oauth/oauth_client.js @@ -74,34 +74,38 @@ Meteor.startup(() => { Accounts.oauth.tryLoginAfterPopupClosed = ( credentialToken, callback, - shouldRetry = true + timeout = 1000 ) => { - const credentialSecret = - OAuth._retrieveCredentialSecret(credentialToken); + let startTime = Date.now(); + let calledOnce = false; + let intervalId; + const checkForCredentialSecret = (clearInterval = false) => { + const credentialSecret = OAuth._retrieveCredentialSecret(credentialToken); + if (!calledOnce && (credentialSecret || clearInterval)) { + calledOnce = true; + Meteor.clearInterval(intervalId); + Accounts.callLoginMethod({ + methodArguments: [{ oauth: { credentialToken, credentialSecret } }], + userCallback: callback ? err => callback(convertError(err)) : () => {}, + }); + } else if (clearInterval) { + Meteor.clearInterval(intervalId); + } + }; + // Check immediately + checkForCredentialSecret(); + + // Then check on an interval // 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; + intervalId = Meteor.setInterval(() => { + if (Date.now() - startTime > timeout) { + checkForCredentialSecret(true); + } else { + checkForCredentialSecret(); } - Meteor.setTimeout( - () => - Accounts.oauth.tryLoginAfterPopupClosed( - credentialToken, - callback, - false - ), - 500 - ); - return; - } - // continue with the rest of the function - Accounts.callLoginMethod({ - methodArguments: [{ oauth: { credentialToken, credentialSecret } }], - userCallback: callback && (err => callback(convertError(err))), - }); + }, 250); }; Accounts.oauth.credentialRequestCompleteHandler = callback => @@ -112,4 +116,3 @@ Accounts.oauth.credentialRequestCompleteHandler = callback => Accounts.oauth.tryLoginAfterPopupClosed(credentialTokenOrError, callback); } } - diff --git a/packages/accounts-oauth/oauth_common.js b/packages/accounts-oauth/oauth_common.js index bfb99b0a5d..1760dee14f 100644 --- a/packages/accounts-oauth/oauth_common.js +++ b/packages/accounts-oauth/oauth_common.js @@ -1,24 +1,5 @@ import { Meteor } from 'meteor/meteor'; -// TODO get from account-base -// config option keys -const VALID_CONFIG_KEYS = [ - 'sendVerificationEmail', - 'forbidClientAccountCreation', - 'passwordEnrollTokenExpiration', - 'passwordEnrollTokenExpirationInDays', - 'restrictCreationByEmailDomain', - 'loginExpirationInDays', - 'loginExpiration', - 'passwordResetTokenExpirationInDays', - 'passwordResetTokenExpiration', - 'ambiguousErrorMessages', - 'bcryptRounds', - 'defaultFieldSelector', - 'loginTokenExpirationHours', - 'tokenSequenceLength', -]; - Accounts.oauth = {}; const services = {}; @@ -36,7 +17,7 @@ Accounts.oauth.registerService = name => { // so this should be a unique index. You might want to add indexes for other // fields returned by your service (eg services.github.login) but you can do // that in your app. - Meteor.users.createIndex(`services.${name}.id`, {unique: true, sparse: true}); + Meteor.users.createIndexAsync(`services.${name}.id`, {unique: true, sparse: true}); } }; @@ -72,17 +53,5 @@ Meteor.startup(() => { ); delete settings.oauthSecretKey; } - // Validate config options keys - Object.keys(settings).forEach(key => { - if (!VALID_CONFIG_KEYS.includes(key)) { - // TODO Consider just logging a debug message instead to allow for additional keys in the settings here? - throw new Meteor.Error( - `Accounts configuration: Invalid key: ${key}` - ); - } else { - // set values in Accounts._options - Accounts._options[key] = settings[key]; - } - }); } }); diff --git a/packages/accounts-oauth/oauth_server.js b/packages/accounts-oauth/oauth_server.js index f8d67eff25..c1c5bf9b55 100644 --- a/packages/accounts-oauth/oauth_server.js +++ b/packages/accounts-oauth/oauth_server.js @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor'; // Listen to calls to `login` with an oauth option set. This is where // users actually get logged in to meteor via oauth. -Accounts.registerLoginHandler(options => { +Accounts.registerLoginHandler(async options => { if (!options.oauth) return undefined; // don't handle @@ -15,7 +15,7 @@ Accounts.registerLoginHandler(options => { credentialSecret: Match.OneOf(null, String) }); - const result = OAuth.retrieveCredential(options.oauth.credentialToken, + const result = await OAuth.retrieveCredential(options.oauth.credentialToken, options.oauth.credentialSecret); if (!result) { @@ -90,8 +90,8 @@ Meteor.startup(() => { }, { "secret.algorithm": { $exists: false } }] - }).forEach(config => { - ServiceConfiguration.configurations.update(config._id, { + }).forEachAsync(async (config) => { + await ServiceConfiguration.configurations.updateAsync(config._id, { $set: { secret: OAuthEncryption.seal(config.secret) } diff --git a/packages/accounts-oauth/package.js b/packages/accounts-oauth/package.js index d26a1ff571..890762bd9b 100644 --- a/packages/accounts-oauth/package.js +++ b/packages/accounts-oauth/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Common code for OAuth-based login services", - version: "1.4.2", + version: '1.4.6', }); Package.onUse(api => { diff --git a/packages/accounts-password/.npm/package/npm-shrinkwrap.json b/packages/accounts-password/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index 10a6d03600..0000000000 --- a/packages/accounts-password/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,311 +0,0 @@ -{ - "lockfileVersion": 1, - "dependencies": { - "@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==" - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==" - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "bcrypt": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", - "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==" - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" - }, - "minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==" - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==" - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" - }, - "node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==" - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==" - }, - "npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - }, - "tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==" - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } -} diff --git a/packages/accounts-password/email_tests.js b/packages/accounts-password/email_tests.js index afcdef3905..16ca358ef5 100644 --- a/packages/accounts-password/email_tests.js +++ b/packages/accounts-password/email_tests.js @@ -49,9 +49,9 @@ testAsyncMulti("accounts emails - reset password flow", [ })); }, function (test, expect) { - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); }, function (test, expect) { @@ -62,9 +62,9 @@ testAsyncMulti("accounts emails - reset password flow", [ })); }, function (test, expect) { - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); } ]); @@ -150,10 +150,12 @@ const getVerifyEmailToken = (email, test, expect) => { })); }; -const loggedIn = (test, expect) => expect((error) => { +const loggedIn = (test, expect) => { + return expect(async (error) => { test.equal(error, undefined); - test.isTrue(Meteor.user()); + test.isTrue(await Meteor.user()); }); +}; testAsyncMulti("accounts emails - verify email flow", [ function (test, expect) { @@ -168,40 +170,44 @@ testAsyncMulti("accounts emails - verify email flow", [ {email: this.email, password: 'foobar'}, loggedIn(test, expect)); }, - function (test, expect) { - test.equal(Meteor.user().emails.length, 1); - test.equal(Meteor.user().emails[0].address, this.email); - test.isFalse(Meteor.user().emails[0].verified); + async function (test, expect) { + const u = await Meteor.userAsync(); + test.equal(u.emails.length, 1); + test.equal(u.emails[0].address, this.email); + test.isFalse(u.emails[0].verified); // We should NOT be publishing things like verification tokens! - test.isFalse(Object.prototype.hasOwnProperty.call(Meteor.user(), 'services')); + test.isFalse(Object.prototype.hasOwnProperty.call(u, 'services')); }, function (test, expect) { getVerifyEmailToken(this.email, test, expect); }, function (test, expect) { // Log out, to test that verifyEmail logs us back in. - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); }, function (test, expect) { - Accounts.verifyEmail(verifyEmailToken, - loggedIn(test, expect)); + Accounts.verifyEmail(verifyEmailToken, loggedIn(test, expect)); }, - function (test, expect) { - test.equal(Meteor.user().emails.length, 1); - test.equal(Meteor.user().emails[0].address, this.email); - test.isTrue(Meteor.user().emails[0].verified); + async function (test) { + const u = await Meteor.userAsync(); + + test.equal(u.emails.length, 1); + test.equal(u.emails[0].address, this.email); + test.isTrue(u.emails[0].verified); }, function (test, expect) { Accounts.connection.call( "addEmailForTestAndVerify", this.anotherEmail, - expect((error, result) => { + expect(async (error, result) => { + const u = await Meteor.userAsync(); + test.isFalse(error); - test.equal(Meteor.user().emails.length, 2); - test.equal(Meteor.user().emails[1].address, this.anotherEmail); - test.isFalse(Meteor.user().emails[1].verified); + test.equal(u.emails.length, 2); + test.equal(u.emails[1].address, this.anotherEmail); + test.isFalse(u.emails[1].verified); })); }, function (test, expect) { @@ -210,9 +216,9 @@ testAsyncMulti("accounts emails - verify email flow", [ function (test, expect) { // Log out, to test that verifyEmail logs us back in. (And if we don't // do that, waitUntilLoggedIn won't be able to prevent race conditions.) - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); }, function (test, expect) { @@ -226,11 +232,12 @@ testAsyncMulti("accounts emails - verify email flow", [ function (test, expect) { Accounts.connection.call( "addEmailForTestAndVerify", this.anotherEmailCaps, - expect((error, result) => { + expect(async (error, result) => { + const u = await Meteor.userAsync(); test.isFalse(error); - test.equal(Meteor.user().emails.length, 3); - test.equal(Meteor.user().emails[2].address, this.anotherEmailCaps); - test.isFalse(Meteor.user().emails[2].verified); + test.equal(u.emails.length, 3); + test.equal(u.emails[2].address, this.anotherEmailCaps); + test.isFalse(u.emails[2].verified); })); }, function (test, expect) { @@ -239,23 +246,25 @@ testAsyncMulti("accounts emails - verify email flow", [ function (test, expect) { // Log out, to test that verifyEmail logs us back in. (And if we don't // do that, waitUntilLoggedIn won't be able to prevent race conditions.) - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); }, function (test, expect) { Accounts.verifyEmail(verifyEmailToken, loggedIn(test, expect)); }, - function (test, expect) { - test.equal(Meteor.user().emails[2].address, this.anotherEmailCaps); - test.isTrue(Meteor.user().emails[2].verified); + async function (test, expect) { + const u = await Meteor.userAsync(); + + test.equal(u.emails[2].address, this.anotherEmailCaps); + test.isTrue(u.emails[2].verified); }, function (test, expect) { - Meteor.logout(expect((error) => { + Meteor.logout(expect(async (error) => { test.equal(error, undefined); - test.equal(Meteor.user(), null); + test.equal(await Meteor.user(), null); })); } ]); diff --git a/packages/accounts-password/email_tests_setup.js b/packages/accounts-password/email_tests_setup.js index 346390e63e..fe393fb663 100644 --- a/packages/accounts-password/email_tests_setup.js +++ b/packages/accounts-password/email_tests_setup.js @@ -33,24 +33,29 @@ Email.hookSend(options => { } }); -Meteor.methods({ - getInterceptedEmails: email => { - check(email, String); - return interceptedEmails[email]; - }, +Meteor.methods( + { + getInterceptedEmails: + email => { + check(email, String); + return interceptedEmails[email]; + }, - addEmailForTestAndVerify: email => { - check(email, String); - Meteor.users.update( - {_id: Accounts.userId()}, - {$push: {emails: {address: email, verified: false}}}); - Accounts.sendVerificationEmail(Accounts.userId(), email); - }, + addEmailForTestAndVerify: + async email => { + check(email, String); + await Meteor.users.updateAsync( + { _id: Accounts.userId() }, + { $push: { emails: { address: email, verified: false } } }); + await Accounts.sendVerificationEmail(Accounts.userId(), email); + }, - createUserOnServer: email => { - check(email, String); - const userId = Accounts.createUser({ email }); - Accounts.sendEnrollmentEmail(userId); - return Meteor.users.findOne(userId); + createUserOnServer: + async email => { + check(email, String); + const userId = await Accounts.createUser({ email }); + await Accounts.sendEnrollmentEmail(userId); + return await Meteor.users.findOneAsync(userId); + } } -}); +); diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index a6671e38af..f41e5b8127 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,49 +1,51 @@ -Package.describe({ - summary: 'Password support for accounts', - // Note: 2.2.0-beta.3 was published during the Meteor 1.6 prerelease - // process, so it might be best to skip to 2.3.x instead of reusing - // 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.3.4', -}); - -Npm.depends({ - bcrypt: '5.0.1', -}); - -Package.onUse(api => { - api.use(['accounts-base', 'sha', 'ejson', 'ddp'], ['client', 'server']); - - // Export Accounts (etc) to packages using this one. - api.imply('accounts-base', ['client', 'server']); - - api.use('email', 'server'); - api.use('random', 'server'); - api.use('check', 'server'); - api.use('ecmascript'); - - api.addFiles('email_templates.js', 'server'); - api.addFiles('password_server.js', 'server'); - api.addFiles('password_client.js', 'client'); -}); - -Package.onTest(api => { - api.use([ - 'accounts-password', - 'sha', - 'tinytest', - 'test-helpers', - 'tracker', - 'accounts-base', - 'random', - 'email', - 'check', - 'ddp', - 'ecmascript', - ]); - api.addFiles('password_tests_setup.js', 'server'); - api.addFiles('password_tests.js', ['client', 'server']); - api.addFiles('email_tests_setup.js', 'server'); - api.addFiles('email_tests.js', 'client'); -}); +Package.describe({ + summary: "Password support for accounts", + // Note: 2.2.0-beta.3 was published during the Meteor 1.6 prerelease + // process, so it might be best to skip to 2.3.x instead of reusing + // 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: "3.2.1", +}); + +Npm.depends({ + bcrypt: "5.0.1", + argon2: "0.41.1", +}); + +Package.onUse((api) => { + api.use(["accounts-base", "sha", "ejson", "ddp"], ["client", "server"]); + + // Export Accounts (etc) to packages using this one. + api.imply("accounts-base", ["client", "server"]); + + api.use("email", "server"); + api.use("random", "server"); + api.use("check", "server"); + api.use("ecmascript"); + + api.addFiles("email_templates.js", "server"); + api.addFiles("password_server.js", "server"); + api.addFiles("password_client.js", "client"); +}); + +Package.onTest((api) => { + api.use([ + "accounts-password", + "sha", + "tinytest", + "test-helpers", + "tracker", + "accounts-base", + "random", + "email", + "check", + "ddp", + "ecmascript" + ]); + api.addFiles("password_tests_setup.js", "server"); + api.addFiles("password_tests.js", ["client", "server"]); + api.addFiles("email_tests_setup.js", "server"); + api.addFiles("email_tests.js", "client"); + api.addFiles("password_argon_tests.js", ["client", "server"]); +}); diff --git a/packages/accounts-password/password_argon_tests.js b/packages/accounts-password/password_argon_tests.js new file mode 100644 index 0000000000..c1fb806d9a --- /dev/null +++ b/packages/accounts-password/password_argon_tests.js @@ -0,0 +1,221 @@ +if (Meteor.isServer) { + Tinytest.addAsync("passwords Argon - migration from bcrypt encryption to argon2", async (test) => { + Accounts._options.argon2Enabled = false; + const username = Random.id(); + const email = `${username}@bcrypt.com`; + const password = "password"; + const userId = await Accounts.createUser( + { + username: username, + email: email, + password: password + } + ); + Accounts._options.argon2Enabled = true; + let user = await Meteor.users.findOneAsync(userId); + const isValid = await Accounts._checkPasswordAsync(user, password); + test.equal(isValid.userId, userId, "checkPassword with bcrypt - User ID should be returned"); + test.equal(typeof isValid.error, "undefined", "checkPassword with bcrypt - No error should be returned"); + + // wait for the migration to happen + await waitUntil( + async () => { + user = await Meteor.users.findOneAsync(userId); + return ( + typeof user.services.password.bcrypt === "undefined" && + typeof user.services.password.argon2 === "string" + ); + }, + { description: "bcrypt should be unset and argon2 should be set" } + ); + + // password is still valid using argon2 + const isValidArgon = await Accounts._checkPasswordAsync(user, password); + test.equal(isValidArgon.userId, userId, "checkPassword with argon2 - User ID should be returned"); + test.equal(typeof isValidArgon.error, "undefined", "checkPassword with argon2 - No error should be returned"); + + // cleanup + Accounts._options.argon2Enabled = false; + await Meteor.users.removeAsync(userId); + }); + + + Tinytest.addAsync("passwords Argon - setPassword", async (test) => { + Accounts._options.argon2Enabled = true; + const username = Random.id(); + const email = `${username}-intercept@example.com`; + + const userId = await Accounts.createUser({ username: username, email: email }); + + let user = await Meteor.users.findOneAsync(userId); + // no services yet. + test.equal(user.services.password, undefined); + + // set a new password. + await Accounts.setPasswordAsync(userId, "new password"); + user = await Meteor.users.findOneAsync(userId); + const oldSaltedHash = user.services.password.argon2; + test.isTrue(oldSaltedHash); + // Send a reset password email (setting a reset token) and insert a login + // token. + await Accounts.sendResetPasswordEmail(userId, email); + await Accounts._insertLoginToken(userId, Accounts._generateStampedLoginToken()); + const user2 = await Meteor.users.findOneAsync(userId); + test.isTrue(user2.services.password.reset); + test.isTrue(user2.services.resume.loginTokens); + + // reset with the same password, see we get a different salted hash + await Accounts.setPasswordAsync(userId, "new password", { logout: false }); + user = await Meteor.users.findOneAsync(userId); + const newSaltedHash = user.services.password.argon2; + test.isTrue(newSaltedHash); + test.notEqual(oldSaltedHash, newSaltedHash); + // No more reset token. + const user3 = await Meteor.users.findOneAsync(userId); + test.isFalse(user3.services.password.reset); + // But loginTokens are still here since we did logout: false. + test.isTrue(user3.services.resume.loginTokens); + + // reset again, see that the login tokens are gone. + await Accounts.setPasswordAsync(userId, "new password"); + user = await Meteor.users.findOneAsync(userId); + const newerSaltedHash = user.services.password.argon2; + test.isTrue(newerSaltedHash); + test.notEqual(oldSaltedHash, newerSaltedHash); + test.notEqual(newSaltedHash, newerSaltedHash); + // No more tokens. + const user4 = await Meteor.users.findOneAsync(userId); + test.isFalse(user4.services.password.reset); + test.isFalse(user4.services.resume.loginTokens); + + // cleanup + Accounts._options.argon2Enabled = false; + await Meteor.users.removeAsync(userId); + }); + + Tinytest.addAsync("passwords Argon - migration from argon2 encryption to bcrypt", async (test) => { + Accounts._options.argon2Enabled = true; + const username = Random.id(); + const email = `${username}@bcrypt.com`; + const password = "password"; + const userId = await Accounts.createUser( + { + username: username, + email: email, + password: password + } + ); + Accounts._options.argon2Enabled = false; + let user = await Meteor.users.findOneAsync(userId); + const isValidArgon = await Accounts._checkPasswordAsync(user, password); + test.equal(isValidArgon.userId, userId, "checkPassword with argon2 - User ID should be returned"); + test.equal(typeof isValidArgon.error, "undefined", "checkPassword with argon2 - No error should be returned"); + + // wait for the migration to happen + await waitUntil( + async () => { + user = await Meteor.users.findOneAsync(userId); + return ( + typeof user.services.password.bcrypt === "string" && + typeof user.services.password.argon2 === "undefined" + ); + }, + { description: "bcrypt should be string and argon2 should be undefined" } + ); + + // password is still valid using bcrypt + const isValidBcrypt = await Accounts._checkPasswordAsync(user, password); + test.equal(isValidBcrypt.userId, userId, "checkPassword with argon2 - User ID should be returned"); + test.equal(typeof isValidBcrypt.error, "undefined", "checkPassword with argon2 - No error should be returned"); + + // cleanup + await Meteor.users.removeAsync(userId); + }); + + const getUserHashArgon2Params = function (user) { + const hash = user?.services?.password?.argon2; + return Accounts._getArgon2Params(hash); + } + const hashPasswordWithSha = function (password) { + return { + digest: SHA256(password), + algorithm: "sha-256" + }; + } + + testAsyncMulti("passwords Argon - allow custom argon2 Params and ensure migration if changed", [ + async function(test) { + Accounts._options.argon2Enabled = true; + // Verify that a argon2 hash generated for a new account uses the + // default params. + let username = Random.id(); + this.password = hashPasswordWithSha("abc123"); + this.userId1 = await Accounts.createUserAsync({ username, password: this.password }); + this.user1 = await Meteor.users.findOneAsync(this.userId1); + let argon2Params = getUserHashArgon2Params(this.user1); + test.equal(argon2Params.type, Accounts._argon2Type()); + test.equal(argon2Params.memoryCost, Accounts._argon2MemoryCost()); + test.equal(argon2Params.timeCost, Accounts._argon2TimeCost()); + test.equal(argon2Params.parallelism, Accounts._argon2Parallelism()); + + + // When a custom number of argon2 TimeCost is set via Accounts.config, + // and an account was already created using the default number of TimeCost, + // make sure that a new hash is created (and stored) using the new number + // of TimeCost, the next time the password is checked. + this.customType = "argon2d"; // argon2.argon2d = 2 + this.customTimeCost = 4; + this.customMemoryCost = 32768; + this.customParallelism = 1; + Accounts._options.argon2Type = this.customType; + Accounts._options.argon2TimeCost = this.customTimeCost; + Accounts._options.argon2MemoryCost = this.customMemoryCost; + Accounts._options.argon2Parallelism = this.customParallelism; + + await Accounts._checkPasswordAsync(this.user1, this.password); + }, + async function(test) { + const defaultType = Accounts._argon2Type(); + const defaultTimeCost = Accounts._argon2TimeCost(); + const defaultMemoryCost = Accounts._argon2MemoryCost(); + const defaultParallelism = Accounts._argon2Parallelism(); + let params; + let username; + + let resolve; + const promise = new Promise(res => resolve = res); + + Meteor.setTimeout(async () => { + this.user1 = await Meteor.users.findOneAsync(this.userId1); + params = getUserHashArgon2Params(this.user1); + test.equal(params.type, 2); + test.equal(params.timeCost, this.customTimeCost); + test.equal(params.memoryCost, this.customMemoryCost); + test.equal(params.parallelism, this.customParallelism); + + // When a custom number of argon2 TimeCost is set, make sure it's + // used for new argon2 password hashes. + username = Random.id(); + const userId2 = await Accounts.createUser({ username, password: this.password }); + const user2 = await Meteor.users.findOneAsync(userId2); + params = getUserHashArgon2Params(user2); + test.equal(params.type, 2); + test.equal(params.timeCost, this.customTimeCost); + test.equal(params.memoryCost, this.customMemoryCost); + test.equal(params.parallelism, this.customParallelism); + + // Cleanup + Accounts._options.argon2Enabled = false; + Accounts._options.argon2Type = defaultType; + Accounts._options.argon2TimeCost = defaultTimeCost; + Accounts._options.argon2MemoryCost = defaultMemoryCost; + Accounts._options.argon2Parallelism = defaultParallelism; + await Meteor.users.removeAsync(this.userId1); + await Meteor.users.removeAsync(userId2); + resolve(); + }, 1000); + + return promise; + } + ]); +} diff --git a/packages/accounts-password/password_client.js b/packages/accounts-password/password_client.js index 00eeb26dbe..e378784a40 100644 --- a/packages/accounts-password/password_client.js +++ b/packages/accounts-password/password_client.js @@ -23,7 +23,7 @@ const internalLoginWithPassword = ({ selector, password, code, callback }) => { if (error) { reportError(error, callback); } else { - callback && callback(); + callback && callback(error, result); } }, }); @@ -121,6 +121,29 @@ Accounts.createUser = (options, callback) => { }); }; + +/** + * @summary Create a new user and returns a promise of its result. + * @locus Anywhere + * @param {Object} options + * @param {String} options.username A unique name for this user. + * @param {String} options.email The user's email address. + * @param {String} options.password The user's password. This is __not__ sent in plain text over the wire. + * @param {Object} options.profile The user's profile, typically including the `name` field. + * @importFromPackage accounts-base + */ +Accounts.createUserAsync = (options) => { + return new Promise((resolve, reject) => + Accounts.createUser(options, (e) => { + if (e) { + reject(e); + } else { + resolve(); + } + }) + ); +}; + // Change password. Must be logged in. // // @param oldPassword {String|null} By default servers no longer allow diff --git a/packages/accounts-password/password_server.js b/packages/accounts-password/password_server.js index 198b7a9c34..151f9c8d5f 100644 --- a/packages/accounts-password/password_server.js +++ b/packages/accounts-password/password_server.js @@ -1,11 +1,15 @@ -import { hash as bcryptHash, compare as bcryptCompare } from 'bcrypt'; +import argon2 from "argon2"; +import { hash as bcryptHash, compare as bcryptCompare } from "bcrypt"; import { Accounts } from "meteor/accounts-base"; // Utility for grabbing user -const getUserById = (id, options) => Meteor.users.findOne(id, Accounts._addDefaultFieldSelector(options)); +const getUserById = + async (id, options) => + await Meteor.users.findOneAsync(id, Accounts._addDefaultFieldSelector(options)); -// User records have a 'services.password.bcrypt' field on them to hold -// their hashed passwords. +// User records have two fields that are used for password-based login: +// - 'services.password.bcrypt', which stores the bcrypt password, which will be deprecated +// - 'services.password.argon2', which stores the argon2 password // // When the client sends a password to the server, it can either be a // string (the plaintext password) or an object with keys 'digest' and @@ -15,130 +19,274 @@ const getUserById = (id, options) => Meteor.users.findOne(id, Accounts._addDefau // strings. // // When the server receives a plaintext password as a string, it always -// hashes it with SHA256 before passing it into bcrypt. When the server +// hashes it with SHA256 before passing it into bcrypt / argon2. When the server // receives a password as an object, it asserts that the algorithm is -// "sha-256" and then passes the digest to bcrypt. - +// "sha-256" and then passes the digest to bcrypt / argon2. Accounts._bcryptRounds = () => Accounts._options.bcryptRounds || 10; -// Given a 'password' from the client, extract the string that we should -// bcrypt. 'password' can be one of: -// - String (the plaintext password) -// - Object with 'digest' and 'algorithm' keys. 'algorithm' must be "sha-256". -// +Accounts._argon2Enabled = () => Accounts._options.argon2Enabled || false; + +const ARGON2_TYPES = { + argon2i: argon2.argon2i, + argon2d: argon2.argon2d, + argon2id: argon2.argon2id +}; + +Accounts._argon2Type = () => ARGON2_TYPES[Accounts._options.argon2Type] || argon2.argon2id; +Accounts._argon2TimeCost = () => Accounts._options.argon2TimeCost || 2; +Accounts._argon2MemoryCost = () => Accounts._options.argon2MemoryCost || 19456; +Accounts._argon2Parallelism = () => Accounts._options.argon2Parallelism || 1; + +/** + * Extracts the string to be encrypted using bcrypt or Argon2 from the given `password`. + * + * @param {string|Object} password - The password provided by the client. It can be: + * - A plaintext string password. + * - An object with the following properties: + * @property {string} digest - The hashed password. + * @property {string} algorithm - The hashing algorithm used. Must be "sha-256". + * + * @returns {string} - The resulting password string to encrypt. + * + * @throws {Error} - If the `algorithm` in the password object is not "sha-256". + */ const getPasswordString = password => { if (typeof password === "string") { password = SHA256(password); - } else { // 'password' is an object + } + else { // 'password' is an object if (password.algorithm !== "sha-256") { throw new Error("Invalid password hash algorithm. " + - "Only 'sha-256' is allowed."); + "Only 'sha-256' is allowed."); } password = password.digest; } return password; }; -// Use bcrypt to hash the password for storage in the database. -// `password` can be a string (in which case it will be run through -// SHA256 before bcrypt) or an object with properties `digest` and -// `algorithm` (in which case we bcrypt `password.digest`). -// -const hashPassword = async password => { +/** + * Encrypt the given `password` using either bcrypt or Argon2. + * @param password can be a string (in which case it will be run through SHA256 before encryption) or an object with properties `digest` and `algorithm` (in which case we bcrypt or Argon2 `password.digest`). + * @returns {Promise} The encrypted password. + */ +const hashPassword = async (password) => { password = getPasswordString(password); - return await bcryptHash(password, Accounts._bcryptRounds()); + if (Accounts._argon2Enabled() === true) { + return await argon2.hash(password, { + type: Accounts._argon2Type(), + timeCost: Accounts._argon2TimeCost(), + memoryCost: Accounts._argon2MemoryCost(), + parallelism: Accounts._argon2Parallelism() + }); + } + else { + return await bcryptHash(password, Accounts._bcryptRounds()); + } }; // Extract the number of rounds used in the specified bcrypt hash. -const getRoundsFromBcryptHash = hash => { +const getRoundsFromBcryptHash = (hash) => { let rounds; if (hash) { - const hashSegments = hash.split('$'); + const hashSegments = hash.split("$"); if (hashSegments.length > 2) { rounds = parseInt(hashSegments[2], 10); } } return rounds; }; +Accounts._getRoundsFromBcryptHash = getRoundsFromBcryptHash; -// Check whether the provided password matches the bcrypt'ed password in -// the database user record. `password` can be a string (in which case -// it will be run through SHA256 before bcrypt) or an object with -// properties `digest` and `algorithm` (in which case we bcrypt -// `password.digest`). -// -// The user parameter needs at least user._id and user.services -Accounts._checkPasswordUserFields = {_id: 1, services: 1}; -// + +/** + * Extract readable parameters from an Argon2 hash string. + * @param {string} hash - The Argon2 hash string. + * @returns {object} An object containing the parsed parameters. + * @throws {Error} If the hash format is invalid. + */ +function getArgon2Params(hash) { + const regex = /^\$(argon2(?:i|d|id))\$v=\d+\$m=(\d+),t=(\d+),p=(\d+)/; + + const match = hash.match(regex); + + if (!match) { + throw new Error("Invalid Argon2 hash format."); + } + + const [, type, memoryCost, timeCost, parallelism] = match; + + return { + type: ARGON2_TYPES[type], + timeCost: parseInt(timeCost, 10), + memoryCost: parseInt(memoryCost, 10), + parallelism: parseInt(parallelism, 10) + }; +} + +Accounts._getArgon2Params = getArgon2Params; + +const getUserPasswordHash = user => { + return user.services?.password?.argon2 || user.services?.password?.bcrypt; +}; + +Accounts._checkPasswordUserFields = { _id: 1, services: 1 }; + +const isBcrypt = (hash) => { + // bcrypt hashes start with $2a$ or $2b$ + return hash.startsWith("$2"); +}; + +const isArgon = (hash) => { + // argon2 hashes start with $argon2i$, $argon2d$ or $argon2id$ + return hash.startsWith("$argon2"); +} + +const updateUserPasswordDefered = (user, formattedPassword) => { + Meteor.defer(async () => { + await updateUserPassword(user, formattedPassword); + }); +}; + +/** + * Hashes the provided password and returns an object that can be used to update the user's password. + * @param formattedPassword + * @returns {Promise<{$set: {"services.password.bcrypt": string}}|{$unset: {"services.password.bcrypt": number}, $set: {"services.password.argon2": string}}>} + */ +const getUpdatorForUserPassword = async (formattedPassword) => { + const encryptedPassword = await hashPassword(formattedPassword); + if (Accounts._argon2Enabled() === false) { + return { + $set: { + "services.password.bcrypt": encryptedPassword + }, + $unset: { + "services.password.argon2": 1 + } + }; + } + else if (Accounts._argon2Enabled() === true) { + return { + $set: { + "services.password.argon2": encryptedPassword + }, + $unset: { + "services.password.bcrypt": 1 + } + }; + } +}; + +const updateUserPassword = async (user, formattedPassword) => { + const updator = await getUpdatorForUserPassword(formattedPassword); + await Meteor.users.updateAsync({ _id: user._id }, updator); +}; + +/** + * Checks whether the provided password matches the hashed password stored in the user's database record. + * + * @param {Object} user - The user object containing at least: + * @property {string} _id - The user's unique identifier. + * @property {Object} services - The user's services data. + * @property {Object} services.password - The user's password object. + * @property {string} [services.password.argon2] - The Argon2 hashed password. + * @property {string} [services.password.bcrypt] - The bcrypt hashed password, deprecated + * + * @param {string|Object} password - The password provided by the client. It can be: + * - A plaintext string password. + * - An object with the following properties: + * @property {string} digest - The hashed password. + * @property {string} algorithm - The hashing algorithm used. Must be "sha-256". + * + * @returns {Promise} - A result object with the following properties: + * @property {string} userId - The user's unique identifier. + * @property {Object} [error] - An error object if the password does not match or an error occurs. + * + * @throws {Error} - If an unexpected error occurs during the process. + */ const checkPasswordAsync = async (user, password) => { const result = { userId: user._id }; const formattedPassword = getPasswordString(password); - const hash = user.services.password.bcrypt; - const hashRounds = getRoundsFromBcryptHash(hash); + const hash = getUserPasswordHash(user); - if (! await bcryptCompare(formattedPassword, hash)) { - result.error = Accounts._handleError("Incorrect password", false); - } else if (hash && Accounts._bcryptRounds() != hashRounds) { - // The password checks out, but the user's bcrypt hash needs to be updated. - Meteor.defer(async () => { - Meteor.users.update({ _id: user._id }, { - $set: { - 'services.password.bcrypt': - await bcryptHash(formattedPassword, Accounts._bcryptRounds()) + const argon2Enabled = Accounts._argon2Enabled(); + if (argon2Enabled === false) { + if (isArgon(hash)) { + // this is a rollback feature, enabling to switch back from argon2 to bcrypt if needed + // TODO : deprecate this + console.warn("User has an argon2 password and argon2 is not enabled, rolling back to bcrypt encryption"); + const match = await argon2.verify(hash, formattedPassword); + if (!match) { + result.error = Accounts._handleError("Incorrect password", false); + } + else{ + // The password checks out, but the user's stored password needs to be updated to argon2 + updateUserPasswordDefered(user, { digest: formattedPassword, algorithm: "sha-256" }); + } + } + else { + const hashRounds = getRoundsFromBcryptHash(hash); + const match = await bcryptCompare(formattedPassword, hash); + if (!match) { + result.error = Accounts._handleError("Incorrect password", false); + } + else if (hash) { + const paramsChanged = hashRounds !== Accounts._bcryptRounds(); + // The password checks out, but the user's bcrypt hash needs to be updated + // to match current bcrypt settings + if (paramsChanged === true) { + updateUserPasswordDefered(user, { digest: formattedPassword, algorithm: "sha-256" }); } - }); - }); + } + } } + else if (argon2Enabled === true) { + if (isBcrypt(hash)) { + // migration code from bcrypt to argon2 + const match = await bcryptCompare(formattedPassword, hash); + if (!match) { + result.error = Accounts._handleError("Incorrect password", false); + } + else { + // The password checks out, but the user's stored password needs to be updated to argon2 + updateUserPasswordDefered(user, { digest: formattedPassword, algorithm: "sha-256" }); + } + } + else { + // argon2 password + const argon2Params = getArgon2Params(hash); + const match = await argon2.verify(hash, formattedPassword); + if (!match) { + result.error = Accounts._handleError("Incorrect password", false); + } + else if (hash) { + const paramsChanged = argon2Params.memoryCost !== Accounts._argon2MemoryCost() || + argon2Params.timeCost !== Accounts._argon2TimeCost() || + argon2Params.parallelism !== Accounts._argon2Parallelism() || + argon2Params.type !== Accounts._argon2Type(); + if (paramsChanged === true) { + // The password checks out, but the user's argon2 hash needs to be updated with the right params + updateUserPasswordDefered(user, { digest: formattedPassword, algorithm: "sha-256" }); + } + } + } + } + return result; }; -const checkPassword = (user, password) => { - return Promise.await(checkPasswordAsync(user, password)); -}; - -Accounts._checkPassword = checkPassword; -Accounts._checkPasswordAsync = checkPasswordAsync; +Accounts._checkPasswordAsync = checkPasswordAsync; /// /// LOGIN /// -/** - * @summary Finds the user with the specified username. - * First tries to match username case sensitively; if that fails, it - * tries case insensitively; but if more than one user matches the case - * insensitive search, it returns null. - * @locus Server - * @param {String} username The username to look for - * @param {Object} [options] - * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. - * @returns {Object} A user if found, else null - * @importFromPackage accounts-base - */ -Accounts.findUserByUsername = - (username, options) => Accounts._findUserByQuery({ username }, options); - -/** - * @summary Finds the user with the specified email. - * First tries to match email case sensitively; if that fails, it - * tries case insensitively; but if more than one user matches the case - * insensitive search, it returns null. - * @locus Server - * @param {String} email The email address to look for - * @param {Object} [options] - * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. - * @returns {Object} A user if found, else null - * @importFromPackage accounts-base - */ -Accounts.findUserByEmail = - (email, options) => Accounts._findUserByQuery({ email }, options); // XXX maybe this belongs in the check package const NonEmptyString = Match.Where(x => { @@ -178,7 +326,7 @@ Accounts.registerLoginHandler("password", async options => { }); - const user = Accounts._findUserByQuery(options.user, {fields: { + const user = await Accounts._findUserByQuery(options.user, {fields: { services: 1, ...Accounts._checkPasswordUserFields, }}); @@ -186,9 +334,7 @@ Accounts.registerLoginHandler("password", async options => { Accounts._handleError("User not found"); } - - if (!user.services || !user.services.password || - !user.services.password.bcrypt) { + if (!getUserPasswordHash(user)) { Accounts._handleError("User has no password set"); } @@ -220,7 +366,7 @@ Accounts.registerLoginHandler("password", async options => { /// /** - * @summary Change a user's username. Use this instead of updating the + * @summary Change a user's username asynchronously. Use this instead of updating the * database directly. The operation will fail if there is an existing user * with a username only differing in case. * @locus Server @@ -228,85 +374,94 @@ Accounts.registerLoginHandler("password", async options => { * @param {String} newUsername A new username for the user. * @importFromPackage accounts-base */ -Accounts.setUsername = (userId, newUsername) => { - check(userId, NonEmptyString); - check(newUsername, NonEmptyString); +Accounts.setUsername = + async (userId, newUsername) => { + check(userId, NonEmptyString); + check(newUsername, NonEmptyString); - const user = getUserById(userId, {fields: { - username: 1, - }}); - if (!user) { - Accounts._handleError("User not found"); - } + const user = await getUserById(userId, { + fields: { + username: 1, + } + }); - const oldUsername = user.username; + if (!user) { + Accounts._handleError("User not found"); + } - // Perform a case insensitive check for duplicates before update - Accounts._checkForCaseInsensitiveDuplicates('username', - 'Username', newUsername, user._id); + const oldUsername = user.username; - Meteor.users.update({_id: user._id}, {$set: {username: newUsername}}); - - // Perform another check after update, in case a matching user has been - // inserted in the meantime - try { - Accounts._checkForCaseInsensitiveDuplicates('username', + // Perform a case insensitive check for duplicates before update + await Accounts._checkForCaseInsensitiveDuplicates('username', 'Username', newUsername, user._id); - } catch (ex) { - // Undo update if the check fails - Meteor.users.update({_id: user._id}, {$set: {username: oldUsername}}); - throw ex; - } -}; + + await Meteor.users.updateAsync({ _id: user._id }, { $set: { username: newUsername } }); + + // Perform another check after update, in case a matching user has been + // inserted in the meantime + try { + await Accounts._checkForCaseInsensitiveDuplicates('username', + 'Username', newUsername, user._id); + } catch (ex) { + // Undo update if the check fails + await Meteor.users.updateAsync({ _id: user._id }, { $set: { username: oldUsername } }); + throw ex; + } + }; // Let the user change their own password if they know the old // password. `oldPassword` and `newPassword` should be objects with keys // `digest` and `algorithm` (representing the SHA256 of the password). -Meteor.methods({changePassword: async function (oldPassword, newPassword) { - check(oldPassword, passwordValidator); - check(newPassword, passwordValidator); +Meteor.methods( + { + changePassword: async function(oldPassword, newPassword) { + check(oldPassword, passwordValidator); + check(newPassword, passwordValidator); - if (!this.userId) { - throw new Meteor.Error(401, "Must be logged in"); - } + if (!this.userId) { + throw new Meteor.Error(401, "Must be logged in"); + } - const user = getUserById(this.userId, {fields: { - services: 1, - ...Accounts._checkPasswordUserFields, - }}); - if (!user) { - Accounts._handleError("User not found"); - } + const user = await getUserById(this.userId, { + fields: { + services: 1, + ...Accounts._checkPasswordUserFields + } + }); + if (!user) { + Accounts._handleError("User not found"); + } - if (!user.services || !user.services.password || !user.services.password.bcrypt) { - Accounts._handleError("User has no password set"); - } + if (!getUserPasswordHash(user)) { + Accounts._handleError("User has no password set"); + } - const result = await checkPasswordAsync(user, oldPassword); - if (result.error) { - throw result.error; - } + const result = await checkPasswordAsync(user, oldPassword); + if (result.error) { + throw result.error; + } - const hashed = await hashPassword(newPassword); + // It would be better if this removed ALL existing tokens and replaced + // the token for the current connection with a new one, but that would + // be tricky, so we'll settle for just replacing all tokens other than + // the one for the current connection. + const currentToken = Accounts._getLoginToken(this.connection.id); + const updator = await getUpdatorForUserPassword(newPassword); - // It would be better if this removed ALL existing tokens and replaced - // the token for the current connection with a new one, but that would - // be tricky, so we'll settle for just replacing all tokens other than - // the one for the current connection. - const currentToken = Accounts._getLoginToken(this.connection.id); - Meteor.users.update( - { _id: this.userId }, - { - $set: { 'services.password.bcrypt': hashed }, - $pull: { - 'services.resume.loginTokens': { hashedToken: { $ne: currentToken } } - }, - $unset: { 'services.password.reset': 1 } + await Meteor.users.updateAsync( + { _id: this.userId }, + { + $set: updator.$set, + $pull: { + "services.resume.loginTokens": { hashedToken: { $ne: currentToken } } + }, + $unset: { "services.password.reset": 1, ...updator.$unset } + } + ); + + return { passwordChanged: true }; } - ); - - return {passwordChanged: true}; -}}); + }); // Force change the users password. @@ -315,50 +470,34 @@ Meteor.methods({changePassword: async function (oldPassword, newPassword) { * @summary Forcibly change the password for a user. * @locus Server * @param {String} userId The id of the user to update. - * @param {String} newPassword A new password for the user. + * @param {String} newPlaintextPassword A new password for the user. * @param {Object} [options] * @param {Object} options.logout Logout all current connections with this userId (default: true) * @importFromPackage accounts-base */ -Accounts.setPasswordAsync = async (userId, newPlaintextPassword, options) => { - check(userId, String); - check(newPlaintextPassword, Match.Where(str => Match.test(str, String) && str.length <= Meteor.settings?.packages?.accounts?.passwordMaxLength || 256)); - check(options, Match.Maybe({ logout: Boolean })); - options = { logout: true , ...options }; +Accounts.setPasswordAsync = + async (userId, newPlaintextPassword, options) => { + check(userId, String); + check(newPlaintextPassword, Match.Where(str => Match.test(str, String) && str.length <= Meteor.settings?.packages?.accounts?.passwordMaxLength || 256)); + check(options, Match.Maybe({ logout: Boolean })); + options = { logout: true, ...options }; - const user = getUserById(userId, {fields: {_id: 1}}); - if (!user) { - throw new Meteor.Error(403, "User not found"); - } + const user = await getUserById(userId, { fields: { _id: 1 } }); + if (!user) { + throw new Meteor.Error(403, "User not found"); + } - const update = { - $unset: { - 'services.password.reset': 1 - }, - $set: {'services.password.bcrypt': await hashPassword(newPlaintextPassword)} + let updator = await getUpdatorForUserPassword(newPlaintextPassword); + updator.$unset = updator.$unset || {}; + updator.$unset["services.password.reset"] = 1; + + if (options.logout) { + updator.$unset["services.resume.loginTokens"] = 1; + } + + await Meteor.users.updateAsync({ _id: user._id }, updator); }; - if (options.logout) { - update.$unset['services.resume.loginTokens'] = 1; - } - - Meteor.users.update({_id: user._id}, update); -}; - -/** - * @summary Forcibly change the password for a user. - * @locus Server - * @param {String} userId The id of the user to update. - * @param {String} newPassword A new password for the user. - * @param {Object} [options] - * @param {Object} options.logout Logout all current connections with this userId (default: true) - * @importFromPackage accounts-base - */ -Accounts.setPassword = (userId, newPlaintextPassword, options) => { - return Promise.await(Accounts.setPasswordAsync(userId, newPlaintextPassword, options)); -}; - - /// /// RESETTING VIA EMAIL /// @@ -368,10 +507,10 @@ const pluckAddresses = (emails = []) => emails.map(email => email.address); // Method called by a user to request a password reset email. This is // the start of the reset process. -Meteor.methods({forgotPassword: options => { +Meteor.methods({forgotPassword: async options => { check(options, {email: String}) - const user = Accounts.findUserByEmail(options.email, { fields: { emails: 1 } }); + const user = await Accounts.findUserByEmail(options.email, { fields: { emails: 1 } }); if (!user) { Accounts._handleError("User not found"); @@ -382,24 +521,25 @@ Meteor.methods({forgotPassword: options => { email => email.toLowerCase() === options.email.toLowerCase() ); - Accounts.sendResetPasswordEmail(user._id, caseSensitiveEmail); + await Accounts.sendResetPasswordEmail(user._id, caseSensitiveEmail); }}); /** - * @summary Generates a reset token and saves it into the database. + * @summary Asynchronously generates a reset token and saves it into the database. * @locus Server * @param {String} userId The id of the user to generate the reset token for. * @param {String} email Which address of the user to generate the reset token for. This address must be in the user's `emails` list. If `null`, defaults to the first email in the list. * @param {String} reason `resetPassword` or `enrollAccount`. * @param {Object} [extraTokenData] Optional additional data to be added into the token record. - * @returns {Object} Object with {email, user, token} values. + * @returns {Promise} Promise of an object with {email, user, token} values. * @importFromPackage accounts-base */ -Accounts.generateResetToken = (userId, email, reason, extraTokenData) => { +Accounts.generateResetToken = + async (userId, email, reason, extraTokenData) => { // Make sure the user exists, and email is one of their addresses. // Don't limit the fields in the user object since the user is returned // by the function and some other fields might be used elsewhere. - const user = getUserById(userId); + const user = await getUserById(userId); if (!user) { Accounts._handleError("Can't find user"); } @@ -437,41 +577,49 @@ Accounts.generateResetToken = (userId, email, reason, extraTokenData) => { // if this method is called from the enroll account work-flow then // store the token record in 'services.password.enroll' db field // else store the token record in in 'services.password.reset' db field - if(reason === 'enrollAccount') { - Meteor.users.update({_id: user._id}, { - $set : { - 'services.password.enroll': tokenRecord + if (reason === "enrollAccount") { + await Meteor.users.updateAsync( + { _id: user._id }, + { + $set: { + "services.password.enroll": tokenRecord + } } - }); + ); // before passing to template, update user object with new token - Meteor._ensure(user, 'services', 'password').enroll = tokenRecord; - } else { - Meteor.users.update({_id: user._id}, { - $set : { - 'services.password.reset': tokenRecord + Meteor._ensure(user, "services", "password").enroll = tokenRecord; + } + else { + await Meteor.users.updateAsync( + { _id: user._id }, + { + $set: { + "services.password.reset": tokenRecord + } } - }); + ); // before passing to template, update user object with new token - Meteor._ensure(user, 'services', 'password').reset = tokenRecord; + Meteor._ensure(user, "services", "password").reset = tokenRecord; } - return {email, user, token}; + return { email, user, token }; }; /** - * @summary Generates an e-mail verification token and saves it into the database. + * @summary Generates asynchronously an e-mail verification token and saves it into the database. * @locus Server * @param {String} userId The id of the user to generate the e-mail verification token for. * @param {String} email Which address of the user to generate the e-mail verification token for. This address must be in the user's `emails` list. If `null`, defaults to the first unverified email in the list. * @param {Object} [extraTokenData] Optional additional data to be added into the token record. - * @returns {Object} Object with {email, user, token} values. + * @returns {Promise} Promise of an object with {email, user, token} values. * @importFromPackage accounts-base */ -Accounts.generateVerificationToken = (userId, email, extraTokenData) => { +Accounts.generateVerificationToken = + async (userId, email, extraTokenData) => { // Make sure the user exists, and email is one of their addresses. // Don't limit the fields in the user object since the user is returned // by the function and some other fields might be used elsewhere. - const user = getUserById(userId); + const user = await getUserById(userId); if (!user) { Accounts._handleError("Can't find user"); } @@ -504,7 +652,7 @@ Accounts.generateVerificationToken = (userId, email, extraTokenData) => { Object.assign(tokenRecord, extraTokenData); } - Meteor.users.update({_id: user._id}, {$push: { + await Meteor.users.updateAsync({_id: user._id}, {$push: { 'services.email.verificationTokens': tokenRecord }}); @@ -523,26 +671,28 @@ Accounts.generateVerificationToken = (userId, email, extraTokenData) => { // to set a new password, without the old password. /** - * @summary Send an email with a link the user can use to reset their password. + * @summary Send an email asynchronously with a link the user can use to reset their password. * @locus Server * @param {String} userId The id of the user to send email to. * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list. * @param {Object} [extraTokenData] Optional additional data to be added into the token record. * @param {Object} [extraParams] Optional additional params to be added to the reset url. - * @returns {Object} Object with {email, user, token, url, options} values. + * @returns {Promise} Promise of an object with {email, user, token, url, options} values. * @importFromPackage accounts-base */ -Accounts.sendResetPasswordEmail = (userId, email, extraTokenData, extraParams) => { - const {email: realEmail, user, token} = - Accounts.generateResetToken(userId, email, 'resetPassword', extraTokenData); - const url = Accounts.urls.resetPassword(token, extraParams); - const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'resetPassword'); - Email.send(options); - if (Meteor.isDevelopment) { - console.log(`\nReset password URL: ${url}`); - } - return {email: realEmail, user, token, url, options}; -}; +Accounts.sendResetPasswordEmail = + async (userId, email, extraTokenData, extraParams) => { + const { email: realEmail, user, token } = + await Accounts.generateResetToken(userId, email, 'resetPassword', extraTokenData); + const url = await Accounts._resolvePromise(Accounts.urls.resetPassword(token, extraParams)); + const options = await Accounts.generateOptionsForEmail(realEmail, user, url, 'resetPassword'); + await Email.sendAsync(options); + + if (Meteor.isDevelopment && !Meteor.isPackageTest) { + console.log(`\nReset password URL: ${ url }`); + } + return { email: realEmail, user, token, url, options }; + }; // send the user an email informing them that their account was created, with // a link that when opened both marks their email as verified and forces them @@ -553,155 +703,183 @@ Accounts.sendResetPasswordEmail = (userId, email, extraTokenData, extraParams) = // want to use enrollment emails. /** - * @summary Send an email with a link the user can use to set their initial password. + * @summary Send an email asynchronously with a link the user can use to set their initial password. * @locus Server * @param {String} userId The id of the user to send email to. * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list. * @param {Object} [extraTokenData] Optional additional data to be added into the token record. * @param {Object} [extraParams] Optional additional params to be added to the enrollment url. - * @returns {Object} Object with {email, user, token, url, options} values. + * @returns {Promise} Promise of an object {email, user, token, url, options} values. * @importFromPackage accounts-base */ -Accounts.sendEnrollmentEmail = (userId, email, extraTokenData, extraParams) => { - const {email: realEmail, user, token} = - Accounts.generateResetToken(userId, email, 'enrollAccount', extraTokenData); - const url = Accounts.urls.enrollAccount(token, extraParams); - const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'enrollAccount'); - Email.send(options); - if (Meteor.isDevelopment) { - console.log(`\nEnrollment email URL: ${url}`); - } - return {email: realEmail, user, token, url, options}; -}; +Accounts.sendEnrollmentEmail = + async (userId, email, extraTokenData, extraParams) => { + + const { email: realEmail, user, token } = + await Accounts.generateResetToken(userId, email, 'enrollAccount', extraTokenData); + + const url = await Accounts._resolvePromise(Accounts.urls.enrollAccount(token, extraParams)); + + const options = + await Accounts.generateOptionsForEmail(realEmail, user, url, 'enrollAccount'); + + await Email.sendAsync(options); + if (Meteor.isDevelopment && !Meteor.isPackageTest) { + console.log(`\nEnrollment email URL: ${ url }`); + } + return { email: realEmail, user, token, url, options }; + }; // Take token from sendResetPasswordEmail or sendEnrollmentEmail, change // the users password, and log them in. -Meteor.methods({resetPassword: async function (...args) { - const token = args[0]; - const newPassword = args[1]; - return await Accounts._loginMethod( - this, - "resetPassword", - args, - "password", - async () => { - check(token, String); - check(newPassword, passwordValidator); +Meteor.methods( + { + resetPassword: + async function (...args) { + const token = args[0]; + const newPassword = args[1]; + return await Accounts._loginMethod( + this, + "resetPassword", + args, + "password", + async () => { + check(token, String); + check(newPassword, passwordValidator); + let user = await Meteor.users.findOneAsync( + { "services.password.reset.token": token }, + { + fields: { + services: 1, + emails: 1, + } + } + ); - let user = Meteor.users.findOne( - {"services.password.reset.token": token}, - {fields: { - services: 1, - emails: 1, - }} - ); + let isEnroll = false; + // if token is in services.password.reset db field implies + // this method is was not called from enroll account workflow + // else this method is called from enroll account workflow + if (!user) { + user = await Meteor.users.findOneAsync( + { "services.password.enroll.token": token }, + { + fields: { + services: 1, + emails: 1, + } + } + ); + isEnroll = true; + } + if (!user) { + throw new Meteor.Error(403, "Token expired"); + } + let tokenRecord = {}; + if (isEnroll) { + tokenRecord = user.services.password.enroll; + } else { + tokenRecord = user.services.password.reset; + } + const { when, email } = tokenRecord; + let tokenLifetimeMs = Accounts._getPasswordResetTokenLifetimeMs(); + if (isEnroll) { + tokenLifetimeMs = Accounts._getPasswordEnrollTokenLifetimeMs(); + } + const currentTimeMs = Date.now(); + if ((currentTimeMs - when) > tokenLifetimeMs) + throw new Meteor.Error(403, "Token expired"); + if (!(pluckAddresses(user.emails).includes(email))) + return { + userId: user._id, + error: new Meteor.Error(403, "Token has invalid email address") + }; - let isEnroll = false; - // if token is in services.password.reset db field implies - // this method is was not called from enroll account workflow - // else this method is called from enroll account workflow - if(!user) { - user = Meteor.users.findOne( - {"services.password.enroll.token": token}, - {fields: { - services: 1, - emails: 1, - }} + // NOTE: We're about to invalidate tokens on the user, who we might be + // logged in as. Make sure to avoid logging ourselves out if this + // happens. But also make sure not to leave the connection in a state + // of having a bad token set if things fail. + const oldToken = Accounts._getLoginToken(this.connection.id); + Accounts._setLoginToken(user._id, this.connection, null); + const resetToOldToken = () => + Accounts._setLoginToken(user._id, this.connection, oldToken); + + const updator = await getUpdatorForUserPassword(newPassword); + + try { + // Update the user record by: + // - Changing the password to the new one + // - Forgetting about the reset token or enroll token that was just used + // - Verifying their email, since they got the password reset via email. + let affectedRecords = {}; + // if reason is enroll then check services.password.enroll.token field for affected records + if (isEnroll) { + affectedRecords = await Meteor.users.updateAsync( + { + _id: user._id, + "emails.address": email, + "services.password.enroll.token": token + }, + { + $set: { + "emails.$.verified": true, + ...updator.$set + }, + $unset: { + "services.password.enroll": 1, + ...updator.$unset + } + }); + } + else { + affectedRecords = await Meteor.users.updateAsync( + { + _id: user._id, + "emails.address": email, + "services.password.reset.token": token + }, + { + $set: { + "emails.$.verified": true, + ...updator.$set + }, + $unset: { + "services.password.reset": 1, + ...updator.$unset + } + }); + } + if (affectedRecords !== 1) + return { + userId: user._id, + error: new Meteor.Error(403, "Invalid email") + }; + } catch (err) { + resetToOldToken(); + throw err; + } + + // Replace all valid login tokens with new ones (changing + // password should invalidate existing sessions). + await Accounts._clearAllLoginTokens(user._id); + + if (Accounts._check2faEnabled?.(user)) { + return { + userId: user._id, + error: Accounts._handleError( + 'Changed password, but user not logged in because 2FA is enabled', + false, + '2fa-enabled' + ), + }; + } + return { userId: user._id }; + } ); - isEnroll = true; } - if (!user) { - throw new Meteor.Error(403, "Token expired"); - } - let tokenRecord = {}; - if(isEnroll) { - tokenRecord = user.services.password.enroll; - } else { - tokenRecord = user.services.password.reset; - } - const { when, email } = tokenRecord; - let tokenLifetimeMs = Accounts._getPasswordResetTokenLifetimeMs(); - if (isEnroll) { - tokenLifetimeMs = Accounts._getPasswordEnrollTokenLifetimeMs(); - } - const currentTimeMs = Date.now(); - if ((currentTimeMs - when) > tokenLifetimeMs) - throw new Meteor.Error(403, "Token expired"); - if (!(pluckAddresses(user.emails).includes(email))) - return { - userId: user._id, - error: new Meteor.Error(403, "Token has invalid email address") - }; - - const hashed = await hashPassword(newPassword); - - // NOTE: We're about to invalidate tokens on the user, who we might be - // logged in as. Make sure to avoid logging ourselves out if this - // happens. But also make sure not to leave the connection in a state - // of having a bad token set if things fail. - const oldToken = Accounts._getLoginToken(this.connection.id); - Accounts._setLoginToken(user._id, this.connection, null); - const resetToOldToken = () => - Accounts._setLoginToken(user._id, this.connection, oldToken); - - try { - // Update the user record by: - // - Changing the password to the new one - // - Forgetting about the reset token or enroll token that was just used - // - Verifying their email, since they got the password reset via email. - let affectedRecords = {}; - // if reason is enroll then check services.password.enroll.token field for affected records - if(isEnroll) { - affectedRecords = Meteor.users.update( - { - _id: user._id, - 'emails.address': email, - 'services.password.enroll.token': token - }, - {$set: {'services.password.bcrypt': hashed, - 'emails.$.verified': true}, - $unset: {'services.password.enroll': 1 }}); - } else { - affectedRecords = Meteor.users.update( - { - _id: user._id, - 'emails.address': email, - 'services.password.reset.token': token - }, - {$set: {'services.password.bcrypt': hashed, - 'emails.$.verified': true}, - $unset: {'services.password.reset': 1 }}); - } - if (affectedRecords !== 1) - return { - userId: user._id, - error: new Meteor.Error(403, "Invalid email") - }; - } catch (err) { - resetToOldToken(); - throw err; - } - - // Replace all valid login tokens with new ones (changing - // password should invalidate existing sessions). - Accounts._clearAllLoginTokens(user._id); - - if (Accounts._check2faEnabled?.(user)) { - return { - userId: user._id, - error: Accounts._handleError( - 'Changed password, but user not logged in because 2FA is enabled', - false, - '2fa-enabled' - ), - }; - } - - return {userId: user._id}; - } - ); -}}); + } +); /// /// EMAIL VERIFICATION @@ -712,84 +890,93 @@ Meteor.methods({resetPassword: async function (...args) { // address as verified /** - * @summary Send an email with a link the user can use verify their email address. + * @summary Send an email asynchronously with a link the user can use verify their email address. * @locus Server * @param {String} userId The id of the user to send email to. * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first unverified email in the list. * @param {Object} [extraTokenData] Optional additional data to be added into the token record. * @param {Object} [extraParams] Optional additional params to be added to the verification url. - * - * @returns {Object} Object with {email, user, token, url, options} values. + * @returns {Promise} Promise of an object with {email, user, token, url, options} values. * @importFromPackage accounts-base */ -Accounts.sendVerificationEmail = (userId, email, extraTokenData, extraParams) => { - // XXX Also generate a link using which someone can delete this - // account if they own said address but weren't those who created - // this account. +Accounts.sendVerificationEmail = + async (userId, email, extraTokenData, extraParams) => { + // XXX Also generate a link using which someone can delete this + // account if they own said address but weren't those who created + // this account. - const {email: realEmail, user, token} = - Accounts.generateVerificationToken(userId, email, extraTokenData); - const url = Accounts.urls.verifyEmail(token, extraParams); - const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'verifyEmail'); - Email.send(options); - if (Meteor.isDevelopment) { - console.log(`\nVerification email URL: ${url}`); - } - return {email: realEmail, user, token, url, options}; -}; + const { email: realEmail, user, token } = + await Accounts.generateVerificationToken(userId, email, extraTokenData); + const url = await Accounts._resolvePromise(Accounts.urls.verifyEmail(token, extraParams)); + const options = await Accounts.generateOptionsForEmail(realEmail, user, url, 'verifyEmail'); + await Email.sendAsync(options); + if (Meteor.isDevelopment && !Meteor.isPackageTest) { + console.log(`\nVerification email URL: ${ url }`); + } + return { email: realEmail, user, token, url, options }; + }; // Take token from sendVerificationEmail, mark the email as verified, // and log them in. -Meteor.methods({verifyEmail: async function (...args) { - const token = args[0]; - return await Accounts._loginMethod( - this, - "verifyEmail", - args, - "password", - () => { - check(token, String); +Meteor.methods( + { + verifyEmail: async function (...args) { + const token = args[0]; + return await Accounts._loginMethod( + this, + "verifyEmail", + args, + "password", + async () => { + check(token, String); - const user = Meteor.users.findOne( - {'services.email.verificationTokens.token': token}, - {fields: { - services: 1, - emails: 1, - }} - ); - if (!user) - throw new Meteor.Error(403, "Verify email link expired"); + const user = await Meteor.users.findOneAsync( + { 'services.email.verificationTokens.token': token }, + { + fields: { + services: 1, + emails: 1, + } + } + ); + if (!user) + throw new Meteor.Error(403, "Verify email link expired"); - const tokenRecord = user.services.email.verificationTokens.find( - t => t.token == token - ); - if (!tokenRecord) - return { - userId: user._id, - error: new Meteor.Error(403, "Verify email link expired") - }; + const tokenRecord = + await user + .services.email.verificationTokens.find(t => t.token == token); - const emailsRecord = user.emails.find( - e => e.address == tokenRecord.address - ); - if (!emailsRecord) - return { - userId: user._id, - error: new Meteor.Error(403, "Verify email link is for unknown address") - }; + if (!tokenRecord) + return { + userId: user._id, + error: new Meteor.Error(403, "Verify email link expired") + }; - // By including the address in the query, we can use 'emails.$' in the - // modifier to get a reference to the specific object in the emails - // array. See - // http://www.mongodb.org/display/DOCS/Updating/#Updating-The%24positionaloperator) - // http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull - Meteor.users.update( - {_id: user._id, - 'emails.address': tokenRecord.address}, - {$set: {'emails.$.verified': true}, - $pull: {'services.email.verificationTokens': {address: tokenRecord.address}}}); + const emailsRecord = + user.emails.find(e => e.address == tokenRecord.address); - if (Accounts._check2faEnabled?.(user)) { + if (!emailsRecord) + return { + userId: user._id, + error: new Meteor.Error(403, "Verify email link is for unknown address") + }; + + // By including the address in the query, we can use 'emails.$' in the + // modifier to get a reference to the specific object in the emails + // array. See + // http://www.mongodb.org/display/DOCS/Updating/#Updating-The%24positionaloperator) + // http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull + await Meteor.users.updateAsync( + { + _id: user._id, + 'emails.address': tokenRecord.address + }, + { + $set: { 'emails.$.verified': true }, + $pull: { 'services.email.verificationTokens': { address: tokenRecord.address } } + }); + + if (Accounts._check2faEnabled?.(user)) { return { userId: user._id, error: Accounts._handleError( @@ -798,15 +985,60 @@ Meteor.methods({verifyEmail: async function (...args) { '2fa-enabled' ), }; - } - - return {userId: user._id}; + }return { userId: user._id }; + } + ); } - ); -}}); + }); + /** - * @summary Add an email address for a user. Use this instead of directly + * @summary Asynchronously replace an email address for a user. Use this instead of directly + * updating the database. The operation will fail if there is a different user + * with an email only differing in case. If the specified user has an existing + * email only differing in case however, we replace it. + * @locus Server + * @param {String} userId The ID of the user to update. + * @param {String} oldEmail The email address to replace. + * @param {String} newEmail The new email address to use. + * @param {Boolean} [verified] Optional - whether the new email address should + * be marked as verified. Defaults to false. + * @importFromPackage accounts-base + */ +Accounts.replaceEmailAsync = async (userId, oldEmail, newEmail, verified) => { + check(userId, NonEmptyString); + check(oldEmail, NonEmptyString); + check(newEmail, NonEmptyString); + check(verified, Match.Optional(Boolean)); + + if (verified === void 0) { + verified = false; + } + + const user = await getUserById(userId, { fields: { _id: 1 } }); + if (!user) + throw new Meteor.Error(403, "User not found"); + + // Ensure no user already has this new email + await Accounts._checkForCaseInsensitiveDuplicates( + "emails.address", + "Email", + newEmail, + user._id + ); + + const result = await Meteor.users.updateAsync( + { _id: user._id, 'emails.address': oldEmail }, + { $set: { 'emails.$.address': newEmail, 'emails.$.verified': verified } } + ); + + if (result.modifiedCount === 0) { + throw new Meteor.Error(404, "No user could be found with old email"); + } +}; + +/** + * @summary Asynchronously add an email address for a user. Use this instead of directly * updating the database. The operation will fail if there is a different user * with an email only differing in case. If the specified user has an existing * email only differing in case however, we replace it. @@ -817,7 +1049,7 @@ Meteor.methods({verifyEmail: async function (...args) { * be marked as verified. Defaults to false. * @importFromPackage accounts-base */ -Accounts.addEmail = (userId, newEmail, verified) => { +Accounts.addEmailAsync = async (userId, newEmail, verified) => { check(userId, NonEmptyString); check(newEmail, NonEmptyString); check(verified, Match.Optional(Boolean)); @@ -826,9 +1058,8 @@ Accounts.addEmail = (userId, newEmail, verified) => { verified = false; } - const user = getUserById(userId, {fields: {emails: 1}}); - if (!user) - throw new Meteor.Error(403, "User not found"); + const user = await getUserById(userId, { fields: { emails: 1 } }); + if (!user) throw new Meteor.Error(403, "User not found"); // Allow users to change their own email to a version with a different case @@ -838,27 +1069,36 @@ Accounts.addEmail = (userId, newEmail, verified) => { // then we are OK and (2) if this would create a conflict with other users // then there would already be a case-insensitive duplicate and we can't fix // that in this code anyway. - const caseInsensitiveRegExp = - new RegExp(`^${Meteor._escapeRegExp(newEmail)}$`, 'i'); - - const didUpdateOwnEmail = (user.emails || []).reduce( - (prev, email) => { - if (caseInsensitiveRegExp.test(email.address)) { - Meteor.users.update({ - _id: user._id, - 'emails.address': email.address - }, {$set: { - 'emails.$.address': newEmail, - 'emails.$.verified': verified - }}); - return true; - } else { - return prev; - } - }, - false + const caseInsensitiveRegExp = new RegExp( + `^${Meteor._escapeRegExp(newEmail)}$`, + "i" ); + // TODO: This is a linear search. If we have a lot of emails. + // we should consider using a different data structure. + const updatedEmail = async (emails = [], _id) => { + let updated = false; + for (const email of emails) { + if (caseInsensitiveRegExp.test(email.address)) { + await Meteor.users.updateAsync( + { + _id: _id, + "emails.address": email.address, + }, + { + $set: { + "emails.$.address": newEmail, + "emails.$.verified": verified, + }, + } + ); + updated = true; + } + } + return updated; + }; + const didUpdateOwnEmail = await updatedEmail(user.emails, user._id); + // In the other updates below, we have to do another call to // checkForCaseInsensitiveDuplicates to make sure that no conflicting values // were added to the database in the meantime. We don't have to do this for @@ -871,52 +1111,66 @@ Accounts.addEmail = (userId, newEmail, verified) => { } // Perform a case insensitive check for duplicates before update - Accounts._checkForCaseInsensitiveDuplicates('emails.address', - 'Email', newEmail, user._id); + await Accounts._checkForCaseInsensitiveDuplicates( + "emails.address", + "Email", + newEmail, + user._id + ); - Meteor.users.update({ - _id: user._id - }, { - $addToSet: { - emails: { - address: newEmail, - verified: verified - } + await Meteor.users.updateAsync( + { + _id: user._id, + }, + { + $addToSet: { + emails: { + address: newEmail, + verified: verified, + }, + }, } - }); + ); // Perform another check after update, in case a matching user has been // inserted in the meantime try { - Accounts._checkForCaseInsensitiveDuplicates('emails.address', - 'Email', newEmail, user._id); + await Accounts._checkForCaseInsensitiveDuplicates( + "emails.address", + "Email", + newEmail, + user._id + ); } catch (ex) { // Undo update if the check fails - Meteor.users.update({_id: user._id}, - {$pull: {emails: {address: newEmail}}}); + await Meteor.users.updateAsync( + { _id: user._id }, + { $pull: { emails: { address: newEmail } } } + ); throw ex; } -} +}; /** - * @summary Remove an email address for a user. Use this instead of updating + * @summary Remove an email address asynchronously for a user. Use this instead of updating * the database directly. * @locus Server * @param {String} userId The ID of the user to update. * @param {String} email The email address to remove. * @importFromPackage accounts-base */ -Accounts.removeEmail = (userId, email) => { - check(userId, NonEmptyString); - check(email, NonEmptyString); +Accounts.removeEmail = + async (userId, email) => { + check(userId, NonEmptyString); + check(email, NonEmptyString); - const user = getUserById(userId, {fields: {_id: 1}}); - if (!user) - throw new Meteor.Error(403, "User not found"); + const user = await getUserById(userId, { fields: { _id: 1 } }); + if (!user) + throw new Meteor.Error(403, "User not found"); - Meteor.users.update({_id: user._id}, - {$pull: {emails: {address: email}}}); -} + await Meteor.users.updateAsync({ _id: user._id }, + { $pull: { emails: { address: email } } }); + } /// /// CREATING USERS @@ -927,54 +1181,64 @@ Accounts.removeEmail = (userId, email) => { // does the actual user insertion. // // returns the user id -const createUser = async options => { - // Unknown keys allowed, because a onCreateUserHook can take arbitrary - // options. - check(options, Match.ObjectIncluding({ - username: Match.Optional(String), - email: Match.Optional(String), - password: Match.Optional(passwordValidator) - })); +const createUser = + async options => { + // Unknown keys allowed, because a onCreateUserHook can take arbitrary + // options. + check(options, Match.ObjectIncluding({ + username: Match.Optional(String), + email: Match.Optional(String), + password: Match.Optional(passwordValidator) + })); - const { username, email, password } = options; - if (!username && !email) - throw new Meteor.Error(400, "Need to set a username or email"); + const { username, email, password } = options; + if (!username && !email) + throw new Meteor.Error(400, "Need to set a username or email"); - const user = {services: {}}; - if (password) { - const hashed = await hashPassword(password); - user.services.password = { bcrypt: hashed }; - } + const user = { services: {} }; + if (password) { + const hashed = await hashPassword(password); + const argon2Enabled = Accounts._argon2Enabled(); + if (argon2Enabled === false) { + user.services.password = { bcrypt: hashed }; + } + else { + user.services.password = { argon2: hashed }; + } + } - return Accounts._createUserCheckingDuplicates({ user, email, username, options }); -}; + return await Accounts._createUserCheckingDuplicates({ user, email, username, options }); + }; // method for create user. Requests come from the client. -Meteor.methods({createUser: async function (...args) { - const options = args[0]; - return await Accounts._loginMethod( - this, - "createUser", - args, - "password", - async () => { - // createUser() above does more checking. - check(options, Object); - if (Accounts._options.forbidClientAccountCreation) - return { - error: new Meteor.Error(403, "Signups forbidden") - }; +Meteor.methods( + { + createUser: async function (...args) { + const options = args[0]; + return await Accounts._loginMethod( + this, + "createUser", + args, + "password", + async () => { + // createUser() above does more checking. + check(options, Object); + if (Accounts._options.forbidClientAccountCreation) + return { + error: new Meteor.Error(403, "Signups forbidden") + }; - const userId = await Accounts.createUserVerifyingEmail(options); + const userId = await Accounts.createUserVerifyingEmail(options); - // client gets logged in as the new user afterwards. - return {userId: userId}; + // client gets logged in as the new user afterwards. + return { userId: userId }; + } + ); } - ); -}}); + }); /** - * @summary Creates an user and sends an email if `options.email` is informed. + * @summary Creates an user asynchronously and sends an email if `options.email` is informed. * Then if the `sendVerificationEmail` option from the `Accounts` package is * enabled, you'll send a verification email if `options.password` is informed, * otherwise you'll send an enrollment email. @@ -987,28 +1251,29 @@ Meteor.methods({createUser: async function (...args) { * @param {Object} options.profile The user's profile, typically including the `name` field. * @importFromPackage accounts-base * */ -Accounts.createUserVerifyingEmail = async (options) => { - options = { ...options }; - // Create user. result contains id and token. - const userId = await createUser(options); - // safety belt. createUser is supposed to throw on error. send 500 error - // instead of sending a verification email with empty userid. - if (! userId) - throw new Error("createUser failed to insert new user"); +Accounts.createUserVerifyingEmail = + async (options) => { + options = { ...options }; + // Create user. result contains id and token. + const userId = await createUser(options); + // safety belt. createUser is supposed to throw on error. send 500 error + // instead of sending a verification email with empty userid. + if (!userId) + throw new Error("createUser failed to insert new user"); - // If `Accounts._options.sendVerificationEmail` is set, register - // a token to verify the user's primary email, and send it to - // that address. - if (options.email && Accounts._options.sendVerificationEmail) { - if (options.password) { - Accounts.sendVerificationEmail(userId, options.email); - } else { - Accounts.sendEnrollmentEmail(userId, options.email); + // If `Accounts._options.sendVerificationEmail` is set, register + // a token to verify the user's primary email, and send it to + // that address. + if (options.email && Accounts._options.sendVerificationEmail) { + if (options.password) { + await Accounts.sendVerificationEmail(userId, options.email); + } else { + await Accounts.sendEnrollmentEmail(userId, options.email); + } } - } - return userId; -}; + return userId; + }; // Create user directly on the server. // @@ -1023,16 +1288,7 @@ Accounts.createUserVerifyingEmail = async (options) => { // method calling Accounts.createUser could set? // -Accounts.createUserAsync = async (options, callback) => { - options = { ...options }; - - // XXX allow an optional callback? - if (callback) { - throw new Error("Accounts.createUser with callback not supported on the server yet."); - } - - return createUser(options); -}; +Accounts.createUserAsync = createUser // Create user directly on the server. // @@ -1047,16 +1303,14 @@ Accounts.createUserAsync = async (options, callback) => { // method calling Accounts.createUser could set? // -Accounts.createUser = (options, callback) => { - return Promise.await(Accounts.createUserAsync(options, callback)); -}; +Accounts.createUser = Accounts.createUserAsync; /// /// PASSWORD-SPECIFIC INDEXES ON USERS /// -Meteor.users.createIndex('services.email.verificationTokens.token', - { unique: true, sparse: true }); -Meteor.users.createIndex('services.password.reset.token', - { unique: true, sparse: true }); -Meteor.users.createIndex('services.password.enroll.token', - { unique: true, sparse: true }); +await Meteor.users.createIndexAsync('services.email.verificationTokens.token', + { unique: true, sparse: true }); +await Meteor.users.createIndexAsync('services.password.reset.token', + { unique: true, sparse: true }); +await Meteor.users.createIndexAsync('services.password.enroll.token', + { unique: true, sparse: true }); diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index 0266c977f2..49f94544a0 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -1,28 +1,44 @@ Accounts._connectionCloseDelayMsForTests = 1000; - -function hashPassword(password) { +const makeTestConnAsync = + (test) => + new Promise((resolve, reject) => { + makeTestConnection( + test, + (clientConn, serverConn) => resolve({ clientConn, serverConn }), + reject + ); + }) +const simplePollAsync = (fn) => + new Promise((resolve, reject) => simplePoll(fn,resolve,reject)) +function hashPasswordWithSha(password) { return { digest: SHA256(password), - algorithm: "sha-256" + algorithm: "sha-256" }; } if (Meteor.isServer) { Accounts.removeDefaultRateLimit(); - Meteor.methods({ - getResetToken: function () { - const token = Meteor.users.findOne(this.userId).services.password.reset; - return token; - }, - addSkipCaseInsensitiveChecksForTest: value => { - Accounts._skipCaseInsensitiveChecksForTest[value] = true; - }, - removeSkipCaseInsensitiveChecksForTest: value => { - delete Accounts._skipCaseInsensitiveChecksForTest[value]; - }, - countUsersOnServer: query => Meteor.users.find(query).count(), - }); + Meteor.methods( + { + getResetToken: + async function () { + const user = await Meteor.users.findOneAsync(this.userId); + return user.services.password.reset; + }, + + addSkipCaseInsensitiveChecksForTest: + value => Accounts._skipCaseInsensitiveChecksForTest[value] = true, + + removeSkipCaseInsensitiveChecksForTest: + value => delete Accounts._skipCaseInsensitiveChecksForTest[value], + + async countUsersOnServer(query) { + return await Meteor.users.find(query).countAsync(); + } + } + ); } if (Meteor.isClient) (() => { @@ -38,23 +54,37 @@ if (Meteor.isClient) (() => { const removeSkipCaseInsensitiveChecksForTest = (value, test, expect) => Meteor.call('removeSkipCaseInsensitiveChecksForTest', value); - const createUserStep = function (test, expect) { + // Make logout steps awaitable so subsequent test steps don't race. + const logoutStep = async (test, expect) => + new Promise(resolve => { + Meteor.logout(err => { + if (err) { + // keep original behavior: fail the test if logout errored + test.fail(err.message); + // still resolve so test runner can continue + return resolve(); + } + test.equal(Meteor.user(), null); + resolve(); + }); + }); + + // Create user only after a confirmed logout to avoid races between + // tests that do login/logout operations. + const createUserStep = async function (test, expect) { + // Wait for the logout to complete synchronously. + await logoutStep(test, expect); + // Hack because Tinytest does not clean the database between tests/runs this.randomSuffix = Random.id(10); - this.username = `AdaLovelace${this.randomSuffix}`; - this.email = `Ada-intercept@lovelace.com${this.randomSuffix}`; + this.username = `AdaLovelace${ this.randomSuffix }`; + this.email = `Ada-intercept@lovelace.com${ this.randomSuffix }`; this.password = 'password'; - Accounts.createUser( - {username: this.username, email: this.email, password: this.password}, - loggedInAs(this.username, test, expect)); - }; - const logoutStep = (test, expect) => - Meteor.logout(expect(error => { - if (error) { - test.fail(error.message); - } - test.equal(Meteor.user(), null); - })); + + Accounts.createUser( + { username: this.username, email: this.email, password: this.password }, + loggedInAs(this.username, test, expect)); + }; const loggedInAs = (someUsername, test, expect) => { return expect(error => { if (error) { @@ -63,18 +93,7 @@ if (Meteor.isClient) (() => { test.equal(Meteor.userId() && Meteor.user().username, someUsername); }); }; - const loggedInUserHasEmail = (someEmail, test, expect) => { - return expect(error => { - if (error) { - test.fail(error.message); - } - const user = Meteor.user(); - test.isTrue(user && user.emails.reduce( - (prev, email) => prev || email.address === someEmail, - false - )); - }); - }; + const expectError = (expectedError, test, expect) => expect(actualError => { test.equal(actualError && actualError.error, expectedError.error); test.equal(actualError && actualError.reason, expectedError.reason); @@ -110,11 +129,11 @@ if (Meteor.isClient) (() => { function (test, expect) { // setup this.username = Random.id(); - this.email = `${Random.id()}-intercept@example.com`; + this.email = `${ Random.id() }-intercept@example.com`; this.password = 'password'; Accounts.createUser( - {username: this.username, email: this.email, password: this.password}, + { username: this.username, email: this.email, password: this.password }, loggedInAs(this.username, test, expect)); }, function (test, expect) { @@ -123,7 +142,7 @@ if (Meteor.isClient) (() => { logoutStep, function (test, expect) { Meteor.loginWithPassword(this.username, this.password, - loggedInAs(this.username, test, expect)); + loggedInAs(this.username, test, expect)); }, logoutStep, // This next step tests reactive contexts which are reactive on @@ -151,18 +170,18 @@ if (Meteor.isClient) (() => { }, logoutStep, function (test, expect) { - Meteor.loginWithPassword({username: this.username}, this.password, - loggedInAs(this.username, test, expect)); + Meteor.loginWithPassword({ username: this.username }, this.password, + loggedInAs(this.username, test, expect)); }, logoutStep, function (test, expect) { Meteor.loginWithPassword(this.email, this.password, - loggedInAs(this.username, test, expect)); + loggedInAs(this.username, test, expect)); }, logoutStep, function (test, expect) { - Meteor.loginWithPassword({email: this.email}, this.password, - loggedInAs(this.username, test, expect)); + Meteor.loginWithPassword({ email: this.email }, this.password, + loggedInAs(this.username, test, expect)); }, logoutStep ]); @@ -173,65 +192,65 @@ if (Meteor.isClient) (() => { // We should be able to log in with the username in lower case function (test, expect) { Meteor.loginWithPassword( - { username: `adalovelace${this.randomSuffix}` }, + { username: `adalovelace${ this.randomSuffix }` }, this.password, loggedInAs(this.username, test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive username " + - "with non-ASCII characters", [ + "with non-ASCII characters", [ function (test, expect) { // Hack because Tinytest does not clean the database between tests/runs this.randomSuffix = Random.id(10); - this.username = `ÁdaLØvela😈e${this.randomSuffix}`; + this.username = `ÁdaLØvela😈e${ this.randomSuffix }`; this.password = 'password'; Accounts.createUser( - {username: this.username, email: this.email, password: this.password}, + { username: this.username, email: this.email, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, // We should be able to log in with the username in lower case function (test, expect) { Meteor.loginWithPassword( - { username: `Γ‘dalΓΈvela😈e${this.randomSuffix}` }, + { username: `Γ‘dalΓΈvela😈e${ this.randomSuffix }` }, this.password, loggedInAs(this.username, test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive username " + - "should escape regex special characters", [ + "should escape regex special characters", [ createUserStep, logoutStep, // We shouldn't be able to log in with a regex expression for the username function (test, expect) { Meteor.loginWithPassword( - { username: `.+${this.randomSuffix}` }, + { username: `.+${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive username " + - "should require a match of the full string", [ + "should require a match of the full string", [ createUserStep, logoutStep, // We shouldn't be able to log in with a partial match for the username function (test, expect) { Meteor.loginWithPassword( - { username: `lovelace${this.randomSuffix}` }, + { username: `lovelace${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive username when " + - "there are multiple matches", [ + "there are multiple matches", [ createUserStep, logoutStep, function (test, expect) { - this.otherUsername = `Adalovelace${this.randomSuffix}`; + this.otherUsername = `Adalovelace${ this.randomSuffix }`; addSkipCaseInsensitiveChecksForTest(this.otherUsername, test, expect); }, // Create another user with a username that only differs in case @@ -246,7 +265,7 @@ if (Meteor.isClient) (() => { // We shouldn't be able to log in with the username in lower case function (test, expect) { Meteor.loginWithPassword( - { username: `adalovelace${this.randomSuffix}` }, + { username: `adalovelace${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); }, @@ -260,13 +279,13 @@ if (Meteor.isClient) (() => { ]); testAsyncMulti("passwords - creating users with the same case insensitive " + - "username", [ + "username", [ createUserStep, logoutStep, // Attempting to create another user with a username that only differs in // case should fail function (test, expect) { - this.newUsername = `adalovelace${this.randomSuffix}`; + this.newUsername = `adalovelace${ this.randomSuffix }`; Accounts.createUser( { username: this.newUsername, password: this.password }, expectError( @@ -275,12 +294,11 @@ if (Meteor.isClient) (() => { expect)); }, // Make sure the new user has not been inserted - function (test, expect) { - Meteor.call('countUsersOnServer', - { username: this.newUsername }, - expect(function (error, result) { - test.equal(result, 0); - })); + async function (test) { + const result = await Meteor.callAsync('countUsersOnServer', { + username: this.newUsername, + }); + test.equal(result, 0); } ]); @@ -290,53 +308,55 @@ if (Meteor.isClient) (() => { // We should be able to log in with the email in lower case function (test, expect) { Meteor.loginWithPassword( - { email: `ada-intercept@lovelace.com${this.randomSuffix}` }, + { email: `ada-intercept@lovelace.com${ this.randomSuffix }` }, this.password, loggedInAs(this.username, test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive email should " + - "escape regex special characters", [ + "escape regex special characters", [ createUserStep, logoutStep, // We shouldn't be able to log in with a regex expression for the email function (test, expect) { Meteor.loginWithPassword( - { email: `.+${this.randomSuffix}` }, + { email: `.+${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive email should " + - "require a match of the full string", [ + "require a match of the full string", [ createUserStep, logoutStep, // We shouldn't be able to log in with a partial match for the email function (test, expect) { Meteor.loginWithPassword( - { email: `com${this.randomSuffix}` }, + { email: `com${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); } ]); testAsyncMulti("passwords - logging in with case insensitive email when " + - "there are multiple matches", [ + "there are multiple matches", [ createUserStep, logoutStep, function (test, expect) { - this.otherUsername = `AdaLovelace${Random.id(10)}`; - this.otherEmail = `ADA-intercept@lovelace.com${this.randomSuffix}`; + this.otherUsername = `AdaLovelace${ Random.id(10) }`; + this.otherEmail = `ADA-intercept@lovelace.com${ this.randomSuffix }`; addSkipCaseInsensitiveChecksForTest(this.otherEmail, test, expect); }, // Create another user with an email that only differs in case function (test, expect) { Accounts.createUser( - { username: this.otherUsername, + { + username: this.otherUsername, email: this.otherEmail, - password: this.password }, + password: this.password + }, loggedInAs(this.otherUsername, test, expect)); }, function (test, expect) { @@ -346,7 +366,7 @@ if (Meteor.isClient) (() => { // We shouldn't be able to log in with the email in lower case function (test, expect) { Meteor.loginWithPassword( - { email: `ada-intercept@lovelace.com${this.randomSuffix}` }, + { email: `ada-intercept@lovelace.com${ this.randomSuffix }` }, this.password, expectUserNotFound(test, expect)); }, @@ -360,20 +380,20 @@ if (Meteor.isClient) (() => { ]); testAsyncMulti("passwords - creating users with the same case insensitive " + - "email", [ + "email", [ createUserStep, logoutStep, // Create user error without callback should throw error function (test, expect) { - this.newUsername = `adalovelace${this.randomSuffix}`; - test.throws(function(){ + this.newUsername = `adalovelace${ this.randomSuffix }`; + test.throws(function () { Accounts.createUser({ username: this.newUsername, password: '' }); }, /Password may not be empty/); }, // Attempting to create another user with an email that only differs in // case should fail function (test, expect) { - this.newEmail = `ada-intercept@lovelace.com${this.randomSuffix}`; + this.newEmail = `ada-intercept@lovelace.com${ this.randomSuffix }`; Accounts.createUser( { email: this.newEmail, password: this.password }, expectError( @@ -382,13 +402,11 @@ if (Meteor.isClient) (() => { expect)); }, // Make sure the new user has not been inserted - function (test, expect) { - Meteor.call('countUsersOnServer', - { 'emails.address': this.newEmail }, - expect (function (error, result) { - test.equal(result, 0); - }) - ); + async function (test) { + const result = await Meteor.callAsync('countUsersOnServer', { + 'emails.address': this.newEmail, + }); + test.equal(result, 0); } ]); @@ -396,7 +414,7 @@ if (Meteor.isClient) (() => { function (test, expect) { // setup this.username = Random.id(); - this.email = `${Random.id()}-intercept@example.com`; + this.email = `${ Random.id() }-intercept@example.com`; this.password = 'password'; this.password2 = 'password2'; @@ -409,15 +427,13 @@ if (Meteor.isClient) (() => { function (test, expect) { Meteor.call("forgotPassword", { email: this.email }, expect(error => { - test.isFalse(error); - })); + test.isFalse(error); + })); }, - function (test, expect) { - Meteor.call("getResetToken", expect((err, token) => { - test.isFalse(err); - test.isTrue(token); - this.token = token; - })); + async function (test) { + const token = await Meteor.callAsync("getResetToken"); + test.isTrue(token); + this.token = token; }, // change password with bad old password. we stay logged in. function (test, expect) { @@ -436,13 +452,11 @@ if (Meteor.isClient) (() => { // change password with good old password. function (test, expect) { Accounts.changePassword(this.password, this.password2, - loggedInAs(this.username, test, expect)); + loggedInAs(this.username, test, expect)); }, - function (test, expect) { - Meteor.call("getResetToken", expect((err, token) => { - test.isFalse(err); - test.isFalse(token); - })); + async function (test) { + const token = await Meteor.callAsync("getResetToken"); + test.isFalse(token); }, logoutStep, // old password, failed login @@ -455,7 +469,7 @@ if (Meteor.isClient) (() => { // new password, success function (test, expect) { Meteor.loginWithPassword(this.email, this.password2, - loggedInAs(this.username, test, expect)); + loggedInAs(this.username, test, expect)); }, logoutStep ]); @@ -463,7 +477,7 @@ if (Meteor.isClient) (() => { testAsyncMulti("passwords - changing password logs out other clients", [ function (test, expect) { this.username = Random.id(); - this.email = `${Random.id()}-intercept@example.com`; + this.email = `${ Random.id() }-intercept@example.com`; this.password = 'password'; this.password2 = 'password2'; Accounts.createUser( @@ -475,21 +489,21 @@ if (Meteor.isClient) (() => { function (test, expect) { this.secondConn = DDP.connect(Meteor.absoluteUrl()); this.secondConn.call('login', - { user: { username: this.username }, password: hashPassword(this.password) }, - expect((err, result) => { - test.isFalse(err); - this.secondConn.setUserId(result.id); - test.isTrue(this.secondConn.userId()); + { user: { username: this.username }, password: hashPasswordWithSha(this.password) }, + expect((err, result) => { + test.isFalse(err); + this.secondConn.setUserId(result.id); + test.isTrue(this.secondConn.userId()); - this.secondConn.onReconnect = () => - this.secondConn.apply( - 'login', - [{ resume: result.token }], - { wait: true }, - (err, result) => - this.secondConn.setUserId(result && result.id || null) - ); - })); + this.secondConn.onReconnect = () => + this.secondConn.apply( + 'login', + [{ resume: result.token }], + { wait: true }, + (err, result) => + this.secondConn.setUserId(result && result.id || null) + ); + })); }, function (test, expect) { Accounts.changePassword( @@ -550,7 +564,8 @@ if (Meteor.isClient) (() => { 'Method call should have 2 arguments since no callback is passed in' ); - Accounts.forgotPassword({ email: 'test@meteor.com' }, () => {}); + Accounts.forgotPassword({ email: 'test@meteor.com' }, () => { + }); test.equal( methodCallArgumentCount, 3, @@ -623,27 +638,31 @@ if (Meteor.isClient) (() => { function (test, expect) { // setup this.username = Random.id(); - this.email = `${Random.id()}-intercept@example.com`; + this.email = `${ Random.id() }-intercept@example.com`; this.password = 'password'; }, // test Accounts.validateNewUser - function(test, expect) { + function (test, expect) { Accounts.createUser( - {username: this.username, password: this.password, - // should fail the new user validators - profile: {invalid: true}}, + { + username: this.username, password: this.password, + // should fail the new user validators + profile: { invalid: true } + }, expect(error => { test.equal(error.error, 403); test.equal(error.reason, "User validation failed"); })); }, logoutStep, - function(test, expect) { + function (test, expect) { Accounts.createUser( - {username: this.username, password: this.password, - // should fail the new user validator with a special - // exception - profile: {invalidAndThrowException: true}}, + { + username: this.username, password: this.password, + // should fail the new user validator with a special + // exception + profile: { invalidAndThrowException: true } + }, expect(error => test.equal( error.reason, @@ -653,13 +672,15 @@ if (Meteor.isClient) (() => { ); }, // test Accounts.onCreateUser - function(test, expect) { + function (test, expect) { Accounts.createUser( - {username: this.username, password: this.password, - testOnCreateUserHook: true}, + { + username: this.username, password: this.password, + testOnCreateUserHook: true + }, loggedInAs(this.username, test, expect)); }, - function(test, expect) { + function (test, expect) { test.equal(Meteor.user().profile.touchedByOnCreateUser, true); }, logoutStep @@ -673,15 +694,17 @@ if (Meteor.isClient) (() => { this.password = 'password'; Accounts.createUser( - {username: this.username, password: this.password, - testOnCreateUserHook: true}, + { + username: this.username, password: this.password, + testOnCreateUserHook: true + }, loggedInAs(this.username, test, expect)); }, // test Meteor.user(). This test properly belongs in // accounts-base/accounts_tests.js, but this is where the tests that // actually log in are. - function(test, expect) { - const clientUser = Meteor.user(); + async function (test, expect) { + const clientUser = await Meteor.userAsync(); Accounts.connection.call('testMeteorUser', expect((err, result) => { test.equal(result._id, clientUser._id); test.equal(result.username, clientUser.username); @@ -690,16 +713,14 @@ if (Meteor.isClient) (() => { test.equal(err, undefined); })); }, - function(test, expect) { + async function (test, expect) { // Test that even with no published fields, we still have a document. - Accounts.connection.call('clearUsernameAndProfile', expect(() => { - test.isTrue(Meteor.userId()); - const user = Meteor.user(); - test.equal(user, {_id: Meteor.userId()}); - })); + await Accounts.connection.callAsync('clearUsernameAndProfile'); + test.isTrue(Meteor.userId()); + test.equal(await Meteor.userAsync(), { _id: Meteor.userId() }); }, logoutStep, - function(test, expect) { + function (test, expect) { const clientUser = Meteor.user(); test.equal(clientUser, null); test.equal(Meteor.userId(), null); @@ -715,8 +736,10 @@ if (Meteor.isClient) (() => { function (test, expect) { this.otherUsername = Random.id(); Accounts.createUser( - {username: this.otherUsername, password: 'dontcare', - testOnCreateUserHook: true}, + { + username: this.otherUsername, password: 'dontcare', + testOnCreateUserHook: true + }, loggedInAs(this.otherUsername, test, expect)); }, function (test, expect) { @@ -728,51 +751,62 @@ if (Meteor.isClient) (() => { this.password = 'password'; Accounts.createUser( - {username: this.username, password: this.password, - testOnCreateUserHook: true}, + { + username: this.username, password: this.password, + testOnCreateUserHook: true + }, loggedInAs(this.username, test, expect)); }, // test the default Meteor.users allow rule. This test properly belongs in // accounts-base/accounts_tests.js, but this is where the tests that // actually log in are. - function(test, expect) { + async function (test, expect) { this.userId = Meteor.userId(); test.notEqual(this.userId, null); test.notEqual(this.userId, this.otherUserId); // Can't update fields other than profile. - Meteor.users.update( - this.userId, {$set: {disallowed: true, 'profile.updated': 42}}, - expect(err => { + await Meteor.users + .updateAsync(this.userId, { + $set: { disallowed: true, "profile.updated": 42 }, + }) + .catch((err) => { test.isTrue(err); test.equal(err.error, 403); - test.isFalse(Object.prototype.hasOwnProperty.call(Meteor.user(), 'disallowed')); - test.isFalse(Object.prototype.hasOwnProperty.call(Meteor.user().profile, 'updated')); - })); + test.isFalse( + Object.prototype.hasOwnProperty.call(Meteor.user(), "disallowed") + ); + test.isFalse( + Object.prototype.hasOwnProperty.call( + Meteor.user().profile, + "updated" + ) + ); + }); }, - function(test, expect) { + async function (test, expect) { // Can't update another user. - Meteor.users.update( - this.otherUserId, {$set: {'profile.updated': 42}}, - expect(err => { - test.isTrue(err); - test.equal(err.error, 403); - })); + await Meteor.users + .updateAsync(this.otherUserId, { $set: { "profile.updated": 42 } }) + .catch( + expect((err) => { + test.isTrue(err); + test.equal(err.error, 403); + }) + ); }, - function(test, expect) { + async function (test, expect) { // Can't update using a non-ID selector. (This one is thrown client-side.) - test.throws(() => Meteor.users.update( - {username: this.username}, {$set: {'profile.updated': 42}} + await test.throwsAsync(async () => await Meteor.users.updateAsync( + { username: this.username }, { $set: { 'profile.updated': 42 } } )); test.isFalse(Object.prototype.hasOwnProperty.call(Meteor.user().profile, 'updated')); }, - function(test, expect) { + async function (test) { // Can update own profile using ID. - Meteor.users.update( - this.userId, {$set: {'profile.updated': 42}}, - expect(err => { - test.isFalse(err); - test.equal(42, Meteor.user().profile.updated); - })); + await Meteor.users.updateAsync( + this.userId, { $set: { 'profile.updated': 42 } }, + ); + test.equal(42, Meteor.user().profile.updated); }, logoutStep ]); @@ -785,7 +819,7 @@ if (Meteor.isClient) (() => { this.password = 'password'; Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, @@ -856,7 +890,7 @@ if (Meteor.isClient) (() => { Meteor.logoutOtherClients(err => { test.isFalse(err); secondConn.call('login', { resume: token }, - expectSecondConnLoggedOut); + expectSecondConnLoggedOut); Accounts.connection.call('login', { resume: Accounts._storedLoginToken() }, expectAccountsConnLoggedIn); @@ -871,7 +905,7 @@ if (Meteor.isClient) (() => { token = Accounts._storedLoginToken(); test.isTrue(token); secondConn.call('login', { resume: token }, - expectSecondConnLoggedIn); + expectSecondConnLoggedIn); }) ); }, @@ -884,7 +918,7 @@ if (Meteor.isClient) (() => { this.password = "password"; Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, @@ -933,7 +967,7 @@ if (Meteor.isClient) (() => { this.password = "password"; Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, function (test, expect) { @@ -961,7 +995,7 @@ if (Meteor.isClient) (() => { }); Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, function (test, expect) { @@ -980,7 +1014,7 @@ if (Meteor.isClient) (() => { this.password = "password"; Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, @@ -1003,13 +1037,14 @@ if (Meteor.isClient) (() => { this.onLogout = Accounts.onLogout(() => this.logoutSuccess = true); Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, function (test, expect) { test.isTrue(this.logoutSuccess); - expect(function() {})(); + expect(function () { + })(); } ]); @@ -1019,7 +1054,7 @@ if (Meteor.isClient) (() => { this.password = "password"; Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, @@ -1078,7 +1113,7 @@ if (Meteor.isClient) (() => { this.onLoginFailure = Accounts.onLoginFailure(() => this.attempt = true); Accounts.createUser( - {username: this.username, password: this.password}, + { username: this.username, password: this.password }, loggedInAs(this.username, test, expect)); }, logoutStep, @@ -1098,718 +1133,925 @@ if (Meteor.isClient) (() => { expect(() => ({}))(); } ]); -}) (); +})(); if (Meteor.isServer) (() => { Tinytest.add('passwords - setup more than one onCreateUserHook', test => { - test.throws(() => Accounts.onCreateUser(() => ({}))); + test.throws(() => Accounts.onCreateUser(() => ({}))); }); - Tinytest.add('passwords - createUser hooks', test => { - const username = Random.id(); - // should fail the new user validators - test.throws(() => Accounts.createUser( - {username: username, profile: {invalid: true}} - )); + Tinytest.addAsync('passwords - createUser hooks', async test => { + const username = Random.id(); + // should fail the new user validators + await test.throwsAsync( + async () => + await Accounts.createUser({ username: username, profile: { invalid: true } })); - const userId = Accounts.createUser({username: username, - testOnCreateUserHook: true}); + const userId = await Accounts + .createUser({ username: username, testOnCreateUserHook: true }); - test.isTrue(userId); - const user = Meteor.users.findOne(userId); - test.equal(user.profile.touchedByOnCreateUser, true); - }); + test.isTrue(userId); + const user = await Meteor.users.findOneAsync(userId); + test.equal(user.profile.touchedByOnCreateUser, true); + }); - Tinytest.add( + Tinytest.addAsync( 'passwords - setPassword', - test => { + async test => { const username = Random.id(); - const email = `${username}-intercept@example.com`; + const email = `${ username }-intercept@example.com`; - const userId = Accounts.createUser({username: username, email: email}); + const userId = await Accounts.createUser({ username: username, email: email }); - let user = Meteor.users.findOne(userId); + let user = await Meteor.users.findOneAsync(userId); // no services yet. test.equal(user.services.password, undefined); // set a new password. - Accounts.setPassword(userId, 'new password'); - user = Meteor.users.findOne(userId); + await Accounts.setPasswordAsync(userId, 'new password'); + user = await Meteor.users.findOneAsync(userId); const oldSaltedHash = user.services.password.bcrypt; test.isTrue(oldSaltedHash); - // Send a reset password email (setting a reset token) and insert a login // token. - Accounts.sendResetPasswordEmail(userId, email); - Accounts._insertLoginToken(userId, Accounts._generateStampedLoginToken()); - test.isTrue(Meteor.users.findOne(userId).services.password.reset); - test.isTrue(Meteor.users.findOne(userId).services.resume.loginTokens); + await Accounts.sendResetPasswordEmail(userId, email); + await Accounts._insertLoginToken(userId, Accounts._generateStampedLoginToken()); + const user2 = await Meteor.users.findOneAsync(userId) + test.isTrue(user2.services.password.reset); + test.isTrue(user2.services.resume.loginTokens); // reset with the same password, see we get a different salted hash - Accounts.setPassword(userId, 'new password', {logout: false}); - user = Meteor.users.findOne(userId); + await Accounts.setPasswordAsync(userId, 'new password', { logout: false }); + user = await Meteor.users.findOneAsync(userId); const newSaltedHash = user.services.password.bcrypt; test.isTrue(newSaltedHash); test.notEqual(oldSaltedHash, newSaltedHash); // No more reset token. - test.isFalse(Meteor.users.findOne(userId).services.password.reset); + const user3 = await Meteor.users.findOneAsync(userId) + test.isFalse(user3.services.password.reset); // But loginTokens are still here since we did logout: false. - test.isTrue(Meteor.users.findOne(userId).services.resume.loginTokens); + test.isTrue(user3.services.resume.loginTokens); // reset again, see that the login tokens are gone. - Accounts.setPassword(userId, 'new password'); - user = Meteor.users.findOne(userId); + await Accounts.setPasswordAsync(userId, 'new password'); + user = await Meteor.users.findOneAsync(userId); const newerSaltedHash = user.services.password.bcrypt; test.isTrue(newerSaltedHash); test.notEqual(oldSaltedHash, newerSaltedHash); test.notEqual(newSaltedHash, newerSaltedHash); // No more tokens. - test.isFalse(Meteor.users.findOne(userId).services.password.reset); - test.isFalse(Meteor.users.findOne(userId).services.resume.loginTokens); + const user4 = await Meteor.users.findOneAsync(userId) + test.isFalse(user4.services.password.reset); + test.isFalse(user4.services.resume.loginTokens); // cleanup - Meteor.users.remove(userId); + await Meteor.users.removeAsync(userId); }); // This test properly belongs in accounts-base/accounts_tests.js, but // this is where the tests that actually log in are. - Tinytest.add('accounts - user() out of context', test => { - // basic server context, no method. - test.throws(() => Meteor.user()); + Tinytest.addAsync('accounts - userAsync() out of context', async test => { + await test.throwsAsync( + async () => + await Meteor.userAsync() + ); + await Meteor.users.removeAsync({}); }); // XXX would be nice to test // Accounts.config({forbidClientAccountCreation: true}) + //TODO[FIBERS] Continue later Tinytest.addAsync( 'passwords - login token observes get cleaned up', - (test, onComplete) => { + async (test) => { const username = Random.id(); - Accounts.createUser({ + const id = await Accounts.createUser({ username: username, - password: hashPassword('password') + password: hashPasswordWithSha('password') }); - makeTestConnection( - test, - (clientConn, serverConn) => { - serverConn.onClose(() => { - test.isFalse(Accounts._getUserObserve(serverConn.id)); - onComplete(); - }); - const result = clientConn.call('login', { - user: {username: username}, - password: hashPassword('password') - }); - test.isTrue(result); - const token = Accounts._getAccountData(serverConn.id, 'loginToken'); - test.isTrue(token); + const { + clientConn, serverConn + } = await makeTestConnAsync(test) + + + serverConn.onClose(() => { + if (Accounts._getUserObserve(serverConn.id) !== undefined) + test.fail('observe should be gone'); + }) + + const result = await clientConn.callAsync('login', { + user: { username: username }, + password: hashPasswordWithSha('password') + }); + + test.isTrue(result); + const token = Accounts._getAccountData(serverConn.id, 'loginToken'); + test.isTrue(token) + test.isTrue(Accounts._getUserObserve(serverConn.id)); + + + try { + const r = + await simplePollAsync(() => !!Accounts._getUserObserve(serverConn.id)) + test.isTrue(Accounts._getUserObserve(serverConn.id)); + clientConn.disconnect() + serverConn.close() + } catch (e) { + test.fail( + `timed out waiting for user observe for connection ${ serverConn.id }` + ); + } - // We poll here, instead of just checking `_getUserObserve` - // once, because the login method defers the creation of the - // observe, and setting up the observe yields, so we could end - // up here before the observe has been set up. - simplePoll( - () => !! Accounts._getUserObserve(serverConn.id), - () => { - test.isTrue(Accounts._getUserObserve(serverConn.id)); - clientConn.disconnect(); - }, - () => { - test.fail( - `timed out waiting for user observe for connection ${serverConn.id}` - ); - onComplete(); - } - ); - }, - onComplete - ); } ); - Tinytest.add( + Tinytest.addAsync( "passwords - reset password doesn't work if email changed after email sent", - test => { - const username = Random.id(); - const email = `${username}-intercept@example.com`; + async test => { + const username = Random.id() + 'reset-password-doesnt-work-if-email-changed' + const email = `${ username }-intercept@example.com`; - const userId = Accounts.createUser({ + const userId = await Accounts.createUser({ username: username, email: email, - password: hashPassword("old-password") + password: hashPasswordWithSha("old-password") }); + const user = await Meteor.users.findOneAsync(userId); - const user = Meteor.users.findOne(userId); - - Accounts.sendResetPasswordEmail(userId, email); - - const resetPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + await Accounts.sendResetPasswordEmail(userId, email); + const [resetPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); const re = new RegExp(`${Meteor.absoluteUrl()}#/reset-password/(\\S*)`); + const match = resetPasswordEmailOptions.text.match(re); test.isTrue(match); const resetPasswordToken = match[1]; - const newEmail = `${Random.id()}-new@example.com`; - Meteor.users.update(userId, {$set: {"emails.0.address": newEmail}}); + const newEmail = `${ Random.id() }-new@example.com`; + await Meteor.users.updateAsync(userId, { $set: { "emails.0.address": newEmail } }); - test.throws( - () => Meteor.call("resetPassword", resetPasswordToken, hashPassword("new-password")), + await test.throwsAsync( + async () => + await Meteor.callAsync("resetPassword", resetPasswordToken, hashPasswordWithSha("new-password")), /Token has invalid email address/ ); - test.throws( - () => Meteor.call( - "login", - {user: {username: username}, - password: hashPassword("new-password")} - ), - /Incorrect password/); + Accounts._options.ambiguousErrorMessages = true; + await test.throwsAsync( + async () => + await Meteor.callAsync( + "login", + { + user: { username: username }, + password: hashPasswordWithSha("new-password") + } + ), + /Something went wrong. Please check your credentials./); }); Tinytest.addAsync( 'passwords - reset password should work when token is not expired', - (test, onComplete) => { - const username = Random.id(); - const email = `${username}-intercept@example.com`; + async (test) => { + const username = Random.id() + 'reset-password-should-work-when-token-is-not-expired'; + const email = `${ username }-intercept-reset@example.com`; - const userId = Accounts.createUser({ + const userId = await Accounts.createUser({ username: username, email: email, - password: hashPassword("old-password") + password: hashPasswordWithSha("old-password") }); - const user = Meteor.users.findOne(userId); + const user = await Meteor.users.findOneAsync(userId); - Accounts.sendResetPasswordEmail(userId, email); - - const resetPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + await Accounts.sendResetPasswordEmail(userId, email); + const [resetPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); const re = new RegExp(`${Meteor.absoluteUrl()}#/reset-password/(\\S*)`); const match = resetPasswordEmailOptions.text.match(re); test.isTrue(match); const resetPasswordToken = match[1]; - - makeTestConnection( - test, - clientConn => { - test.isTrue(clientConn.call( - "resetPassword", - resetPasswordToken, - hashPassword("new-password") - )); - - test.isTrue(clientConn.call("login", { - user: { username }, - password: hashPassword("new-password") - })); - - onComplete(); - } - ); + const { clientConn } = await makeTestConnAsync(test) + test.isTrue(await clientConn.callAsync( + "resetPassword", + resetPasswordToken, + hashPasswordWithSha("new-password") + )); + test.isTrue(await clientConn.callAsync("login", { + user: { username }, + password: hashPasswordWithSha("new-password") + })); }); - Tinytest.add( + Tinytest.addAsync( 'passwords - reset password should not work when token is expired', - test => { + async test => { const username = Random.id(); - const email = `${username}-intercept@example.com`; + const email = `${ username }-intercept@example.com`; - const userId = Accounts.createUser({ + const userId = await Accounts.createUser({ username: username, email: email, - password: hashPassword("old-password") + password: hashPasswordWithSha("old-password") }); - const user = Meteor.users.findOne(userId); + const user = await Meteor.users.findOneAsync(userId); - Accounts.sendResetPasswordEmail(userId, email); + await Accounts.sendResetPasswordEmail(userId, email); - const resetPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + const [resetPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); const re = new RegExp(`${Meteor.absoluteUrl()}#/reset-password/(\\S*)`); const match = resetPasswordEmailOptions.text.match(re); test.isTrue(match); const resetPasswordToken = match[1]; - Meteor.users.update(userId, {$set: {"services.password.reset.when": new Date(Date.now() + -5 * 24 * 3600 * 1000) }}); + await Meteor.users.updateAsync(userId, { $set: { "services.password.reset.when": new Date(Date.now() + -5 * 24 * 3600 * 1000) } }); - test.throws( - () => Meteor.call("resetPassword", resetPasswordToken, hashPassword("new-password")), - /Token expired/ - ); - test.throws( - () => Meteor.call( + try { + await Meteor.callAsync("resetPassword", resetPasswordToken, hashPasswordWithSha("new-password")) + } catch (e) { + test.throws(() => { + throw e; + }) + } + + Accounts._options.ambiguousErrorMessages = true; + await test.throwsAsync( + async () => await Meteor.callAsync( "login", - {user: {username: username}, - password: hashPassword("new-password")} + { + user: { username: username }, + password: hashPasswordWithSha("new-password") + } ), - /Incorrect password/); + /Something went wrong. Please check your credentials./); }); - Tinytest.add('forgotPassword - different error messages returned depending' + - ' on whether ambiguousErrorMessages flag is passed in Account.config', - test =>{ - const username = Random.id(); - const email = `${Random.id()}-intercept@example.com`; - const randomEmail = `${Random.id()}-Ada_intercept@some.com`; - const wrongOptions = {email: randomEmail} - const password = 'password'; - const options = Accounts._options + Tinytest.addAsync('forgotPassword - different error messages returned depending' + + ' on whether ambiguousErrorMessages flag is passed in Account.config', + async test => { + const username = Random.id(); + const email = `${ Random.id() }-intercept@example.com`; + const randomEmail = `${ Random.id() }-Ada_intercept@some.com`; + const wrongOptions = { email: randomEmail } + const password = 'password'; + const options = Accounts._options - Accounts.createUser( - { username: username, email: email, password: hashPassword(password) }, - ); + await Accounts.createUser( + { + username: username, + email: email, + password: hashPasswordWithSha(password) + }, + ); - Accounts._options.ambiguousErrorMessages = true - test.throws( - ()=> Meteor.call('forgotPassword', wrongOptions), - 'Something went wrong. Please check your credentials' - ) + Accounts._options.ambiguousErrorMessages = true; + await test.throwsAsync( + async () => await Meteor.callAsync('forgotPassword', wrongOptions), + 'Something went wrong. Please check your credentials' + ); - Accounts._options.ambiguousErrorMessages = false - test.throws( - ()=> Meteor.call('forgotPassword', wrongOptions), - 'User not found' - ) - // return accounts as it were - Accounts._options = options + Accounts._options.ambiguousErrorMessages = false; + await test.throwsAsync( + async () => await Meteor.callAsync('forgotPassword', wrongOptions), + /User not found/ + ); + // return accounts as it were + Accounts._options = options }); - Tinytest.add( + Tinytest.addAsync( 'passwords - reset tokens with reasons get cleaned up', - test => { - const email = `${test.id}-intercept@example.com`; - const userId = Accounts.createUser({email: email, password: hashPassword('password')}); - Accounts.sendResetPasswordEmail(userId, email); - test.isTrue(!!Meteor.users.findOne(userId).services.password.reset); + async test => { + const email = `${ test.id }-intercept@example.com`; + const userId = + await Accounts.createUser( + { + email: email, + password: hashPasswordWithSha('password') + } + ); + await Accounts.sendResetPasswordEmail(userId, email); + const user1 = await Meteor.users.findOneAsync(userId); + test.isTrue(!!user1.services.password.reset); - Accounts._expirePasswordResetTokens(new Date(), userId); - - test.isUndefined(Meteor.users.findOne(userId).services.password.reset); + await Accounts._expirePasswordResetTokens(new Date(), userId); + const user2 = await Meteor.users.findOneAsync(userId); + test.isUndefined(user2.services.password.reset); }); - Tinytest.add( + Tinytest.addAsync( 'passwords - reset tokens without reasons get cleaned up', - test => { - const email = `${test.id}-intercept@example.com`; - const userId = Accounts.createUser({email: email, password: hashPassword('password')}); - Accounts.sendResetPasswordEmail(userId, email); - Meteor.users.update({_id: userId}, {$unset: {"services.password.reset.reason": 1}}); - test.isTrue(!!Meteor.users.findOne(userId).services.password.reset); - test.isUndefined(Meteor.users.findOne(userId).services.password.reset.reason); + async test => { + const email = `${ test.id }-intercept@example.com`; + const userId = + await Accounts.createUser( + { + email: email, + password: hashPasswordWithSha('password') + } + ); + await Accounts.sendResetPasswordEmail(userId, email); + await Meteor.users.updateAsync( + { _id: userId }, + { $unset: { "services.password.reset.reason": 1 } } + ); + const user1 = await Meteor.users.findOneAsync(userId); + test.isTrue(!!user1.services.password.reset); + test.isUndefined(user1.services.password.reset.reason); - Accounts._expirePasswordResetTokens(new Date(), userId); - - test.isUndefined(Meteor.users.findOne(userId).services.password.reset); + await Accounts._expirePasswordResetTokens(new Date(), userId); + const user2 = await Meteor.users.findOneAsync(userId); + test.isUndefined(user2.services.password.reset); }); Tinytest.addAsync( 'passwords - enroll password should work when token is not expired', - (test, onComplete) => { + async test => { const username = Random.id(); - const email = `${username}-intercept@example.com`; + const email = `${ username }-intercept@example.com`; - const userId = Accounts.createUser({ + const userId = await Accounts.createUser({ username: username, email: email }); - const user = Meteor.users.findOne(userId); - - Accounts.sendEnrollmentEmail(userId, email); - - const enrollPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + const user = await Meteor.users.findOneAsync(userId); + await Accounts.sendEnrollmentEmail(userId, email); + const [enrollPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); const re = new RegExp(`${Meteor.absoluteUrl()}#/enroll-account/(\\S*)`); const match = enrollPasswordEmailOptions.text.match(re); test.isTrue(match); const enrollPasswordToken = match[1]; - makeTestConnection( - test, - clientConn => { - test.isTrue(clientConn.call( - "resetPassword", - enrollPasswordToken, - hashPassword("new-password") - )); + const { + clientConn + } = await makeTestConnAsync(test) - test.isTrue(clientConn.call("login", { - user: { username }, - password: hashPassword("new-password") - })); + test.isTrue( + await clientConn.callAsync( + "resetPassword", + enrollPasswordToken, + hashPasswordWithSha("new-password")) + ); + test.isTrue( + await clientConn.callAsync("login", { + user: { username }, + password: hashPasswordWithSha("new-password") + }) + ); - onComplete(); - }); }); - Tinytest.add( + Tinytest.addAsync( 'passwords - enroll password should not work when token is expired', - test => { + async test => { const username = Random.id(); - const email = `${username}-intercept@example.com`; + const email = `${ username }-intercept@example.com`; - const userId = Accounts.createUser({ + const userId = await Accounts.createUser({ username: username, email: email }); - const user = Meteor.users.findOne(userId); + const user = await Meteor.users.findOneAsync(userId); - Accounts.sendEnrollmentEmail(userId, email); + await Accounts.sendEnrollmentEmail(userId, email); - const enrollPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + const [enrollPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); const re = new RegExp(`${Meteor.absoluteUrl()}#/enroll-account/(\\S*)`); const match = enrollPasswordEmailOptions.text.match(re); test.isTrue(match); const enrollPasswordToken = match[1]; - Meteor.users.update(userId, {$set: {"services.password.enroll.when": new Date(Date.now() + -35 * 24 * 3600 * 1000) }}); + await Meteor.users.updateAsync(userId, { $set: { "services.password.enroll.when": new Date(Date.now() + -35 * 24 * 3600 * 1000) } }); - test.throws( - () => Meteor.call("resetPassword", enrollPasswordToken, hashPassword("new-password")), + await test.throwsAsync( + async () => await Meteor.callAsync("resetPassword", enrollPasswordToken, hashPasswordWithSha("new-password")), /Token expired/ ); }); - Tinytest.add('passwords - enroll tokens get cleaned up', test => { - const email = `${test.id}-intercept@example.com`; - const userId = Accounts.createUser({email: email, password: hashPassword('password')}); + Tinytest.addAsync('passwords - enroll tokens get cleaned up', + async test => { + const email = `${ test.id }-intercept@example.com`; + const userId = + await Accounts.createUser({ email: email, password: hashPasswordWithSha('password') }); - Accounts.sendEnrollmentEmail(userId, email); - test.isTrue(!!Meteor.users.findOne(userId).services.password.enroll); - Accounts._expirePasswordEnrollTokens(new Date(), userId); - test.isUndefined(Meteor.users.findOne(userId).services.password.enroll); - }); + await Accounts.sendEnrollmentEmail(userId, email); + const user1 = await Meteor.users.findOneAsync(userId); + test.isTrue(!!user1.services.password.enroll); + await Accounts._expirePasswordEnrollTokens(new Date(), userId); + const user2 = await Meteor.users.findOneAsync(userId); + test.isUndefined(user2.services.password.enroll); + }); - Tinytest.add( + Tinytest.addAsync( "passwords - enroll tokens don't get cleaned up when reset tokens are cleaned up", - test => { - const email = `${test.id}-intercept@example.com`; - const userId = Accounts.createUser({email: email, password: hashPassword('password')}); + async test => { + const email = `${ test.id }-intercept@example.com`; + const userId = + await Accounts.createUser({ + email: email, + password: hashPasswordWithSha('password') + }); - Accounts.sendEnrollmentEmail(userId, email); - const enrollToken = Meteor.users.findOne(userId).services.password.enroll; + await Accounts.sendEnrollmentEmail(userId, email); + const user1 = await Meteor.users.findOneAsync(userId); + const enrollToken = user1.services.password.enroll; test.isTrue(enrollToken); - Accounts._expirePasswordResetTokens(new Date(), userId); - test.equal(enrollToken, Meteor.users.findOne(userId).services.password.enroll); + await Accounts._expirePasswordResetTokens(new Date(), userId); + const user2 = await Meteor.users.findOneAsync(userId) + test.equal(enrollToken, user2.services.password.enroll); } ) - Tinytest.add( + Tinytest.addAsync( "passwords - reset tokens don't get cleaned up when enroll tokens are cleaned up", - test => { - const email = `${test.id}-intercept@example.com`; - const userId = Accounts.createUser({email: email, password: hashPassword('password')}); + async test => { + const email = `${ test.id }-intercept@example.com`; + const userId = + await Accounts.createUser({ email: email, password: hashPasswordWithSha('password') }); - Accounts.sendResetPasswordEmail(userId, email); - const resetToken = Meteor.users.findOne(userId).services.password.reset; + await Accounts.sendResetPasswordEmail(userId, email); + const user1 = await Meteor.users.findOneAsync(userId); + const resetToken = user1.services.password.reset; test.isTrue(resetToken); - Accounts._expirePasswordEnrollTokens(new Date(), userId); - test.equal(resetToken,Meteor.users.findOne(userId).services.password.reset); + await Accounts._expirePasswordEnrollTokens(new Date(), userId); + const user2 = await Meteor.users.findOneAsync(userId); + test.equal(resetToken, user2.services.password.reset); } ) // We should be able to change the username - Tinytest.add("passwords - change username & findUserByUsername", test => { - const username = Random.id(); - const ignoreFieldName = "profile"; - const userId = Accounts.createUser({ - username, - [ignoreFieldName]: {name: 'foo'}, + Tinytest.addAsync("passwords - change username & findUserByUsername", + async test => { + const username = Random.id(); + const ignoreFieldName = "profile"; + const userId = await Accounts.createUser({ + username, + [ignoreFieldName]: { name: 'foo' }, + }); + + test.isTrue(userId); + + const newUsername = Random.id(); + await Accounts.setUsername(userId, newUsername); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.username, newUsername); + + // Test findUserByUsername as well while we're here + let user = await Accounts.findUserByUsername(newUsername); + test.equal(user._id, userId, 'userId - ignore'); + test.isNotUndefined(user[ignoreFieldName], 'field - no ignore'); + + // Test default field selector + const options = Accounts._options; + Accounts._options = { defaultFieldSelector: { [ignoreFieldName]: 0 } }; + user = await Accounts.findUserByUsername(newUsername); + test.equal(user.username, newUsername, 'username - default ignore'); + test.isUndefined(user[ignoreFieldName], 'field - default ignore'); + + // Test default field selector over-ride + user = await Accounts.findUserByUsername(newUsername, { + fields: { + [ignoreFieldName]: 1 + } + }); + test.isUndefined(user.username, 'username - override'); + test.isNotUndefined(user[ignoreFieldName], 'field - override'); + + Accounts._options = options; }); - test.isTrue(userId); - - const newUsername = Random.id(); - Accounts.setUsername(userId, newUsername); - - test.equal(Accounts._findUserByQuery({id: userId}).username, newUsername); - - // Test findUserByUsername as well while we're here - let user = Accounts.findUserByUsername(newUsername); - test.equal(user._id, userId, 'userId - ignore'); - test.isNotUndefined(user[ignoreFieldName], 'field - no ignore'); - - // Test default field selector - const options = Accounts._options; - Accounts._options = {defaultFieldSelector: {[ignoreFieldName]: 0}}; - user = Accounts.findUserByUsername(newUsername); - test.equal(user.username, newUsername, 'username - default ignore'); - test.isUndefined(user[ignoreFieldName], 'field - default ignore'); - - // Test default field selector over-ride - user = Accounts.findUserByUsername(newUsername, { - fields: { - [ignoreFieldName]: 1 - } - }); - test.isUndefined(user.username, 'username - override'); - test.isNotUndefined(user[ignoreFieldName], 'field - override'); - - Accounts._options = options; - }); - - Tinytest.add("passwords - change username to a new one only differing " + - "in case", test => { - const username = `${Random.id()}user`; - const userId = Accounts.createUser({ + Tinytest.addAsync("passwords - change username to a new one only differing " + + "in case", async test => { + const username = `${ Random.id() }user`; + const userId = await Accounts.createUser({ username: username.toUpperCase() }); test.isTrue(userId); const newUsername = username.toLowerCase(); - Accounts.setUsername(userId, newUsername); - - test.equal(Accounts._findUserByQuery({id: userId}).username, newUsername); + await Accounts.setUsername(userId, newUsername); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.username, newUsername); }); // We should not be able to change the username to one that only // differs in case from an existing one - Tinytest.add("passwords - change username should fail when there are " + - "existing users with a username only differing in case", test => { - const username = `${Random.id()}user`; - const usernameUpper = username.toUpperCase(); + Tinytest.addAsync("passwords - change username should fail when there are " + + "existing users with a username only differing in case", + async test => { + const username = `${ Random.id() }user`; + const usernameUpper = username.toUpperCase(); - const userId1 = Accounts.createUser({ - username: username + const userId1 = await Accounts.createUser({ + username: username + }); + + const user2OriginalUsername = Random.id(); + const userId2 = await Accounts.createUser({ + username: user2OriginalUsername + }); + + test.isTrue(userId1); + test.isTrue(userId2); + + Accounts._options.ambiguousErrorMessages = false; + await test.throwsAsync( + async () => await Accounts.setUsername(userId2, usernameUpper), + /Username already exists/ + ); + + const u2 = await Accounts._findUserByQuery({ id: userId2 }) + test.equal(u2.username, user2OriginalUsername); }); - const user2OriginalUsername = Random.id(); - const userId2 = Accounts.createUser({ - username: user2OriginalUsername + Tinytest.addAsync("passwords - add email & findUserByEmail", + async test => { + const origEmail = `${ Random.id() }@turing.com`; + const username = Random.id(); + const ignoreFieldName = "profile"; + const userId = await Accounts.createUser({ + email: origEmail, + username, + [ignoreFieldName]: { name: 'foo' }, + }); + + const newEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, newEmail); + + const thirdEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, thirdEmail, true); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.emails, [ + { address: origEmail, verified: false }, + { address: newEmail, verified: false }, + { address: thirdEmail, verified: true } + ]); + + // Test findUserByEmail as well while we're here + let user = await Accounts.findUserByEmail(origEmail); + test.equal(user._id, userId); + test.isNotUndefined(user[ignoreFieldName], 'field - no ignore'); + + // Test default field selector + const options = Accounts._options; + Accounts._options = { defaultFieldSelector: { [ignoreFieldName]: 0 } }; + user = await Accounts.findUserByEmail(origEmail); + test.equal(user.username, username, 'username - default ignore'); + test.isUndefined(user[ignoreFieldName], 'field - default ignore'); + + // Test default field selector over-ride + user = await Accounts.findUserByEmail(origEmail, { + fields: { + [ignoreFieldName]: 1 + } + }); + test.equal(user._id, userId, 'userId - override'); + test.isUndefined(user.username, 'username - override'); + test.isNotUndefined(user[ignoreFieldName], 'field - override'); + + Accounts._options = options; }); - test.isTrue(userId1); - test.isTrue(userId2); + Tinytest.addAsync("passwords - add email when user has not an existing email", + async test => { + const userId = await Accounts.createUser({ + username: `user${ Random.id() }` + }); - test.throws( - () => Accounts.setUsername(userId2, usernameUpper), - /Username already exists/ - ); + const newEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, newEmail); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.emails, [ + { address: newEmail, verified: false }, + ]); + }); - test.equal(Accounts._findUserByQuery({id: userId2}).username, - user2OriginalUsername); + Tinytest.addAsync("passwords - add email when the user has an existing email " + + "only differing in case", + async test => { + const origEmail = `${ Random.id() }@turing.com`; + const userId = await Accounts.createUser({ + email: origEmail + }); + + const newEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, newEmail); + + const thirdEmail = origEmail.toUpperCase(); + await Accounts.addEmailAsync(userId, thirdEmail, true); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.emails, [ + { address: thirdEmail, verified: true }, + { address: newEmail, verified: false } + ]); + }); + + Tinytest.addAsync("passwords - add email should fail when there is an existing " + + "user with an email only differing in case", + async test => { + const user1Email = `${ Random.id() }@turing.com`; + const userId1 = await Accounts.createUser({ + email: user1Email + }); + + const user2Email = `${ Random.id() }@turing.com`; + const userId2 = await Accounts.createUser({ + email: user2Email + }); + + const dupEmail = user1Email.toUpperCase(); + await test.throwsAsync( + async () => await Accounts.addEmailAsync(userId2, dupEmail), + /Email already exists/ + ); + + const u1 = await Accounts._findUserByQuery({ id: userId1 }) + test.equal(u1.emails, [ + { address: user1Email, verified: false } + ]); + const u2 = await Accounts._findUserByQuery({ id: userId2 }) + test.equal(u2.emails, [ + { address: user2Email, verified: false } + ]); + }); + + + +Tinytest.addAsync("accounts emails - replace email", async test => { + const origEmail = `originalemail@test.com`; + const userId = await Accounts.createUserAsync({ + email: origEmail, + password: 'password' }); - Tinytest.add("passwords - add email & findUserByEmail", test => { - const origEmail = `${Random.id()}@turing.com`; - const username = Random.id(); - const ignoreFieldName = "profile"; - const userId = Accounts.createUser({ - email: origEmail, - username, - [ignoreFieldName]: {name: 'foo'}, + const newEmail = `newemail@test.com`; + + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.emails, [ + { address: origEmail, verified: false } + ]); + + await Accounts.replaceEmailAsync(userId, origEmail, newEmail); + const u2 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u2.emails, [ + { address: newEmail, verified: false } + ]); +}) + + Tinytest.addAsync("passwords - remove email", + async test => { + const origEmail = `${ Random.id() }@turing.com`; + const userId = await Accounts.createUser({ + email: origEmail + }); + + const newEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, newEmail); + + const thirdEmail = `${ Random.id() }@turing.com`; + await Accounts.addEmailAsync(userId, thirdEmail, true); + const u1 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u1.emails, [ + { address: origEmail, verified: false }, + { address: newEmail, verified: false }, + { address: thirdEmail, verified: true } + ]); + + await Accounts.removeEmail(userId, newEmail); + const u2 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u2.emails, [ + { address: origEmail, verified: false }, + { address: thirdEmail, verified: true } + ]); + + await Accounts.removeEmail(userId, origEmail); + const u3 = await Accounts._findUserByQuery({ id: userId }) + test.equal(u3.emails, [ + { address: thirdEmail, verified: true } + ]); }); - const newEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, newEmail); - - const thirdEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, thirdEmail, true); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: origEmail, verified: false }, - { address: newEmail, verified: false }, - { address: thirdEmail, verified: true } - ]); - - // Test findUserByEmail as well while we're here - let user = Accounts.findUserByEmail(origEmail); - test.equal(user._id, userId); - test.isNotUndefined(user[ignoreFieldName], 'field - no ignore'); - - // Test default field selector - const options = Accounts._options; - Accounts._options = {defaultFieldSelector: {[ignoreFieldName]: 0}}; - user = Accounts.findUserByEmail(origEmail); - test.equal(user.username, username, 'username - default ignore'); - test.isUndefined(user[ignoreFieldName], 'field - default ignore'); - - // Test default field selector over-ride - user = Accounts.findUserByEmail(origEmail, { - fields: { - [ignoreFieldName]: 1 - } - }); - test.equal(user._id, userId, 'userId - override'); - test.isUndefined(user.username, 'username - override'); - test.isNotUndefined(user[ignoreFieldName], 'field - override'); - - Accounts._options = options; - }); - - Tinytest.add("passwords - add email when user has not an existing email", test => { - const userId = Accounts.createUser({ - username: `user${Random.id()}` - }); - - const newEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, newEmail); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: newEmail, verified: false }, - ]); - }); - - Tinytest.add("passwords - add email when the user has an existing email " + - "only differing in case", test => { - const origEmail = `${Random.id()}@turing.com`; - const userId = Accounts.createUser({ - email: origEmail - }); - - const newEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, newEmail); - - const thirdEmail = origEmail.toUpperCase(); - Accounts.addEmail(userId, thirdEmail, true); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: thirdEmail, verified: true }, - { address: newEmail, verified: false } - ]); - }); - - Tinytest.add("passwords - add email should fail when there is an existing " + - "user with an email only differing in case", test => { - const user1Email = `${Random.id()}@turing.com`; - const userId1 = Accounts.createUser({ - email: user1Email - }); - - const user2Email = `${Random.id()}@turing.com`; - const userId2 = Accounts.createUser({ - email: user2Email - }); - - const dupEmail = user1Email.toUpperCase(); - test.throws( - () => Accounts.addEmail(userId2, dupEmail), - /Email already exists/ - ); - - test.equal(Accounts._findUserByQuery({id: userId1}).emails, [ - { address: user1Email, verified: false } - ]); - - test.equal(Accounts._findUserByQuery({id: userId2}).emails, [ - { address: user2Email, verified: false } - ]); - }); - - Tinytest.add("passwords - remove email", test => { - const origEmail = `${Random.id()}@turing.com`; - const userId = Accounts.createUser({ - email: origEmail - }); - - const newEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, newEmail); - - const thirdEmail = `${Random.id()}@turing.com`; - Accounts.addEmail(userId, thirdEmail, true); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: origEmail, verified: false }, - { address: newEmail, verified: false }, - { address: thirdEmail, verified: true } - ]); - - Accounts.removeEmail(userId, newEmail); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: origEmail, verified: false }, - { address: thirdEmail, verified: true } - ]); - - Accounts.removeEmail(userId, origEmail); - - test.equal(Accounts._findUserByQuery({id: userId}).emails, [ - { address: thirdEmail, verified: true } - ]); - }); - - Tinytest.addAsync( - 'passwords - allow custom bcrypt rounds', - async (test, done) => { - const getUserHashRounds = user => - Number(user.services.password.bcrypt.substring(4, 6)); - - + const getUserHashRounds = user => + Number(user.services.password.bcrypt.substring(4, 6)); + testAsyncMulti("passwords - allow custom bcrypt rounds",[ + async function (test) { // Verify that a bcrypt hash generated for a new account uses the - // default number of rounds. let username = Random.id(); - const password = hashPassword('abc123'); - const userId1 = Accounts.createUser({ username, password }); - let user1 = Meteor.users.findOne(userId1); - let rounds = getUserHashRounds(user1); + this.password = hashPasswordWithSha('abc123'); + this.userId1 = await Accounts.createUser({ username, password: this.password }); + this.user1 = await Meteor.users.findOneAsync(this.userId1); + let rounds = getUserHashRounds(this.user1); test.equal(rounds, Accounts._bcryptRounds()); // When a custom number of bcrypt rounds is set via Accounts.config, // and an account was already created using the default number of rounds, // make sure that a new hash is created (and stored) using the new number // of rounds, the next time the password is checked. + this.customRounds = 11; + Accounts._options.bcryptRounds = this.customRounds; + await Accounts._checkPasswordAsync(this.user1, this.password); + }, + async function(test) { const defaultRounds = Accounts._bcryptRounds(); - const customRounds = 11; - Accounts._options.bcryptRounds = customRounds; - await Accounts._checkPasswordAsync(user1, password); - Meteor.setTimeout(() => { - user1 = Meteor.users.findOne(userId1); - rounds = getUserHashRounds(user1); - test.equal(rounds, customRounds); + let rounds; + let username; + let resolve; + const promise = new Promise(res => resolve = res); + + Meteor.setTimeout(async () => { + this.user1 = await Meteor.users.findOneAsync(this.userId1); + rounds = getUserHashRounds(this.user1); + test.equal(rounds, this.customRounds); // When a custom number of bcrypt rounds is set, make sure it's // used for new bcrypt password hashes. username = Random.id(); - const userId2 = Accounts.createUser({ username, password }); - const user2 = Meteor.users.findOne(userId2); + const userId2 = await Accounts.createUser({ username, password: this.password }); + const user2 = await Meteor.users.findOneAsync(userId2); rounds = getUserHashRounds(user2); - test.equal(rounds, customRounds); + test.equal(rounds, this.customRounds); // Cleanup Accounts._options.bcryptRounds = defaultRounds; - Meteor.users.remove(userId1); - Meteor.users.remove(userId2); - done(); + await Meteor.users.removeAsync(this.userId1); + await Meteor.users.removeAsync(userId2); + resolve(); }, 5000); + + return promise; } - ); + ]); // default number of rounds. - Tinytest.add('passwords - extra params in email urls', (test) => { - const username = Random.id(); - const email = `${username}-intercept@example.com`; - const userId = Accounts.createUser({ - username: username, - email: email + Tinytest.addAsync('passwords - extra params in email urls', + async (test) => { + const username = Random.id(); + const email = `${ username }-intercept@example.com`; + + const userId = await Accounts.createUser({ + username: username, + email: email + }); + + const extraParams = { test: 'success' }; + await Accounts.sendEnrollmentEmail(userId, email, null, extraParams); + + const [enrollPasswordEmailOptions] = + await Meteor.callAsync("getInterceptedEmails", email); + + const re = new RegExp(`${Meteor.absoluteUrl()}(\\S*)`); + const match = enrollPasswordEmailOptions.text.match(re); + const url = new URL(match) + test.equal(url.searchParams.get('test'), extraParams.test); }); - const extraParams = { test: 'success' }; - Accounts.sendEnrollmentEmail(userId, email, null, extraParams); + Tinytest.addAsync('passwords - createUserAsync', async test => { + const username = Random.id(); + const email = `${username}-intercept@example.com`; + const password = 'password'; - const enrollPasswordEmailOptions = - Meteor.call("getInterceptedEmails", email)[0]; + const userId = await Accounts.createUserAsync({ + username: username, + email: email, + password: password + }); - const re = new RegExp(`${Meteor.absoluteUrl()}(\\S*)`); - const match = enrollPasswordEmailOptions.text.match(re); - const url = new URL(match) - test.equal(url.searchParams.get('test'), extraParams.test); + test.isTrue(userId, 'User ID should be returned'); + const user = await Meteor.users.findOneAsync(userId); + test.equal(user.username, username, 'Username should match'); + test.equal(user.emails[0].address, email, 'Email should match'); + + Accounts.config({ + ambiguousErrorMessages: false, + }) + + await test.throwsAsync(async () => { + await Accounts.createUserAsync({ + username: username, + email: email, + password: password + }); + }, 'already exists'); }); -}) (); + Tinytest.addAsync('passwords - send email functions', async test => { + // Create a user with an unverified email + const username = Random.id(); + const email = `${username}-intercept@example.com`; + const password = 'password'; + + const userId = await Accounts.createUserAsync({ + username: username, + email: email, + password: password + }); + + test.isTrue(userId, 'User ID should be returned'); + + // Mock Email.sendAsync to track if it was called + const originalSendAsync = Email.sendAsync; + let emailSent = 0; + Email.sendAsync = async (options) => { + emailSent++; + return originalSendAsync(options); + }; + + try { + // Test sendVerificationEmail + const verificationResult = await Accounts.sendVerificationEmail(userId, email); + + // Verify the result contains expected properties + test.isTrue(verificationResult, 'Result should be returned for verification email'); + test.equal(verificationResult.email, email, 'Email in verification result should match'); + test.isTrue(verificationResult.user, 'User object should be in verification result'); + test.isTrue(verificationResult.token, 'Token should be in verification result'); + test.isTrue(verificationResult.url, 'URL should be in verification result'); + test.isTrue(verificationResult.options, 'Email options should be in verification result'); + + // Test sendEnrollmentEmail + const enrollmentResult = await Accounts.sendEnrollmentEmail(userId, email); + + // Verify the result contains expected properties + test.isTrue(enrollmentResult, 'Result should be returned for enrollment email'); + test.equal(enrollmentResult.email, email, 'Email in enrollment result should match'); + test.isTrue(enrollmentResult.user, 'User object should be in enrollment result'); + test.isTrue(enrollmentResult.token, 'Token should be in enrollment result'); + test.isTrue(enrollmentResult.url, 'URL should be in enrollment result'); + test.isTrue(enrollmentResult.options, 'Email options should be in enrollment result'); + + // Test sendResetPasswordEmail + const resetResult = await Accounts.sendResetPasswordEmail(userId, email); + + // Verify the result contains expected properties + test.isTrue(resetResult, 'Result should be returned for reset password email'); + test.equal(resetResult.email, email, 'Email in reset result should match'); + test.isTrue(resetResult.user, 'User object should be in reset result'); + test.isTrue(resetResult.token, 'Token should be in reset result'); + test.isTrue(resetResult.url, 'URL should be in reset result'); + test.isTrue(resetResult.options, 'Email options should be in reset result'); + + // Verify Email.sendAsync was called for all three emails + test.equal(emailSent, 3, 'Email.sendAsync should have been called three times'); + + // Get the intercepted emails + const interceptedEmails = await Meteor.callAsync("getInterceptedEmails", email); + test.equal(interceptedEmails.length, 3, 'Three emails should have been intercepted'); + + // Verify the verification email content + const verificationEmailOptions = interceptedEmails[0]; + test.isTrue(verificationEmailOptions, 'Verification email should have been intercepted'); + const verificationRe = new RegExp(`${Meteor.absoluteUrl()}#/verify-email/(\\S*)`); + const verificationMatch = verificationEmailOptions.text.match(verificationRe); + test.isTrue(verificationMatch, 'Verification email should contain verification URL'); + const verificationTokenFromUrl = verificationMatch[1]; + test.isTrue(verificationResult.url.includes(verificationTokenFromUrl), 'Verification URL in result should contain the token'); + + // Verify the enrollment email content + const enrollmentEmailOptions = interceptedEmails[1]; + test.isTrue(enrollmentEmailOptions, 'Enrollment email should have been intercepted'); + const enrollmentRe = new RegExp(`${Meteor.absoluteUrl()}#/enroll-account/(\\S*)`); + const enrollmentMatch = enrollmentEmailOptions.text.match(enrollmentRe); + test.isTrue(enrollmentMatch, 'Enrollment email should contain enrollment URL'); + const enrollmentTokenFromUrl = enrollmentMatch[1]; + test.isTrue(enrollmentResult.url.includes(enrollmentTokenFromUrl), 'Enrollment URL in result should contain the token'); + + // Verify the reset password email content + const resetEmailOptions = interceptedEmails[2]; + test.isTrue(resetEmailOptions, 'Reset password email should have been intercepted'); + const resetRe = new RegExp(`${Meteor.absoluteUrl()}#/reset-password/(\\S*)`); + const resetMatch = resetEmailOptions.text.match(resetRe); + test.isTrue(resetMatch, 'Reset password email should contain reset URL'); + const resetTokenFromUrl = resetMatch[1]; + test.isTrue(resetResult.url.includes(resetTokenFromUrl), 'Reset URL in result should contain the token'); + + // Verify email headers and from address for all emails + for (const emailOptions of interceptedEmails) { + test.equal(emailOptions.from, 'test@meteor.com', 'From address should match'); + test.equal(emailOptions.headers['My-Custom-Header'], 'Cool', 'Custom header should be present'); + } + } finally { + // Restore the original Email.sendAsync + Email.sendAsync = originalSendAsync; + } + }); +})(); diff --git a/packages/accounts-password/password_tests_setup.js b/packages/accounts-password/password_tests_setup.js index 82aba8c893..50a1e95862 100644 --- a/packages/accounts-password/password_tests_setup.js +++ b/packages/accounts-password/password_tests_setup.js @@ -118,17 +118,25 @@ Accounts.config({ }); -Meteor.methods({ - testMeteorUser: () => Meteor.user(), - clearUsernameAndProfile: function () { - if (!this.userId) - throw new Error("Not logged in!"); - Meteor.users.update(this.userId, - {$unset: {profile: 1, username: 1}}); - }, +Meteor.methods( + { + testMeteorUser: + async () => await Meteor.userAsync(), - expireTokens: function () { - Accounts._expireTokens(new Date(), this.userId); - }, - removeUser: username => Meteor.users.remove({ "username": username }), -}); + clearUsernameAndProfile: + async function () { + if (!this.userId) throw new Error("Not logged in!"); + await Meteor + .users + .updateAsync(this.userId, { $unset: { profile: 1, username: 1 } }); + }, + + expireTokens: + async function () { + await Accounts._expireTokens(new Date(), this.userId); + }, + + removeUser: + async username => await Meteor.users.removeAsync({ "username": username }), + } +); diff --git a/packages/accounts-passwordless/package.js b/packages/accounts-passwordless/package.js index 2743b88aaf..060171cd54 100644 --- a/packages/accounts-passwordless/package.js +++ b/packages/accounts-passwordless/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'No-password login/sign-up support for accounts', - version: '2.1.3', + version: '3.0.2', }); Package.onUse(api => { diff --git a/packages/accounts-passwordless/passwordless_server.js b/packages/accounts-passwordless/passwordless_server.js index 382867926a..20c23e17e8 100644 --- a/packages/accounts-passwordless/passwordless_server.js +++ b/packages/accounts-passwordless/passwordless_server.js @@ -8,13 +8,17 @@ import { } from './server_utils'; import { Random } from 'meteor/random'; -const findUserWithOptions = ({ selector }) => { +const findUserWithOptions = async ({ selector }) => { if (!selector) { Accounts._handleError('A selector is necessary'); } - const { email, ...rest } = selector; - return Meteor.users.findOne( - { ...rest, ...(email ? { 'emails.address': selector.email } : {}) }, + const { email, id, ...rest } = selector; + return Meteor.users.findOneAsync( + { + ...rest, + ...(id && { _id: id }), + ...(email && { 'emails.address': email }) + }, { fields: { services: 1, @@ -24,7 +28,7 @@ const findUserWithOptions = ({ selector }) => { ); }; // Handler to login with an ott. -Accounts.registerLoginHandler('passwordless', options => { +Accounts.registerLoginHandler('passwordless', async options => { if (!options.token) return undefined; // don't handle check(options, { @@ -36,7 +40,7 @@ Accounts.registerLoginHandler('passwordless', options => { const sequence = options.token.toUpperCase(); const { selector } = options; - const user = findUserWithOptions(options); + const user = await findUserWithOptions(options); if (!user) { Accounts._handleError('User not found'); @@ -73,7 +77,7 @@ Accounts.registerLoginHandler('passwordless', options => { // 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( + await Meteor.users.updateAsync( { _id: user._id, 'emails.address': verifiedEmail }, { $set: { @@ -89,7 +93,7 @@ Accounts.registerLoginHandler('passwordless', options => { // Utility for plucking addresses from emails const pluckAddresses = (emails = []) => emails.map(email => email.address); -const createUser = userData => { +const createUser = async userData => { const { username, email } = userData; if (!username && !email) { throw new Meteor.Error(400, 'Need to set a username or email'); @@ -110,8 +114,8 @@ function generateSequence() { } Meteor.methods({ - requestLoginTokenForUser: ({ selector, userData, options = {} }) => { - let user = Accounts._findUserByQuery(selector, { + requestLoginTokenForUser: async ({ selector, userData, options = {} }) => { + let user = await Accounts._findUserByQuery(selector, { fields: { emails: 1 }, }); @@ -127,8 +131,8 @@ Meteor.methods({ const isNewUser = !user; if (!user) { - const userId = createUser(userData); - user = Accounts._findUserByQuery( + const userId = await createUser(userData); + user = await Accounts._findUserByQuery( { id: userId }, { fields: { emails: 1 }, @@ -167,7 +171,7 @@ Meteor.methods({ Accounts._handleError(`Login tokens could not be generated`); } - Meteor.users.update(user._id, { + await Meteor.users.updateAsync(user._id, { $set: { 'services.passwordless': { createdAt: new Date(), @@ -182,21 +186,22 @@ Meteor.methods({ }); const shouldSendLoginTokenEmail = Accounts._onCreateLoginTokenHook - ? Accounts._onCreateLoginTokenHook({ + ? await Accounts._onCreateLoginTokenHook({ token: userSequence, userId: user._id, }) : true; if (shouldSendLoginTokenEmail) { - tokens.forEach(({ email, sequence }) => { + const sendLogins = tokens.map(({ email, sequence }) => Accounts.sendLoginTokenEmail({ userId: user._id, sequence, email, ...(options.extra ? { extra: options.extra } : {}), - }); - }); + }) + ); + await Promise.all(sendLogins); } return result; @@ -213,17 +218,17 @@ Meteor.methods({ * @param {Object} options.extra Optional. Extra properties * @returns {Object} Object with {email, user, token, url, options} values. */ -Accounts.sendLoginTokenEmail = ({ userId, sequence, email, extra = {} }) => { - const user = getUserById(userId); - const url = Accounts.urls.loginToken(email, sequence); - const options = Accounts.generateOptionsForEmail( +Accounts.sendLoginTokenEmail = async ({ userId, sequence, email, extra = {} }) => { + const user = await getUserById(userId); + const url = await Accounts._resolvePromise(Accounts.urls.loginToken(email, sequence, extra)); + const options = await Accounts.generateOptionsForEmail( email, user, url, 'sendLoginToken', { ...extra, sequence } ); - Email.send({ ...options, extra }); + await Email.sendAsync({ ...options, extra }); if (Meteor.isDevelopment) { console.log(`\nLogin Token url: ${url}`); } @@ -231,11 +236,11 @@ Accounts.sendLoginTokenEmail = ({ userId, sequence, email, extra = {} }) => { }; const setupUsersCollection = () => { - Meteor.users.createIndex('services.passwordless.tokens.token', { + Meteor.users.createIndexAsync('services.passwordless.tokens.token', { unique: true, sparse: true, }); - Meteor.users.createIndex('services.passwordless.token', { + Meteor.users.createIndexAsync('services.passwordless.token', { unique: true, sparse: true, }); diff --git a/packages/accounts-passwordless/server_utils.js b/packages/accounts-passwordless/server_utils.js index f41414cbad..4e9a2b20d5 100644 --- a/packages/accounts-passwordless/server_utils.js +++ b/packages/accounts-passwordless/server_utils.js @@ -5,8 +5,8 @@ import { SHA256 } from 'meteor/sha'; const ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000; export const DEFAULT_TOKEN_SEQUENCE_LENGTH = 6; -export const getUserById = (id, options) => - Meteor.users.findOne(id, Accounts._addDefaultFieldSelector(options)); +export const getUserById = async (id, options) => + Meteor.users.findOneAsync(id, Accounts._addDefaultFieldSelector(options)); export const tokenValidator = () => { const tokenLength = diff --git a/packages/accounts-twitter/package.js b/packages/accounts-twitter/package.js index a444a9d9ef..405c08d38b 100644 --- a/packages/accounts-twitter/package.js +++ b/packages/accounts-twitter/package.js @@ -1,20 +1,20 @@ Package.describe({ summary: "Login service for Twitter accounts", - version: "1.5.0", + version: "1.5.2", }); -Package.onUse(api => { - api.use('ecmascript'); - api.use('accounts-base', ['client', 'server']); +Package.onUse((api) => { + api.use("ecmascript"); + api.use("accounts-base", ["client", "server"]); // Export Accounts (etc) to packages using this one. - api.imply('accounts-base', ['client', 'server']); - api.use('accounts-oauth', ['client', 'server']); - api.use('twitter-oauth'); - api.imply('twitter-oauth'); + api.imply("accounts-base", ["client", "server"]); + api.use("accounts-oauth", ["client", "server"]); + api.use("twitter-oauth"); + api.imply("twitter-oauth"); - api.use('http', ['client', 'server']); - - api.use(['accounts-ui', 'twitter-config-ui'], ['client', 'server'], { weak: true }); + api.use(["accounts-ui", "twitter-config-ui"], ["client", "server"], { + weak: true, + }); api.addFiles("notice.js"); api.addFiles("twitter.js"); diff --git a/packages/accounts-ui-unstyled/login_buttons_dropdown.js b/packages/accounts-ui-unstyled/login_buttons_dropdown.js index 548b296518..8f67169eea 100644 --- a/packages/accounts-ui-unstyled/login_buttons_dropdown.js +++ b/packages/accounts-ui-unstyled/login_buttons_dropdown.js @@ -226,7 +226,7 @@ const isInPasswordSignupFields = (fieldOrFields) => { return signupFields.reduce( (prev, field) => prev && fieldOrFields.includes(field), true, - ) + ); } return signupFields.includes(fieldOrFields); @@ -488,7 +488,7 @@ Template._loginButtonsLoggedOutPasswordlessService.helpers({ inSignupFlow: () => loginButtonsSession.get('inSignupFlow'), showCreateAccountLink: () => !Accounts._options.forbidClientAccountCreation, -}) +}); Template._loginButtonsLoggedOutPasswordService.helpers({ fields: () => { @@ -565,7 +565,7 @@ Template._loginButtonsLoggedOutPasswordService.helpers({ Template._loginButtonsFormField.helpers({ inputType: function () { - return this.inputType || "text" + return this.inputType || "text"; } }); @@ -584,7 +584,7 @@ Template._loginButtonsChangePassword.events({ Template._loginButtonsChangePassword.helpers({ fields: () => { - const { username, emails } = Meteor.user() + const { username, emails } = Meteor.user(); let email; if (emails) { email = emails[0].address; diff --git a/packages/accounts-ui-unstyled/login_buttons_single.js b/packages/accounts-ui-unstyled/login_buttons_single.js index 8a2fdeb3da..a850e409d0 100644 --- a/packages/accounts-ui-unstyled/login_buttons_single.js +++ b/packages/accounts-ui-unstyled/login_buttons_single.js @@ -78,6 +78,9 @@ Template._loginButtonsLoggedOutSingleLoginButton.helpers({ return !!ServiceConfiguration.configurations.findOne({service: this.name}); }, capitalizedName: function () { + if (this.name === 'twitter') { + return 'X/Twitter'; + } if (this.name === 'github') // XXX we should allow service packages to set their capitalized name return 'GitHub'; diff --git a/packages/accounts-ui-unstyled/package.js b/packages/accounts-ui-unstyled/package.js index e6985bd1e0..ae508a96de 100644 --- a/packages/accounts-ui-unstyled/package.js +++ b/packages/accounts-ui-unstyled/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Unstyled version of login widgets', - version: '1.7.0', + version: '1.7.2', }); Package.onUse(function(api) { diff --git a/packages/accounts-ui/package.js b/packages/accounts-ui/package.js index 49b6f4a00a..d31273bc30 100644 --- a/packages/accounts-ui/package.js +++ b/packages/accounts-ui/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Simple templates to add login widgets to an app", - version: "1.4.2", + version: '1.4.3', }); Package.onUse(api => { diff --git a/packages/accounts-weibo/package.js b/packages/accounts-weibo/package.js index 92bae9f3c5..c38e6316d4 100644 --- a/packages/accounts-weibo/package.js +++ b/packages/accounts-weibo/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Login service for Sina Weibo accounts", - version: "1.4.0", + version: '1.4.1', }); Package.onUse(api => { diff --git a/packages/allow-deny/allow-deny.js b/packages/allow-deny/allow-deny.js index e1bff9f9ab..802cd467dd 100644 --- a/packages/allow-deny/allow-deny.js +++ b/packages/allow-deny/allow-deny.js @@ -7,14 +7,14 @@ const hasOwn = Object.prototype.hasOwnProperty; // Restrict default mutators on collection. allow() and deny() take the // same options: // -// options.insert {Function(userId, doc)} +// options.insertAsync {Function(userId, doc)} // return true to allow/deny adding this document // -// options.update {Function(userId, docs, fields, modifier)} +// options.updateAsync {Function(userId, docs, fields, modifier)} // return true to allow/deny updating these documents. // `fields` is passed as an array of fields that are to be modified // -// options.remove {Function(userId, docs)} +// options.removeAsync {Function(userId, docs)} // return true to allow/deny removing these documents // // options.fetch {Array} @@ -90,7 +90,10 @@ CollectionPrototype._defineMutationMethods = function(options) { insert: {allow: [], deny: []}, update: {allow: [], deny: []}, remove: {allow: [], deny: []}, - upsert: {allow: [], deny: []}, // dummy arrays; can't set these! + insertAsync: {allow: [], deny: []}, + updateAsync: {allow: [], deny: []}, + removeAsync: {allow: [], deny: []}, + upsertAsync: {allow: [], deny: []}, // dummy arrays; can't set these! fetch: [], fetchAllFields: false }; @@ -99,7 +102,7 @@ CollectionPrototype._defineMutationMethods = function(options) { return; // anonymous collection // XXX Think about method namespacing. Maybe methods should be - // "Meteor:Mongo:insert/NAME"? + // "Meteor:Mongo:insertAsync/NAME"? self._prefix = '/' + self._name + '/'; // Mutation Methods @@ -110,26 +113,40 @@ CollectionPrototype._defineMutationMethods = function(options) { if (self._connection && (self._connection === Meteor.server || Meteor.isClient)) { const m = {}; - ['insert', 'update', 'remove'].forEach((method) => { + [ + 'insertAsync', + 'updateAsync', + 'removeAsync', + 'insert', + 'update', + 'remove', + ].forEach(method => { const methodName = self._prefix + method; if (options.useExisting) { - const handlerPropName = Meteor.isClient ? '_methodHandlers' : 'method_handlers'; + const handlerPropName = Meteor.isClient + ? '_methodHandlers' + : 'method_handlers'; // Do not try to create additional methods if this has already been called. // (Otherwise the .methods() call below will throw an error.) - if (self._connection[handlerPropName] && - typeof self._connection[handlerPropName][methodName] === 'function') return; + if ( + self._connection[handlerPropName] && + typeof self._connection[handlerPropName][methodName] === 'function' + ) + return; } + const isInsert = name => name.includes('insert'); + m[methodName] = function (/* ... */) { // All the methods do their own validation, instead of using check(). check(arguments, [Match.Any]); const args = Array.from(arguments); try { - // For an insert, if the client didn't specify an _id, generate one + // For an insert/insertAsync, if the client didn't specify an _id, generate one // now; because this uses DDP.randomStream, it will be consistent with // what the client generated. We generate it now rather than later so - // that if (eg) an allow/deny rule does an insert to the same + // that if (eg) an allow/deny rule does an insert/insertAsync to the same // collection (not that it really should), the generated _id will // still be the first use of the stream and will be consistent. // @@ -138,42 +155,57 @@ CollectionPrototype._defineMutationMethods = function(options) { // between arbitrary client-specified _id fields and merely // client-controlled-via-randomSeed fields. let generatedId = null; - if (method === "insert" && !hasOwn.call(args[0], '_id')) { + if (isInsert(method) && !hasOwn.call(args[0], '_id')) { generatedId = self._makeNewID(); } if (this.isSimulation) { // In a client simulation, you can do any mutation (even with a // complex selector). - if (generatedId !== null) + if (generatedId !== null) { args[0]._id = generatedId; - return self._collection[method].apply( - self._collection, args); + } + return self._collection[method].apply(self._collection, args); } // This is the server receiving a method call from the client. // We don't allow arbitrary selectors in mutations from the client: only // single-ID selectors. - if (method !== 'insert') - throwIfSelectorIsNotId(args[0], method); + if (!isInsert(method)) throwIfSelectorIsNotId(args[0], method); + + const syncMethodName = method.replace('Async', ''); + const syncValidatedMethodName = '_validated' + method.charAt(0).toUpperCase() + syncMethodName.slice(1); + // it forces to use async validated behavior + const validatedMethodName = syncValidatedMethodName + 'Async'; if (self._restricted) { // short circuit if there is no way it will pass. - if (self._validators[method].allow.length === 0) { + if (self._validators[syncMethodName].allow.length === 0) { throw new Meteor.Error( - 403, "Access denied. No allow validators set on restricted " + - "collection for method '" + method + "'."); + 403, + 'Access denied. No allow validators set on restricted ' + + "collection for method '" + + method + + "'." + ); } - const validatedMethodName = - '_validated' + method.charAt(0).toUpperCase() + method.slice(1); args.unshift(this.userId); - method === 'insert' && args.push(generatedId); + isInsert(method) && args.push(generatedId); return self[validatedMethodName].apply(self, args); } else if (self._isInsecure()) { - if (generatedId !== null) - args[0]._id = generatedId; + if (generatedId !== null) args[0]._id = generatedId; + // In insecure mode we use the server _collection methods, and these sync methods + // do not exist in the server anymore, so we have this mapper to call the async methods + // instead. + const syncMethodsMapper = { + insert: "insertAsync", + update: "updateAsync", + remove: "removeAsync", + }; + + // In insecure mode, allow any mutation (with a simple selector). // XXX This is kind of bogus. Instead of blindly passing whatever // we get from the network to this function, we should actually @@ -185,11 +217,11 @@ CollectionPrototype._defineMutationMethods = function(options) { // invoke it. Bam, broken DDP connection. Probably should just // take this whole method and write it three times, invoking // helpers for the common code. - return self._collection[method].apply(self._collection, args); + return self._collection[syncMethodsMapper[method] || method].apply(self._collection, args); } else { // In secure mode, if we haven't called allow or deny, then nothing // is permitted. - throw new Meteor.Error(403, "Access denied"); + throw new Meteor.Error(403, 'Access denied'); } } catch (e) { if ( @@ -237,37 +269,57 @@ CollectionPrototype._isInsecure = function () { return self._insecure; }; -CollectionPrototype._validatedInsert = function (userId, doc, - generatedId) { - const self = this; +async function asyncSome(array, predicate) { + for (let item of array) { + if (await predicate(item)) { + return true; + } + } + return false; +} +async function asyncEvery(array, predicate) { + for (let item of array) { + if (!await predicate(item)) { + return false; + } + } + return true; +} + +CollectionPrototype._validatedInsertAsync = async function(userId, doc, + generatedId) { + const self = this; // call user validators. // Any deny returns true means denied. - if (self._validators.insert.deny.some((validator) => { - return validator(userId, docToValidate(validator, doc, generatedId)); + if (await asyncSome(self._validators.insert.deny, async (validator) => { + const result = validator(userId, docToValidate(validator, doc, generatedId)); + return Meteor._isPromise(result) ? await result : result; })) { throw new Meteor.Error(403, "Access denied"); } // Any allow returns true means proceed. Throw error if they all fail. - if (self._validators.insert.allow.every((validator) => { - return !validator(userId, docToValidate(validator, doc, generatedId)); + + if (await asyncEvery(self._validators.insert.allow, async (validator) => { + const result = validator(userId, docToValidate(validator, doc, generatedId)); + return !(Meteor._isPromise(result) ? await result : result); })) { throw new Meteor.Error(403, "Access denied"); } - // If we generated an ID above, insert it now: after the validation, but + // If we generated an ID above, insertAsync it now: after the validation, but // before actually inserting. if (generatedId !== null) doc._id = generatedId; - self._collection.insert.call(self._collection, doc); + return self._collection.insertAsync.call(self._collection, doc); }; // Simulate a mongo `update` operation while validating that the access // control rules set by calls to `allow/deny` are satisfied. If all // pass, rewrite the mongo operation to use $in to set the list of // document ids to change ##ValidatedChange -CollectionPrototype._validatedUpdate = function( +CollectionPrototype._validatedUpdateAsync = async function( userId, selector, mutator, options) { const self = this; @@ -326,28 +378,31 @@ CollectionPrototype._validatedUpdate = function( }); } - const doc = self._collection.findOne(selector, findOptions); + const doc = await self._collection.findOneAsync(selector, findOptions); if (!doc) // none satisfied! return 0; // call user validators. // Any deny returns true means denied. - if (self._validators.update.deny.some((validator) => { + if (await asyncSome(self._validators.update.deny, async (validator) => { const factoriedDoc = transformDoc(validator, doc); - return validator(userId, - factoriedDoc, - fields, - mutator); + const result = validator(userId, + factoriedDoc, + fields, + mutator); + return Meteor._isPromise(result) ? await result : result; })) { throw new Meteor.Error(403, "Access denied"); } + // Any allow returns true means proceed. Throw error if they all fail. - if (self._validators.update.allow.every((validator) => { + if (await asyncEvery(self._validators.update.allow, async (validator) => { const factoriedDoc = transformDoc(validator, doc); - return !validator(userId, - factoriedDoc, - fields, - mutator); + const result = validator(userId, + factoriedDoc, + fields, + mutator); + return !(Meteor._isPromise(result) ? await result : result); })) { throw new Meteor.Error(403, "Access denied"); } @@ -359,7 +414,7 @@ CollectionPrototype._validatedUpdate = function( // avoid races, but since selector is guaranteed to already just be an ID, we // don't have to any more. - return self._collection.update.call( + return self._collection.updateAsync.call( self._collection, selector, mutator, options); }; @@ -376,7 +431,7 @@ const ALLOWED_UPDATE_OPERATIONS = { // Simulate a mongo `remove` operation while validating access control // rules. See #ValidatedChange -CollectionPrototype._validatedRemove = function(userId, selector) { +CollectionPrototype._validatedRemoveAsync = async function(userId, selector) { const self = this; const findOptions = {transform: null}; @@ -387,20 +442,22 @@ CollectionPrototype._validatedRemove = function(userId, selector) { }); } - const doc = self._collection.findOne(selector, findOptions); + const doc = await self._collection.findOneAsync(selector, findOptions); if (!doc) return 0; // call user validators. // Any deny returns true means denied. - if (self._validators.remove.deny.some((validator) => { - return validator(userId, transformDoc(validator, doc)); + if (await asyncSome(self._validators.remove.deny, async (validator) => { + const result = validator(userId, transformDoc(validator, doc)); + return Meteor._isPromise(result) ? await result : result; })) { throw new Meteor.Error(403, "Access denied"); } // Any allow returns true means proceed. Throw error if they all fail. - if (self._validators.remove.allow.every((validator) => { - return !validator(userId, transformDoc(validator, doc)); + if (await asyncEvery(self._validators.remove.allow, async (validator) => { + const result = validator(userId, transformDoc(validator, doc)); + return !(Meteor._isPromise(result) ? await result : result); })) { throw new Meteor.Error(403, "Access denied"); } @@ -410,9 +467,29 @@ CollectionPrototype._validatedRemove = function(userId, selector) { // Mongo to avoid races, but since selector is guaranteed to already just be // an ID, we don't have to any more. - return self._collection.remove.call(self._collection, selector); + return self._collection.removeAsync.call(self._collection, selector); }; +CollectionPrototype._callMutatorMethodAsync = function _callMutatorMethodAsync(name, args, options = {}) { + + // For two out of three mutator methods, the first argument is a selector + const firstArgIsSelector = name === "updateAsync" || name === "removeAsync"; + if (firstArgIsSelector && !alreadyInSimulation()) { + // If we're about to actually send an RPC, we should throw an error if + // this is a non-ID selector, because the mutation methods only allow + // single-ID selectors. (If we don't throw here, we'll see flicker.) + throwIfSelectorIsNotId(args[0], name); + } + + const mutatorMethodName = this._prefix + name; + return this._connection.applyAsync(mutatorMethodName, args, { + returnStubValue: this.resolverType === 'stub' || this.resolverType == null, + // StubStream is only used for testing where you don't care about the server + returnServerResultPromise: !this._connection._stream._isStub && this.resolverType !== 'stub', + ...options, + }); +} + CollectionPrototype._callMutatorMethod = function _callMutatorMethod(name, args, callback) { if (Meteor.isClient && !callback && !alreadyInSimulation()) { // Client can't block, so it can't report errors by exception, @@ -457,7 +534,7 @@ function docToValidate(validator, doc, generatedId) { // to tell the difference between "client specified the ID" and "server // generated the ID", because transforms expect to get _id. If you want to // do that check, you can do it with a specific - // `C.allow({insert: f, transform: null})` validator. + // `C.allow({insertAsync: f, transform: null})` validator. if (generatedId !== null) { ret._id = generatedId; } @@ -468,38 +545,56 @@ function docToValidate(validator, doc, generatedId) { function addValidator(collection, allowOrDeny, options) { // validate keys - const validKeysRegEx = /^(?:insert|update|remove|fetch|transform)$/; + const validKeysRegEx = /^(?:insertAsync|updateAsync|removeAsync|insert|update|remove|fetch|transform)$/; Object.keys(options).forEach((key) => { if (!validKeysRegEx.test(key)) throw new Error(allowOrDeny + ": Invalid key: " + key); + + // TODO deprecated async config on future versions + const isAsyncKey = key.includes('Async'); + if (isAsyncKey) { + const syncKey = key.replace('Async', ''); + Meteor.deprecate(allowOrDeny + `: The "${key}" key is deprecated. Use "${syncKey}" instead.`); + } }); collection._restricted = true; - ['insert', 'update', 'remove'].forEach((name) => { + [ + 'insertAsync', + 'updateAsync', + 'removeAsync', + 'insert', + 'update', + 'remove', + ].forEach(name => { if (hasOwn.call(options, name)) { if (!(options[name] instanceof Function)) { - throw new Error(allowOrDeny + ": Value for `" + name + "` must be a function"); + throw new Error( + allowOrDeny + ': Value for `' + name + '` must be a function' + ); } // If the transform is specified at all (including as 'null') in this // call, then take that; otherwise, take the transform from the // collection. if (options.transform === undefined) { - options[name].transform = collection._transform; // already wrapped + options[name].transform = collection._transform; // already wrapped } else { options[name].transform = LocalCollection.wrapTransform( - options.transform); + options.transform + ); } - - collection._validators[name][allowOrDeny].push(options[name]); + const isAsyncName = name.includes('Async'); + const validatorSyncName = isAsyncName ? name.replace('Async', '') : name; + collection._validators[validatorSyncName][allowOrDeny].push(options[name]); } }); - // Only update the fetch fields if we're passed things that affect - // fetching. This way allow({}) and allow({insert: f}) don't result in + // Only updateAsync the fetch fields if we're passed things that affect + // fetching. This way allow({}) and allow({insertAsync: f}) don't result in // setting fetchAllFields - if (options.update || options.remove || options.fetch) { + if (options.updateAsync || options.removeAsync || options.fetch) { if (options.fetch && !(options.fetch instanceof Array)) { throw new Error(allowOrDeny + ": Value for `fetch` must be an array"); } diff --git a/packages/allow-deny/package.js b/packages/allow-deny/package.js index 9ac1d408d8..c4dc9d3e78 100644 --- a/packages/allow-deny/package.js +++ b/packages/allow-deny/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'allow-deny', - version: '1.1.1', + version: '2.1.0', // 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. diff --git a/packages/audit-argument-checks/package.js b/packages/audit-argument-checks/package.js index 8cdeb571d6..f4418d6381 100644 --- a/packages/audit-argument-checks/package.js +++ b/packages/audit-argument-checks/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Try to detect inadequate input sanitization", - version: '1.0.7' + version: '1.0.8', }); // This package is empty; its presence is detected by livedata. diff --git a/packages/autopublish/package.js b/packages/autopublish/package.js index 8eb03d221f..1067567d5e 100644 --- a/packages/autopublish/package.js +++ b/packages/autopublish/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "(For prototyping only) Publish the entire database to all clients", - version: '1.0.7' + version: '1.0.8', }); // This package is empty; its presence is detected by several other packages diff --git a/packages/autoupdate/autoupdate_client.js b/packages/autoupdate/autoupdate_client.js index 2d93a367ec..61a6df35b5 100644 --- a/packages/autoupdate/autoupdate_client.js +++ b/packages/autoupdate/autoupdate_client.js @@ -45,7 +45,7 @@ const clientVersions = Autoupdate._clientVersions = // Used by a self-test and hot-module-replacement new ClientVersions(); -Meteor.connection.registerStore( +Meteor.connection.registerStoreClient( "meteor_autoupdate_clientVersions", clientVersions.createStore() ); diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index 3b64afb450..00771ee1f0 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -13,7 +13,9 @@ const clientVersions = new ClientVersions(); // Used by hot-module-replacement Autoupdate._clientVersions = clientVersions; -Meteor.connection.registerStore( + +// TODO[fibers]: make it's fine to call registerStoreClient here +Meteor.connection.registerStoreClient( "meteor_autoupdate_clientVersions", clientVersions.createStore() ); diff --git a/packages/autoupdate/autoupdate_server.js b/packages/autoupdate/autoupdate_server.js index 5a85f62bfe..82af4c65e6 100644 --- a/packages/autoupdate/autoupdate_server.js +++ b/packages/autoupdate/autoupdate_server.js @@ -25,8 +25,8 @@ // The ID of each document is the client architecture, and the fields of // the document are the versions described above. +import { onMessage } from "meteor/inter-process-messaging"; import { ClientVersions } from "./client_versions.js"; -var Future = Npm.require("fibers/future"); export const Autoupdate = __meteor_runtime_config__.autoupdate = { // Map from client architectures (web.browser, web.browser.legacy, @@ -53,12 +53,12 @@ Autoupdate.autoupdateVersionRefreshable = null; Autoupdate.autoupdateVersionCordova = null; Autoupdate.appId = __meteor_runtime_config__.appId = process.env.APP_ID; -var syncQueue = new Meteor._SynchronousQueue(); +var syncQueue = new Meteor._AsynchronousQueue(); -function updateVersions(shouldReloadClientProgram) { +async function updateVersions(shouldReloadClientProgram) { // Step 1: load the current client program on the server if (shouldReloadClientProgram) { - WebAppInternals.reloadClientPrograms(); + await WebAppInternals.reloadClientPrograms(); } const { @@ -87,7 +87,7 @@ function updateVersions(shouldReloadClientProgram) { // Step 3: form the new client boilerplate which contains the updated // assets and __meteor_runtime_config__. if (shouldReloadClientProgram) { - WebAppInternals.generateBoilerplate(); + await WebAppInternals.generateBoilerplate(); } // Step 4: update the ClientVersions collection. @@ -130,8 +130,8 @@ Meteor.publish( {is_auto: true} ); -Meteor.startup(function () { - updateVersions(false); +Meteor.startup(async function () { + await updateVersions(false); // Force any connected clients that are still looking for these older // document IDs to reload. @@ -145,33 +145,45 @@ Meteor.startup(function () { }); }); -var fut = new Future(); - -// We only want 'refresh' to trigger 'updateVersions' AFTER onListen, -// so we add a queued task that waits for onListen before 'refresh' can queue -// tasks. Note that the `onListening` callbacks do not fire until after -// Meteor.startup, so there is no concern that the 'updateVersions' calls from -// 'refresh' will overlap with the `updateVersions` call from Meteor.startup. - -syncQueue.queueTask(function () { - fut.wait(); -}); - -WebApp.onListening(function () { - fut.return(); -}); - function enqueueVersionsRefresh() { - syncQueue.queueTask(function () { - updateVersions(true); + syncQueue.queueTask(async function () { + await updateVersions(true); }); } -// Listen for messages pertaining to the client-refresh topic. -import { onMessage } from "meteor/inter-process-messaging"; -onMessage("client-refresh", enqueueVersionsRefresh); +const setupListeners = () => { + // Listen for messages pertaining to the client-refresh topic. + onMessage("client-refresh", enqueueVersionsRefresh); -// Another way to tell the process to refresh: send SIGHUP signal -process.on('SIGHUP', Meteor.bindEnvironment(function () { - enqueueVersionsRefresh(); -}, "handling SIGHUP signal for refresh")); + // Another way to tell the process to refresh: send SIGHUP signal + process.on('SIGHUP', Meteor.bindEnvironment(function () { + enqueueVersionsRefresh(); + }, "handling SIGHUP signal for refresh")); +}; + +if (Meteor._isFibersEnabled) { + var Future = Npm.require("fibers/future"); + + var fut = new Future(); + + // We only want 'refresh' to trigger 'updateVersions' AFTER onListen, + // so we add a queued task that waits for onListen before 'refresh' can queue + // tasks. Note that the `onListening` callbacks do not fire until after + // Meteor.startup, so there is no concern that the 'updateVersions' calls from + // 'refresh' will overlap with the `updateVersions` call from Meteor.startup. + + syncQueue.queueTask(function () { + fut.wait(); + }); + + WebApp.onListening(function () { + fut.return(); + }); + + setupListeners(); + +} else { + WebApp.onListening(function () { + Promise.resolve(setupListeners()); + }); +} diff --git a/packages/autoupdate/package.js b/packages/autoupdate/package.js index 3388f8ac20..514439ce1c 100644 --- a/packages/autoupdate/package.js +++ b/packages/autoupdate/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Update the client when new client code is available', - version: '1.8.0', + version: '2.0.1', }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index 2318003140..0000000000 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,923 +0,0 @@ -{ - "lockfileVersion": 1, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==" - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" - }, - "@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==" - }, - "@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", - "dependencies": { - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - } - } - }, - "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==" - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==" - }, - "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==" - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", - "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==" - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", - "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==" - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==" - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==" - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==" - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", - "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==" - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" - }, - "@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==" - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==" - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==" - }, - "@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==" - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==" - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==" - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - }, - "@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==" - }, - "@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==" - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" - }, - "@babel/parser": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz", - "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==" - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==" - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==" - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==" - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==" - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==" - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", - "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==" - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==" - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==" - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==" - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==" - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==" - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==" - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==" - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==" - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==" - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==" - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==" - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==" - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", - "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==" - }, - "@babel/plugin-transform-classes": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", - "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==" - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==" - }, - "@babel/plugin-transform-destructuring": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", - "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==" - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==" - }, - "@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==" - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==" - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", - "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==" - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==" - }, - "@babel/plugin-transform-parameters": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", - "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==" - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==" - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==" - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.13.tgz", - "integrity": "sha512-MmTZx/bkUrfJhhYAYt3Urjm+h8DQGrPrnKQ94jLo7NLuOU+T89a7IByhKmrb8SKhrIYIQ0FN0CHMbnFRen4qNw==" - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==" - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==" - }, - "@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==" - }, - "@babel/plugin-transform-runtime": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==" - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==" - }, - "@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==" - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==" - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==" - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==" - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==" - }, - "@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==" - }, - "@babel/runtime": { - "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.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==" - }, - "@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==" - }, - "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==" - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==" - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==" - }, - "@meteorjs/babel": { - "version": "7.18.0-beta.6", - "resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.18.0-beta.6.tgz", - "integrity": "sha512-M3BL5ivQQBE4iQ9my7WqXZdkhR61x2H/Z0xshYuv8kppFzuS9/saksET1T7JrTGJnnfONpoxqYkiBGIHSw8+cQ==" - }, - "@meteorjs/reify": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@meteorjs/reify/-/reify-0.23.0.tgz", - "integrity": "sha512-sHQCbZHoM+PxT+pWvkJDsaOpJP+tMQ31Mr2t1T0YcXl18eScb0bQNafe8TugNCc4pngByppfscVX4ppr84MzDw==", - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" - }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" - }, - "babel-helper-evaluate-path": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", - "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==" - }, - "babel-helper-flip-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha512-rSrkRW4YQ2ETCWww9gbsWk4N0x1BOtln349Tk0dlCS90oT68WMLyGR7WvaMp3eAnsVrCqdUtC19lo1avyGPejA==" - }, - "babel-helper-is-nodes-equiv": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha512-ri/nsMFVRqXn7IyT5qW4/hIAGQxuYUFHa3qsxmPtbk6spZQcYlyDogfVpNm2XYOslH/ULS4VEJGUqQX5u7ACQw==" - }, - "babel-helper-is-void-0": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha512-07rBV0xPRM3TM5NVJEOQEkECX3qnHDjaIbFvWYPv+T1ajpUiVLiqTfC+MmiZxY5KOL/Ec08vJdJD9kZiP9UkUg==" - }, - "babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA==" - }, - "babel-helper-remove-or-void": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha512-eYNceYtcGKpifHDir62gHJadVXdg9fAhuZEXiRQnJJ4Yi4oUTpqpNY//1pM4nVyjjDMPYaC2xSf0I+9IqVzwdA==" - }, - "babel-helper-to-multiple-sequence-expressions": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", - "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==" - }, - "babel-plugin-minify-builtins": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", - "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==" - }, - "babel-plugin-minify-constant-folding": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", - "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==" - }, - "babel-plugin-minify-dead-code-elimination": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.2.tgz", - "integrity": "sha512-krq9Lwi0QIzyAlcNBXTL4usqUvevB4BzktdEsb8srcXC1AaYqRJiAQw6vdKdJSaXbz6snBvziGr6ch/aoRCfpA==" - }, - "babel-plugin-minify-flip-comparisons": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha512-8hNwgLVeJzpeLVOVArag2DfTkbKodzOHU7+gAZ8mGBFGPQHK6uXVpg3jh5I/F6gfi5Q5usWU2OKcstn1YbAV7A==" - }, - "babel-plugin-minify-guarded-expressions": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", - "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==" - }, - "babel-plugin-minify-infinity": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha512-X0ictxCk8y+NvIf+bZ1HJPbVZKMlPku3lgYxPmIp62Dp8wdtbMLSekczty3MzvUOlrk5xzWYpBpQprXUjDRyMA==" - }, - "babel-plugin-minify-mangle-names": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz", - "integrity": "sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw==" - }, - "babel-plugin-minify-numeric-literals": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha512-5D54hvs9YVuCknfWywq0eaYDt7qYxlNwCqW9Ipm/kYeS9gYhJd0Rr/Pm2WhHKJ8DC6aIlDdqSBODSthabLSX3A==" - }, - "babel-plugin-minify-replace": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", - "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==" - }, - "babel-plugin-minify-simplify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", - "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==" - }, - "babel-plugin-minify-type-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha512-4ADB0irJ/6BeXWHubjCJmrPbzhxDgjphBMjIjxCc25n4NGJ00NsYqwYt+F/OvE9RXx8KaSW7cJvp+iZX436tnQ==" - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==" - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==" - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==" - }, - "babel-plugin-transform-inline-consecutive-adds": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha512-8D104wbzzI5RlxeVPYeQb9QsUyepiH1rAO5hpPpQ6NPRgQLpIVwkS/Nbx944pm4K8Z+rx7CgjPsFACz/VCBN0Q==" - }, - "babel-plugin-transform-member-expression-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha512-Xq9/Rarpj+bjOZSl1nBbZYETsNEDDJSrb6Plb1sS3/36FukWFLLRysgecva5KZECjUJTrJoQqjJgtWToaflk5Q==" - }, - "babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.5.tgz", - "integrity": "sha512-xj/KrWi6/uP+DrD844h66Qh2cZN++iugEIgH8QcIxhmZZPNP6VpOE9b4gP2FFW39xDAY43kCmYMM6U0QNKN8fw==" - }, - "babel-plugin-transform-minify-booleans": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha512-9pW9ePng6DZpzGPalcrULuhSCcauGAbn8AeU3bE34HcDkGm8Ldt0ysjGkyb64f0K3T5ilV4mriayOVv5fg0ASA==" - }, - "babel-plugin-transform-property-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha512-Pf8JHTjTPxecqVyL6KSwD/hxGpoTZjiEgV7nCx0KFQsJYM0nuuoCajbg09KRmZWeZbJ5NGTySABYv8b/hY1eEA==" - }, - "babel-plugin-transform-regexp-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha512-JjymDyEyRNhAoNFp09y/xGwYVYzT2nWTGrBrWaL6eCg2m+B24qH2jR0AA8V8GzKJTgC8NW6joJmc6nabvWBD/g==" - }, - "babel-plugin-transform-remove-console": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg==" - }, - "babel-plugin-transform-remove-debugger": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha512-Kd+eTBYlXfwoFzisburVwrngsrz4xh9I0ppoJnU/qlLysxVBRgI4Pj+dk3X8F5tDiehp3hhP8oarRMT9v2Z3lw==" - }, - "babel-plugin-transform-remove-undefined": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", - "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==" - }, - "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha512-GLInxhGAQWJ9YIdjwF6dAFlmh4U+kN8pL6Big7nkDzHoZcaDQOtBm28atEhQJq6m9GpAovbiGEShKqXv4BSp0A==" - }, - "babel-plugin-transform-undefined-to-void": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha512-D2UbwxawEY1xVc9svYAUZQM2xarwSNXue2qDIx6CeV2EuMGaes/0su78zlIDIAgE7BvnMw4UpmSo9fDy+znghg==" - }, - "babel-preset-meteor": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.10.0.tgz", - "integrity": "sha512-bcdNfRCQAjTV42cUcmaG5/ltLZZQLpZajUcP+o0Lr+aLTY/XLNkGfASM5383wdXiAkEFl0sDOXeknnLlQtrmdg==" - }, - "babel-preset-minify": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.2.tgz", - "integrity": "sha512-v4GL+kk0TfovbRIKZnC3HPbu2cAGmPAby7BsOmuPdMJfHV+4FVdsGXTH/OOGQRKYdjemBuL1+MsE6mobobhe9w==" - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==" - }, - "caniuse-lite": { - "version": "1.0.30001449", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", - "integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "core-js-compat": { - "version": "3.27.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz", - "integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" - }, - "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==" - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==" - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==" - }, - "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==" - }, - "meteor-babel-helpers": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/meteor-babel-helpers/-/meteor-babel-helpers-0.0.3.tgz", - "integrity": "sha512-PgfmiyT/HiBaxwGHxS4t3Qi0fpmEW3O0WW2VfrgekiMGz3aZPd9/4PRIaMMZsfyjQ1vyEm6dZqTAFZENbuoTxw==" - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "periscopic": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.3.tgz", - "integrity": "sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==" - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==" - }, - "regexpu-core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", - "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==" - }, - "regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" - }, - "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" - } - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "supports-color": { - "version": "5.5.0", - "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": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==" - }, - "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } -} diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 264b30a132..5606e78665 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -1,13 +1,21 @@ var semver = Npm.require("semver"); var JSON5 = Npm.require("json5"); +var SWC = Npm.require("@meteorjs/swc-core"); +const reifyCompile = Npm.require("@meteorjs/reify/lib/compiler").compile; +const reifyAcornParse = Npm.require("@meteorjs/reify/lib/parsers/acorn").parse; +var fs = Npm.require('fs'); +var path = Npm.require('path'); +var vm = Npm.require('vm'); +var crypto = Npm.require('crypto'); + /** * A compiler that can be instantiated with features and used inside * Plugin.registerCompiler * @param {Object} extraFeatures The same object that getDefaultOptions takes */ -BabelCompiler = function BabelCompiler(extraFeatures, modifyBabelConfig) { +BabelCompiler = function BabelCompiler(extraFeatures, modifyConfig) { this.extraFeatures = extraFeatures; - this.modifyBabelConfig = modifyBabelConfig; + this.modifyConfig = modifyConfig; this._babelrcCache = null; this._babelrcWarnings = Object.create(null); this.cacheDirectory = null; @@ -17,16 +25,180 @@ var BCp = BabelCompiler.prototype; var excludedFileExtensionPattern = /\.(es5|min)\.js$/i; var hasOwn = Object.prototype.hasOwnProperty; +function getMeteorConfig() { + return Plugin?.getMeteorConfig() || {}; +} + +// Check if verbose mode is enabled either in the provided config or in extraFeatures +BCp.isVerbose = function(config = getMeteorConfig()) { + if (config?.modern?.transpiler?.verbose) { + return true; + } + if (config?.modern?.verbose) { + return true; + } + if (config?.verbose) { + return true; + } + return !!this.extraFeatures?.verbose; +}; + // There's no way to tell the current Meteor version, but we can infer // whether it's Meteor 1.4.4 or earlier by checking the Node version. var isMeteorPre144 = semver.lt(process.version, "4.8.1"); +var enableClientTLA = process.env.METEOR_ENABLE_CLIENT_TOP_LEVEL_AWAIT === 'true'; + +function compileWithBabel(source, babelOptions, cacheOptions) { + return profile('Babel.compile', function () { + return Babel.compile(source, babelOptions, cacheOptions); + }); +} + +function compileWithSwc(source, swcOptions = {}, { features }) { + return profile('SWC.compile', function () { + // Perform SWC transformation. + const transformed = SWC.transformSync(source, swcOptions); + + let content = transformed.code; + + // Preserve Meteor-specific features: reify modules, nested imports, and top-level await support. + const result = reifyCompile(content, { + parse: reifyAcornParse, + generateLetDeclarations: false, + ast: false, + // Enforce reify options for proper compatibility. + avoidModernSyntax: true, + enforceStrictMode: false, + dynamicImport: true, + ...(features.topLevelAwait && { topLevelAwait: true }), + ...(features.compileForShell && { moduleAlias: 'module' }), + ...((features.modernBrowsers || features.nodeMajorVersion >= 8) && { + avoidModernSyntax: false, + generateLetDeclarations: true, + }), + }); + content = result.code; + + return { + code: content, + map: JSON.parse(transformed.map), + sourceType: 'module', + }; + }); +} + +BCp.initializeMeteorAppConfig = function () { + const meteorConfig = getMeteorConfig(); + if (this.isVerbose()) { + logConfigBlock('Meteor Config', meteorConfig); + } + return meteorConfig; +}; + +let lastModifiedSwcConfig; +let lastModifiedSwcConfigTime; +BCp.initializeMeteorAppSwcrc = function () { + const hasSwcRc = fs.existsSync(`${getMeteorAppDir()}/.swcrc`); + const hasSwcJs = !hasSwcRc && fs.existsSync(`${getMeteorAppDir()}/swc.config.js`); + if (!lastModifiedSwcConfig && !hasSwcRc && !hasSwcJs) { + return; + } + const swcFile = hasSwcJs ? 'swc.config.js' : '.swcrc'; + const filePath = `${getMeteorAppDir()}/${swcFile}`; + const fileStats = fs.statSync(filePath); + const fileModTime = fileStats?.mtime?.getTime(); + + let currentLastModifiedConfigTime; + if (hasSwcJs) { + // For dynamic JS files, first get the resolved configuration + const resolvedConfig = lastModifiedSwcConfigTime?.includes(`${fileModTime}`) + ? lastModifiedSwcConfig || getMeteorAppSwcrc(swcFile) + : getMeteorAppSwcrc(swcFile); + // Calculate a hash of the resolved configuration to detect changes + const contentHash = crypto + .createHash('sha256') + .update(JSON.stringify(resolvedConfig)) + .digest('hex'); + // Combine file modification time and content hash to create a unique identifier + currentLastModifiedConfigTime = `${fileModTime}-${contentHash}`; + // Store the resolved configuration + lastModifiedSwcConfig = resolvedConfig; + } else { + // For static JSON files, just use the file modification time + currentLastModifiedConfigTime = fileModTime; + } + + if (currentLastModifiedConfigTime !== lastModifiedSwcConfigTime) { + lastModifiedSwcConfigTime = currentLastModifiedConfigTime; + lastModifiedSwcConfig = getMeteorAppSwcrc(swcFile); + + if (this.isVerbose()) { + logConfigBlock('SWC Custom Config', lastModifiedSwcConfig); + } + + this._swcIncompatible = {}; + } + return lastModifiedSwcConfig; +}; + +let lastModifiedSwcLegacyConfig; +BCp.initializeMeteorAppLegacyConfig = function () { + const swcLegacyConfig = convertBabelTargetsForSwc(Babel.getMinimumModernBrowserVersions()); + if (this.isVerbose() && !lastModifiedSwcLegacyConfig) { + logConfigBlock('SWC Legacy Config', swcLegacyConfig); + } + lastModifiedSwcLegacyConfig = swcLegacyConfig; + return lastModifiedSwcConfig; +}; + +// Helper function to check if @swc/helpers is available +function hasSwcHelpers() { + return fs.existsSync(`${getMeteorAppDir()}/node_modules/@swc/helpers`); +} + +// Helper function to log friendly messages about SWC helpers +function logSwcHelpersStatus(isAvailable) { + const label = color('[SWC Helpers]', 36); + + if (isAvailable) { + // Green message for when helpers are available + console.log(`${label} ${color('βœ“ @swc/helpers is available in your project!', 32)}`); + console.log(` ${color('Benefits:', 32)}`); + console.log(` ${color('β€’ Smaller bundle size: External helpers reduce code duplication', 32)}`); + console.log(` ${color('β€’ Faster loads: less code to parse on first download', 32)}`); + console.log(` ${color('β€’ Optional caching: separate vendor chunk can be cached by browsers', 32)}`); + } else { + // Yellow message for when helpers are not available + console.log(`${label} ${color('⚠ @swc/helpers is not available in your project', 33)}`); + console.log(` ${color('Suggestion:', 33)}`); + console.log(` ${color('β€’ Add @swc/helpers to your project:', 33)}`); + console.log(` ${color('meteor npm install --save @swc/helpers', 33)}`); + console.log(` ${color('β€’ This will reduce bundle size and improve performance', 33)}`); + } + console.log(); +} + +let hasSwcHelpersAvailable = false; +BCp.initializeMeteorAppSwcHelpersAvailable = function () { + hasSwcHelpersAvailable = hasSwcHelpers(); + if (this.isVerbose()) { + logSwcHelpersStatus(hasSwcHelpersAvailable); + } + return hasSwcHelpersAvailable; +}; + BCp.processFilesForTarget = function (inputFiles) { var compiler = this; // Reset this cache for each batch processed. this._babelrcCache = null; + this.initializeMeteorAppConfig(); + this.initializeMeteorAppSwcrc(); + this.initializeMeteorAppLegacyConfig(); + this.initializeMeteorAppSwcHelpersAvailable(); + inputFiles.forEach(function (inputFile) { if (inputFile.supportsLazyCompilation) { inputFile.addJavaScript({ @@ -48,6 +220,8 @@ BCp.processFilesForTarget = function (inputFiles) { // null to indicate there was an error, and nothing should be added. BCp.processOneFileForTarget = function (inputFile, source) { this._babelrcCache = this._babelrcCache || Object.create(null); + this._swcCache = this._swcCache || Object.create(null); + this._swcIncompatible = this._swcIncompatible || Object.create(null); if (typeof source !== "string") { // Other compiler plugins can call processOneFileForTarget with a @@ -89,8 +263,15 @@ BCp.processOneFileForTarget = function (inputFile, source) { features.nodeMajorVersion = parseInt(process.versions.node, 10); } else if (arch === "web.browser") { features.modernBrowsers = true; + } else if (arch === "web.cordova") { + features.modernBrowsers = ! getMeteorConfig()?.cordova?.disableModern; } + features.topLevelAwait = inputFile.supportsTopLevelAwait && + (arch.startsWith('os.') || enableClientTLA); + + features.useNativeAsyncAwait = Meteor.isFibersDisabled; + if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility // in older browsers (e.g. wrapping named function expressions, per @@ -113,32 +294,202 @@ BCp.processOneFileForTarget = function (inputFile, source) { }, }; - this.inferTypeScriptConfig( - features, inputFile, cacheOptions.cacheDeps); - - var babelOptions = Babel.getDefaultOptions(features); - babelOptions.caller = { name: "meteor", arch }; - - this.inferExtraBabelOptions( - inputFile, - babelOptions, - cacheOptions.cacheDeps - ); - - babelOptions.sourceMaps = true; - babelOptions.filename = - babelOptions.sourceFileName = packageName - ? "packages/" + packageName + "/" + inputFilePath + const filename = packageName + ? `packages/${packageName}/${inputFilePath}` : inputFilePath; - if (this.modifyBabelConfig) { - this.modifyBabelConfig(babelOptions, inputFile); - } + const setupBabelOptions = () => { + this.inferTypeScriptConfig(features, inputFile, cacheOptions.cacheDeps); + var babelOptions = Babel.getDefaultOptions(features); + babelOptions.caller = { name: "meteor", arch }; + + babelOptions.sourceMaps = true; + babelOptions.filename = babelOptions.sourceFileName = filename; + + this.inferExtraBabelOptions(inputFile, babelOptions, cacheOptions.cacheDeps); + + if (this.modifyConfig) { + this.modifyConfig(babelOptions, inputFile); + } + + return babelOptions; + }; + + const setupSWCOptions = () => { + const isTypescriptSyntax = inputFilePath.endsWith('.ts') || inputFilePath.endsWith('.tsx'); + const hasTSXSupport = inputFilePath.endsWith('.tsx'); + const hasJSXSupport = inputFilePath.endsWith('.jsx'); + const isLegacyWebArch = arch.includes('legacy'); + + var swcOptions = { + jsc: { + ...(!isLegacyWebArch && { target: 'es2015' }), + parser: { + syntax: isTypescriptSyntax ? 'typescript' : 'ecmascript', + jsx: hasJSXSupport, + tsx: hasTSXSupport, + }, + ...(hasSwcHelpersAvailable && + (packageName == null || + !['modules-runtime'].includes(packageName)) && { + externalHelpers: true, + }), + }, + module: { type: 'es6' }, + minify: false, + sourceMaps: true, + filename, + sourceFileName: filename, + ...(isLegacyWebArch && { + env: { targets: lastModifiedSwcLegacyConfig || {} }, + }), + }; + + // Merge with app-level SWC config + if (lastModifiedSwcConfig) { + swcOptions = deepMerge(swcOptions, lastModifiedSwcConfig, [ + 'env.targets', + 'module.type', + ]); + } + + this.inferExtraSWCOptions(inputFile, swcOptions, cacheOptions.cacheDeps); + + if (!!this.extraFeatures?.swc && this.modifyConfig) { + this.modifyConfig(swcOptions, inputFile); + } + + // Resolve custom baseUrl to an absolute path pointing to the project root + if (swcOptions.jsc && swcOptions.jsc.baseUrl) { + swcOptions.jsc.baseUrl = path.resolve(process.cwd(), swcOptions.jsc.baseUrl); + } + + return swcOptions; + }; + + var babelOptions = { filename }; try { - var result = profile('Babel.compile', function () { - return Babel.compile(source, babelOptions, cacheOptions); - }); + var result = (() => { + const isNodeModulesCode = packageName == null && inputFilePath.includes("node_modules/"); + const isAppCode = packageName == null && !isNodeModulesCode; + const isPackageCode = packageName != null; + const isLegacyWebArch = arch.includes('legacy'); + + const transpConfig = getMeteorConfig()?.modern?.transpiler; + const hasModernTranspiler = transpConfig != null && transpConfig !== false; + const shouldSkipSwc = + !hasModernTranspiler || + (isAppCode && transpConfig?.excludeApp === true) || + (isNodeModulesCode && transpConfig?.excludeNodeModules === true) || + (isPackageCode && transpConfig?.excludePackages === true) || + (isLegacyWebArch && transpConfig?.excludeLegacy === true) || + (isAppCode && + Array.isArray(transpConfig?.excludeApp) && + isExcludedConfig(inputFilePath, transpConfig?.excludeApp || [])) || + (isNodeModulesCode && + Array.isArray(transpConfig?.excludeNodeModules) && + (isExcludedConfig(inputFilePath, transpConfig?.excludeNodeModules || []) || + isExcludedConfig( + inputFilePath.replace('node_modules/', ''), + transpConfig?.excludeNodeModules || [], + true, + ))) || + (isPackageCode && + Array.isArray(transpConfig?.excludePackages) && + (isExcludedConfig(packageName, transpConfig?.excludePackages || []) || + isExcludedConfig( + `${packageName}/${inputFilePath}`, + transpConfig?.excludePackages || [], + ))); + + const cacheKey = [ + toBeAdded.hash, + lastModifiedSwcConfigTime, + isLegacyWebArch ? 'legacy' : '', + hasSwcHelpersAvailable, + ] + .filter(Boolean) + .join('-'); + // Determine if SWC should be used based on package and file criteria. + const shouldUseSwc = + (!shouldSkipSwc || this.extraFeatures?.swc) && + !this._swcIncompatible[cacheKey]; + let compilation; + try { + let usedSwc = false; + if (shouldUseSwc) { + // Create a cache key based on the source hash and the compiler used + // Check cache + compilation = this.readFromSwcCache({ cacheKey }); + // Return cached result if found. + if (compilation) { + if (this.isVerbose()) { + logTranspilation({ + usedSwc: true, + inputFilePath, + packageName, + isNodeModulesCode, + cacheHit: true, + arch, + }); + } + return compilation; + } + + const swcOptions = setupSWCOptions(); + compilation = compileWithSwc( + source, + swcOptions, + { features }, + ); + // Save result in cache + this.writeToSwcCache({ cacheKey, compilation }); + usedSwc = true; + } else { + // Set up Babel options only when compiling with Babel + babelOptions = setupBabelOptions(); + + compilation = compileWithBabel(source, babelOptions, cacheOptions); + usedSwc = false; + } + + if (this.isVerbose()) { + logTranspilation({ + usedSwc, + inputFilePath, + packageName, + isNodeModulesCode, + cacheHit: false, + arch, + }); + } + } catch (e) { + this._swcIncompatible[cacheKey] = true; + // If SWC fails, fall back to Babel + + babelOptions = setupBabelOptions(); + compilation = compileWithBabel(source, babelOptions, cacheOptions); + if (this.isVerbose()) { + logTranspilation({ + usedSwc: false, + inputFilePath, + packageName, + isNodeModulesCode, + cacheHit: false, + arch, + errorMessage: e?.message, + ...(e?.message?.includes( + 'cannot be used outside of module code', + ) && { + tip: 'Remove nested imports or replace them with require to support SWC and improve speed.', + }), + }); + } + } + + return compilation; + })(); } catch (e) { if (e.loc) { // Error is from @babel/parser. @@ -248,6 +599,15 @@ BCp.inferExtraBabelOptions = function (inputFile, babelOptions, cacheDeps) { ); }; +BCp.inferExtraSWCOptions = function (inputFile, swcOptions, cacheDeps) { + if (! inputFile.require || + ! inputFile.findControlFile || + ! inputFile.readAndWatchFile) { + return false; + } + return this._inferFromSwcRc(inputFile, swcOptions, cacheDeps); +}; + BCp._inferFromBabelRc = function (inputFile, babelOptions, cacheDeps) { var babelrcPath = inputFile.findControlFile(".babelrc"); if (babelrcPath) { @@ -300,6 +660,65 @@ BCp._inferFromPackageJson = function (inputFile, babelOptions, cacheDeps) { } }; +BCp._inferFromSwcRc = function (inputFile, swcOptions, cacheDeps) { + var swcrcPath = inputFile.findControlFile(".swcrc"); + if (swcrcPath) { + if (! hasOwn.call(this._babelrcCache, swcrcPath)) { + try { + this._babelrcCache[swcrcPath] = { + controlFilePath: swcrcPath, + controlFileData: JSON.parse( + inputFile.readAndWatchFile(swcrcPath)), + deps: Object.create(null), + }; + } catch (e) { + if (e instanceof SyntaxError) { + e.message = ".swcrc is not a valid JSON file: " + e.message; + } + throw e; + } + } + + const cacheEntry = this._babelrcCache[swcrcPath]; + + if (this._inferHelperForSwc(inputFile, cacheEntry)) { + deepMerge(swcOptions, cacheEntry.controlFileData); + Object.assign(cacheDeps, cacheEntry.deps); + return true; + } + } +}; + +BCp._inferHelperForSwc = function (inputFile, cacheEntry) { + if (! cacheEntry.controlFileData) { + return false; + } + + if (hasOwn.call(cacheEntry, "finalInferHelperForSwcResult")) { + // We've already run _inferHelperForSwc and populated + // cacheEntry.controlFileData, so we can return early here. + return cacheEntry.finalInferHelperForSwcResult; + } + + // First, ensure that the current file path is not excluded. + if (cacheEntry.controlFileData.exclude) { + const exclude = cacheEntry.controlFileData.exclude; + const path = inputFile.getPathInPackage(); + + if (exclude instanceof Array) { + for (let i = 0; i < exclude.length; ++i) { + if (path.match(exclude[i])) { + return cacheEntry.finalInferHelperForSwcResult = false; + } + } + } else if (path.match(exclude)) { + return cacheEntry.finalInferHelperForSwcResult = false; + } + } + + return cacheEntry.finalInferHelperForSwcResult = true; +}; + BCp._inferHelper = function (inputFile, cacheEntry) { if (! cacheEntry.controlFileData) { return false; @@ -556,3 +975,245 @@ function packageNameFromTopLevelModuleId(id) { } return parts[0]; } + +const SwcCacheContext = '.swc-cache'; + +BCp.readFromSwcCache = function({ cacheKey }) { + // Check in-memory cache. + let compilation = this._swcCache[cacheKey]; + // If not found, try file system cache if enabled. + if (!compilation && this.cacheDirectory) { + const cacheFilePath = path.join(this.cacheDirectory, SwcCacheContext, `${cacheKey}.json`); + if (fs.existsSync(cacheFilePath)) { + try { + compilation = JSON.parse(fs.readFileSync(cacheFilePath, 'utf8')); + // Save back to in-memory cache. + this._swcCache[cacheKey] = compilation; + } catch (err) { + // Ignore any errors reading/parsing the cache. + } + } + } + return compilation; +}; + +BCp.writeToSwcCache = function({ cacheKey, compilation }) { + // Save to in-memory cache. + this._swcCache[cacheKey] = compilation; + // If file system caching is enabled, write asynchronously. + if (this.cacheDirectory) { + const cacheFilePath = path.join(this.cacheDirectory, SwcCacheContext, `${cacheKey}.json`); + try { + const writeFileCache = async () => { + await fs.promises.mkdir(path.dirname(cacheFilePath), { recursive: true }); + await fs.promises.writeFile(cacheFilePath, JSON.stringify(compilation), 'utf8'); + }; + // Invoke without blocking the main flow. + writeFileCache(); + } catch (err) { + // If writing fails, ignore the error. + } + } +}; + +function getMeteorAppDir() { + return process.cwd(); +} + +function getMeteorAppPackageJson() { + return JSON.parse( + fs.readFileSync(`${getMeteorAppDir()}/package.json`, 'utf-8'), + ); +} + +function getMeteorAppSwcrc(file = '.swcrc') { + try { + const filePath = `${getMeteorAppDir()}/${file}`; + if (file.endsWith('.js')) { + let content = fs.readFileSync(filePath, 'utf-8'); + // Check if the content uses ES module syntax (export default) + if (content.includes('export default')) { + // Transform ES module syntax to CommonJS + content = content.replace(/export\s+default\s+/, 'module.exports = '); + } + const script = new vm.Script(` + (function() { + const module = {}; + module.exports = {}; + (function(exports, module) { + ${content} + })(module.exports, module); + return module.exports; + })() + `); + const context = vm.createContext({ process }); + return script.runInContext(context); + } else { + // For .swcrc and other JSON files, parse as JSON + return JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + } catch (e) { + console.error(`Error parsing ${file} file`, e); + } +} + +const _regexCache = new Map(); + +function isRegexLike(str) { + return /[.*+?^${}()|[\]\\]/.test(str); +} + +function isExcludedConfig(name, excludeList = [], startsWith) { + if (!name || !excludeList?.length) return false; + return excludeList.some(rule => { + if (name === rule) return true; + if (startsWith && name.startsWith(rule)) return true; + if (isRegexLike(rule)) { + let regex = _regexCache.get(rule); + if (!regex) { + try { + regex = new RegExp(rule); + _regexCache.set(rule, regex); + } catch (err) { + console.warn(`Invalid regex in exclude list: "${rule}"`); + return false; + } + } + return regex.test(name); + } + + return false; + }); +} + +const disableTextColors = Boolean(JSON.parse(process.env.METEOR_DISABLE_COLORS || "false")); + +function color(text, code) { + return disableTextColors ? text : `\x1b[${code}m${text}\x1b[0m`; +} + +function logTranspilation({ + packageName, + inputFilePath, + usedSwc, + cacheHit, + isNodeModulesCode, + arch, + errorMessage = '', + tip = '', +}) { + const transpiler = usedSwc ? 'SWC' : 'Babel'; + const transpilerColor = usedSwc ? 32 : 33; + const label = color('[Transpiler]', 36); + const transpilerPart = `${label} Used ${color( + transpiler, + transpilerColor, + )} for`; + const filePathPadded = `${ + packageName ? `${packageName}/` : '' + }${inputFilePath}`.padEnd(50); + let rawOrigin = ''; + if (packageName) { + rawOrigin = `(package)`; + } else { + rawOrigin = isNodeModulesCode ? '(node_modules)' : '(app)'; + } + const originPaddedRaw = rawOrigin.padEnd(35); + const originPaddedColored = packageName + ? originPaddedRaw + : isNodeModulesCode + ? color(originPaddedRaw, 90) + : color(originPaddedRaw, 35); + const cacheStatus = errorMessage + ? color('⚠️ Fallback', 33) + : usedSwc + ? cacheHit + ? color('🟒 Cache hit', 32) + : color('πŸ”΄ Cache miss', 31) + : ''; + const archPart = arch ? color(` (${arch})`, 90) : ''; + console.log( + `${transpilerPart} ${filePathPadded}${originPaddedColored}${cacheStatus}${archPart}`, + ); + if (errorMessage) { + console.log(); + console.log(` ↳ ${color('Error:', 31)} ${errorMessage}`); + if (tip) { + console.log(); + console.log(` ${color('πŸ’‘ Tip:', 33)} ${tip}`); + } + console.log(); + } +} + +function logConfigBlock(description, configObject) { + const label = color('[Config]', 36); + const descriptionColor = color(description, 90); + + console.log(`${label} ${descriptionColor}`); + + const configLines = JSON.stringify(configObject, null, 2) + .replace(/"([^"]+)":/g, '$1:') + .split('\n') + .map(line => ' ' + line); + + configLines.forEach(line => console.log(line)); + console.log(); +} + +function deepMerge(target, source, preservePaths = [], inPath = '') { + for (const key in source) { + const fullPath = inPath ? `${inPath}.${key}` : key; + + // Skip preserved paths + if (preservePaths.includes(fullPath)) continue; + + if ( + typeof source[key] === 'object' && + source[key] !== null && + !Array.isArray(source[key]) + ) { + target[key] = deepMerge( + target[key] || {}, + source[key], + preservePaths, + fullPath, + ); + } else { + target[key] = source[key]; + } + } + return target; +} + +function convertBabelTargetsForSwc(babelTargets) { + const allowedEnvs = new Set([ + 'chrome', 'opera', 'edge', 'firefox', 'safari', + 'ie', 'ios', 'android', 'node', 'electron' + ]); + + const filteredTargets = {}; + for (const [env, version] of Object.entries(babelTargets)) { + if (allowedEnvs.has(env)) { + // Convert an array version (e.g., [10, 3]) into "10.3", otherwise convert to string. + filteredTargets[env] = Array.isArray(version) ? version.join('.') : version.toString(); + } + } + + return filteredTargets; +} + +/** + * A compiler that extends BabelCompiler but always uses SWC + * @param {Object} extraFeatures Additional features to pass to BabelCompiler + * @param {Function} modifyConfig Function to modify the configuration + */ +SwcCompiler = function SwcCompiler(extraFeatures, modifyConfig) { + extraFeatures = extraFeatures || {}; + extraFeatures.swc = true; + BabelCompiler.call(this, extraFeatures, modifyConfig); +}; + +// Inherit from BabelCompiler +SwcCompiler.prototype = Object.create(BabelCompiler.prototype); +SwcCompiler.prototype.constructor = SwcCompiler; diff --git a/packages/babel-compiler/babel.js b/packages/babel-compiler/babel.js index d7e0c287a6..03a8543e2a 100644 --- a/packages/babel-compiler/babel.js +++ b/packages/babel-compiler/babel.js @@ -47,5 +47,16 @@ Babel = { getMinimumModernBrowserVersions: function () { return Npm.require("@meteorjs/babel/modern-versions.js").get(); + }, + + compileForShell(command, cacheOptions) { + const babelOptions = Babel.getDefaultOptions({ + nodeMajorVersion: parseInt(process.versions.node, 10), + compileForShell: true + }); + delete babelOptions.sourceMap; + delete babelOptions.sourceMaps; + babelOptions.ast = false; + return Babel.compile(command, babelOptions, cacheOptions).code; } }; diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index a7ab425cae..2e69cdc028 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -1,12 +1,14 @@ Package.describe({ name: "babel-compiler", summary: "Parser/transpiler for ECMAScript 2015+ syntax", - version: '7.10.4', + version: '7.12.2', }); Npm.depends({ - '@meteorjs/babel': '7.18.0-beta.6', - 'json5': '2.1.1' + '@meteorjs/babel': '7.20.1', + 'json5': '2.2.3', + 'semver': '7.6.3', + "@meteorjs/swc-core": "1.12.14", }); Package.onUse(function (api) { @@ -21,4 +23,5 @@ Package.onUse(function (api) { api.export('Babel', 'server'); api.export('BabelCompiler', 'server'); + api.export('SwcCompiler', 'server'); }); diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index cf9d140903..522ccdb598 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '1.5.1', + version: '1.5.2', documentation: 'README.md' }); diff --git a/packages/base64/package.js b/packages/base64/package.js index 547992b2a4..1a1009051f 100644 --- a/packages/base64/package.js +++ b/packages/base64/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Base64 encoding and decoding", - version: '1.0.12', + version: '1.0.13', }); Package.onUse(api => { diff --git a/packages/binary-heap/package.js b/packages/binary-heap/package.js index fba196e706..c532928f9d 100644 --- a/packages/binary-heap/package.js +++ b/packages/binary-heap/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Binary Heap datastructure implementation", - version: '1.0.11' + version: '1.0.12', }); Package.onUse(api => { diff --git a/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json b/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index 15ed96ef52..0000000000 --- a/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "lockfileVersion": 1, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } - } -} diff --git a/packages/boilerplate-generator-tests/package.js b/packages/boilerplate-generator-tests/package.js index 833fb0c696..8c95f5f034 100644 --- a/packages/boilerplate-generator-tests/package.js +++ b/packages/boilerplate-generator-tests/package.js @@ -2,7 +2,7 @@ Package.describe({ // These tests are in a separate package so that we can Npm.depend on // parse5, a html parsing library. summary: "Tests for the boilerplate-generator package", - version: '1.5.1', + version: '1.5.3', documentation: null }); @@ -13,7 +13,6 @@ Npm.depends({ Package.onTest(function (api) { api.use('ecmascript'); api.use([ - 'underscore', 'tinytest', 'boilerplate-generator' ], 'server'); diff --git a/packages/boilerplate-generator-tests/web.browser-tests.js b/packages/boilerplate-generator-tests/web.browser-tests.js index 915e2f6ebf..48c0d06fd8 100644 --- a/packages/boilerplate-generator-tests/web.browser-tests.js +++ b/packages/boilerplate-generator-tests/web.browser-tests.js @@ -1,6 +1,5 @@ import { parse, serialize } from 'parse5'; import { generateHTMLForArch } from './test-lib'; -import { _ } from 'meteor/underscore'; Tinytest.addAsync( "boilerplate-generator-tests - web.browser - basic output", @@ -66,10 +65,6 @@ Tinytest.addAsync( async function (test) { const newHtml = await generateHTMLForArch("web.browser", false); - _.templateSettings = { - interpolate: /\{\{(.+?)\}\}/g - }; - test.matches(newHtml, /foo="foobar"/); test.matches(newHtml, /]*href="[^<>]*bootstrap[^<>]*">/); test.matches(newHtml, /]*src="[^<>]*templating[^<>]*">/); diff --git a/packages/boilerplate-generator-tests/web.cordova-tests.js b/packages/boilerplate-generator-tests/web.cordova-tests.js index 04eb249ac5..ffe954105e 100644 --- a/packages/boilerplate-generator-tests/web.cordova-tests.js +++ b/packages/boilerplate-generator-tests/web.cordova-tests.js @@ -1,6 +1,5 @@ import { parse, serialize } from 'parse5'; import { generateHTMLForArch } from './test-lib'; -import { _ } from 'meteor/underscore'; Tinytest.addAsync( "boilerplate-generator-tests - web.cordova - basic output", @@ -60,9 +59,7 @@ Tinytest.addAsync( async function (test) { const newHtml = await generateHTMLForArch('web.cordova', false); - _.templateSettings = { - interpolate: /\{\{(.+?)\}\}/g - }; + test.matches(newHtml, /]*href="[^<>]*bootstrap[^<>]*">/); test.matches(newHtml, /]*src="[^<>]*templating[^<>]*">/); test.matches(newHtml, /'; Tinytest.add("webapp - npm modules", function (test) { // Make sure the version number looks like a version number. - test.matches(WebAppInternals.NpmModules.connect.version, /^3\.(\d+)\.(\d+)/); - test.equal(typeof(WebAppInternals.NpmModules.connect.module), 'function'); - test.equal(typeof(WebAppInternals.NpmModules.connect.module.basicAuth), - 'function'); + test.matches(WebAppInternals.NpmModules.express.version, /^5\.(\d+)\.(\d+)/); + test.equal(typeof(WebAppInternals.NpmModules.express.module), 'function'); +}); + +Tinytest.addAsync( + "webapp - addRuntimeConfigHook usage", + async function (test, done) { + WebApp.addRuntimeConfigHook(async (config) => { + const nextConfig = { + ...WebApp.decodeRuntimeConfig(config.encodedCurrentConfig), + customKey: 'customValue', + }; + return WebApp.encodeRuntimeConfig(nextConfig); + }); + + const req = new http.IncomingMessage(); + req.url = 'http://example.com'; + req.browser = { name: 'headless' }; + const boilerplate = await WebAppInternals.getBoilerplate(req, 'web.browser'); + const html = await streamToString(boilerplate.stream); + test.isTrue(/__meteor_runtime_config__ = (.*customKey[^"].*customValue.*)/.test(html)); + } +); + +Tinytest.addAsync("webapp - parse url queries", async function (test) { + WebApp.handlers.get("/queries", async (req, res) => { + res.json(req.query); + }); + + const queriesTestCases = [ + 'planet=Mars', + 'galaxy=Andromeda&star=Betelgeuse', + 'spacecraft=Voyager%202', + 'meteor=Perseid&meteor=Leonid', + 'astronaut[name]=Neil&astronaut[mission]=Apollo%2011', + 'galaxy[name]=Milky%20Way&galaxy[diameter]=105700', + 'constellation[name]=Orion&constellation[stars][]=Betelgeuse&constellation[stars][]=Rigel', + 'galaxy[name]=Andromeda&galaxy[age]=10&meteors[]=Perseid&meteors[]=Geminid', + 'astronaut[name]=Buzz&astronaut[missions][first]=Apollo%2011&astronaut[missions][second]=Apollo%2022', + 'spacecraft[]=Voyager&spacecraft[]=Pioneer&spacecraft[0][type]=orbiter', + 'comet=Halley&status=active%20comet', + 'planet=&galaxy=' + ]; + const queryResults = [ + { planet: 'Mars' }, + { galaxy: 'Andromeda', star: 'Betelgeuse' }, + { spacecraft: 'Voyager 2' }, + { meteor: ['Perseid', 'Leonid'] }, + { astronaut: { name: 'Neil', mission: 'Apollo 11' } }, + { galaxy: { name: 'Milky Way', diameter: '105700' } }, + { constellation: { name: 'Orion', stars: ['Betelgeuse', 'Rigel'] } }, + { + galaxy: { name: 'Andromeda', age: '10' }, + meteors: ['Perseid', 'Geminid'] + }, + { + astronaut: { + name: 'Buzz', + missions: { first: 'Apollo 11', second: 'Apollo 22' } + } + }, + { spacecraft: ['Voyager', 'Pioneer', { type: 'orbiter' }] }, + { comet: 'Halley', status: 'active comet' }, + { planet: '', galaxy: '' } + ]; + let i = 0; + for await (const queriesTestCase of queriesTestCases) { + const resp = await asyncGet(`${Meteor.absoluteUrl()}/queries?${queriesTestCase}`); + const queryParsed = JSON.parse(resp.content); + test.equal(queryParsed, queryResults[i]); + i++; + } }); diff --git a/packages/weibo-config-ui/package.js b/packages/weibo-config-ui/package.js index 3e66efe90f..0ba53ff0a8 100644 --- a/packages/weibo-config-ui/package.js +++ b/packages/weibo-config-ui/package.js @@ -1,11 +1,11 @@ Package.describe({ summary: "Blaze configuration templates for Weibo OAuth.", - version: "1.0.2", + version: '1.0.3', }); Package.onUse(api => { api.use('ecmascript', 'client'); - api.use('templating@1.4.0', 'client'); + api.use('templating@1.4.2', 'client'); api.addFiles('weibo_login_button.css', 'client'); api.addFiles( diff --git a/packages/weibo-oauth/package.js b/packages/weibo-oauth/package.js index e2de8dd3ba..7fda8c1e8e 100644 --- a/packages/weibo-oauth/package.js +++ b/packages/weibo-oauth/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Weibo OAuth flow", - version: "1.3.2", + version: '1.3.3', }); Package.onUse(api => { @@ -14,3 +14,9 @@ Package.onUse(api => { api.export('Weibo'); }); + +Package.onTest(function(api) { + api.use('weibo-oauth'); + api.use(['tinytest', 'ecmascript', 'test-helpers', 'oauth', 'oauth2', 'service-configuration']); + api.addFiles('weibo-oauth_tests.js'); +}); diff --git a/packages/weibo-oauth/weibo-oauth_tests.js b/packages/weibo-oauth/weibo-oauth_tests.js new file mode 100644 index 0000000000..260b483cd2 --- /dev/null +++ b/packages/weibo-oauth/weibo-oauth_tests.js @@ -0,0 +1,34 @@ +Tinytest.addAsync( + 'weibo-oauth - run service oauth with mocked flow as expected', + async function (test) { + const oauthMock = mockBehaviours(OAuth, { + _fetch: () => Promise.resolve({ json: () => ({ access_token: 'testToken', uid: '12345' })}), + }); + + const service = 'weibo'; + const serviceMockConfig = { service }; + const mockConfig = { clientId: "test", secret: "test", loginStyle: "popup" }; + if (Meteor.isServer) { + await ServiceConfiguration.configurations.upsertAsync(serviceMockConfig, { $set: mockConfig }); + const result = await OAuthTest.registeredServices[service].handleOauthRequest({}); + test.isTrue(!!result?.serviceData, 'should return mocked result'); + test.equal( + oauthMock.mockedRuns.map(({ name }) => name), + ['openSecret','_redirectUri','_fetch','_fetch'], + 'should run mock oauth behaviors', + ); + } else if (Meteor.isClient) { + ServiceConfiguration.configurations.insert({ ...serviceMockConfig, ...mockConfig }); + Weibo.requestCredential({}); + test.equal( + oauthMock.mockedRuns.map(({ name }) => name), + ['_loginStyle', '_redirectUri', '_stateParam', 'launchLogin'], + 'should run mock oauth behaviors', + ); + } + + oauthMock.stop(); + + return Promise.resolve(); + }, +); diff --git a/packages/weibo-oauth/weibo_server.js b/packages/weibo-oauth/weibo_server.js index 24d56438fd..44ef8558db 100644 --- a/packages/weibo-oauth/weibo_server.js +++ b/packages/weibo-oauth/weibo_server.js @@ -32,7 +32,7 @@ OAuth.registerService('weibo', 2, null, async query => { // - access_token // - expires_in: lifetime of this token in seconds (5 years(!) right now) const getTokenResponse = async (query) => { - const config = ServiceConfiguration.configurations.findOne({ + const config = await ServiceConfiguration.configurations.findOneAsync({ service: 'weibo', }); if (!config) throw new ServiceConfiguration.ConfigError(); diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index 3a15538a8e..0000000000 --- a/prettier.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@quave/eslint-config-quave/prettier.config'); diff --git a/scripts/admin/bump-all-version-numbers.js b/scripts/admin/bump-all-version-numbers.js index 915c999296..a4e45f0d12 100644 --- a/scripts/admin/bump-all-version-numbers.js +++ b/scripts/admin/bump-all-version-numbers.js @@ -1,21 +1,20 @@ // run as node scripts/admin/bump-all-version-numbers.js -var fs = require("fs"); -var _ = require("../../packages/underscore/underscore.js")._; +const fs = require("fs"); -var packageNames = _.rest(process.argv, 2); +const packageNames = process.argv.slice(2); -_.each(packageNames, function (name) { +packageNames.forEach(name => { // name = "packages/" + name + "/package.js"; - var content = fs.readFileSync(name, {encoding: "utf-8"}); + const content = fs.readFileSync(name, {encoding: "utf-8"}); - var match = content.match(/\d+\.\d+\.\d+-winr.\d+/); + const match = content.match(/\d+\.\d+\.\d+-winr.\d+/); if (match) { - var versionNumber = match[0]; - var s = versionNumber.split("."); - s[3] = (parseInt(s[3], 10) + 1); - var incremented = s.join("."); + const versionNumber = match[0]; + const s = versionNumber.split("."); + s[3] = (parseInt(s[3], 10) + 1).toString(); + const incremented = s.join("."); content = content.replace(versionNumber, incremented); console.log(match[0], match[1], incremented); diff --git a/scripts/admin/check-legacy-syntax/check-syntax.js b/scripts/admin/check-legacy-syntax/check-syntax.js index 6630a535a7..58b1ce1284 100644 --- a/scripts/admin/check-legacy-syntax/check-syntax.js +++ b/scripts/admin/check-legacy-syntax/check-syntax.js @@ -5,158 +5,189 @@ // and when used in build plugins can run in old Meteor versions const clientEcmascriptVersion = 5; -// Node 8 (Meteor 1.6+) fully supports 2016 -const serverEcmascriptVersion = '2016'; +// Node 8 (Meteor 1.6+) fully supports 2016, and supports most of 2017 +const serverEcmascriptVersion = "2017"; + +// Latest version - (has TLA) +const latestEcmascriptVersion = "2022"; // By default, all files in these packages are expected to use es5 syntax // Files only used on the server can be listed, which allows them to use // some newer syntax (limited by the oldest Meteor version we want to support // when the package is used in a build plugin) +// There is the fully ignoredFiles option, which allows files to use any +// syntax, but this should be avoided. Add a comment to the file explaining +// why it needs to use newer syntax. + +// Note that if a package is able to use TLA (has a dependency on ecmascript), +// it can be removed from the list of packages this script runs on. +// This script is only needed for packages that can't use TLA/ecmascript. const packages = { - 'meteor': { + meteor: { serverFiles: [ - 'dynamics_nodejs.js', - 'asl-helpers.js', - 'server_environment.js' + "server_environment.js", + "dynamics_nodejs.js", + "emitter-promise.js" + ], + + // TODO: Fibers + // Ignored server files that has a features > 2016 + ignoredFiles: [ + "async_helpers.js", + "asynchronous_queue.js", ] }, - 'accounts-ui': {}, - 'audit-argument-checks': {}, - 'autopublish': {}, - 'babel-compiler': { - serverFiles: ['babel.js', 'babel-compiler.js'] + "accounts-ui": {}, + "audit-argument-checks": {}, + autopublish: {}, + "babel-compiler": { + serverFiles: ["babel.js", "babel-compiler.js"], + ignoredFiles: ["babel-compiler.js"], }, - 'babel-runtime': {}, - 'browser-policy': {}, - 'browser-policy-common': {}, - 'browser-policy-content': {}, - 'browser-policy-framing': {}, + "babel-runtime": {}, + "browser-policy": {}, + "browser-policy-common": {}, + // "browser-policy-content": { + // // TODO: Fibers + // // This is a server only file but it uses TLA. + // ignoredFiles: ["browser-policy-content.js"], + // }, + "browser-policy-framing": {}, // 'constraint-solver': {}, - 'crosswalk': {}, - 'context': { - serverFiles: ['context.js'] + crosswalk: {}, + // context: { Removed/moved to depracated, we don't need it anymore because of fibers + // serverFiles: ["context.js"], + // }, + ddp: {}, + "disable-oplog": {}, + "dynamic-import": { + serverFiles: ["security.js"], }, - 'ddp': {}, - 'disable-oplog': {}, - 'dynamic-import': { - serverFiles: ['security.js'] + ecmascript: { + serverFiles: ["plugin.js", "ecmascript.js"], }, - 'ecmascript': { - serverFiles: ['plugin.js', 'ecmascript.js'] + "ecmascript-runtime": {}, + "ecmascript-runtime-client": { + serverFiles: ["versions.js"], }, - 'ecmascript-runtime': {}, - 'ecmascript-runtime-client': { - serverFiles: ['versions.js'] + "ecmascript-runtime-server": {}, + "es5-shim": {}, + fetch: {}, + "geojson-utils": {}, + "hot-code-push": {}, + "hot-module-replacement": {}, + insecure: {}, + "inter-process-messaging": { + serverFiles: ["inter-process-messaging.js"], }, - 'ecmascript-runtime-server': {}, - 'es5-shim': {}, - 'fetch': {}, - 'geojson-utils': {}, - 'hot-code-push': {}, - 'hot-module-replacement': {}, - 'insecure': {}, - 'inter-process-messaging': { - serverFiles: ['inter-process-messaging.js'] + "launch-screen": {}, + localstorage: {}, + "logic-solver": { + // TODO: Fibers - Legacy + // Revisit when we remove fibers, this may break for legacy + ignoredFiles: ["logic.js", "optimize.js", "minisat.js"], }, - 'launch-screen': {}, - 'localstorage': {}, - 'logic-solver': {}, - 'meteor-base': {}, - 'mobile-experience': {}, - 'mobile-status-bar': {}, - 'modern-browsers': { - serverFiles: ['modern.js'] + "meteor-base": {}, + "mobile-experience": {}, + "mobile-status-bar": {}, + "modern-browsers": { + serverFiles: ["modern.js"], }, - 'modules': {}, - 'modules-runtime': {}, - 'modules-runtime-hot': {}, - 'mongo-dev-server': {}, - 'mongo-livedata': {}, - 'npm-mongo': { - serverFiles: ['wrapper.js'] + modules: {}, + "modules-runtime": {}, + "modules-runtime-hot": {}, + "mongo-dev-server": {}, + "mongo-livedata": {}, + "npm-mongo": { + serverFiles: ["wrapper.js"], }, - 'package-stats-opt-out': {}, - 'package-version-parser': {}, - 'promise': {}, - 'react-fast-refresh': {}, - 'reactive-var': {}, - 'reload-safetybelt': {}, - 'sha': {}, - 'standard-minifiers': {}, + "package-stats-opt-out": {}, + "package-version-parser": {}, + promise: {}, + "react-fast-refresh": {}, + "reactive-var": {}, + // "reload-safetybelt": { + // // is a server only file that uses TLA. + // ignoredFiles: ["reload-safety-belt.js"], + // }, + sha: {}, + "standard-minifiers": {}, // 'test-in-console': {}, - 'test-server-tests-in-console-once': {}, - 'tinytest-harness': {}, - 'twitter-config-ui': {}, + "test-server-tests-in-console-once": {}, + "tinytest-harness": {}, + "twitter-config-ui": {}, // 'twitter-oauth': {}, - 'typescript': { - serverFiles: ['plugin.js'] + typescript: { + serverFiles: ["plugin.js"], }, - 'underscore': {}, - 'url': {}, + url: {}, }; -const acorn = require('acorn'); -const fs = require('fs'); -const path = require('path'); +const acorn = require("acorn"); +const fs = require("fs"); +const path = require("path"); -const baseDir = path.resolve(__dirname, '../../../'); +const baseDir = path.resolve(__dirname, "../../../"); -Object.keys(packages).forEach(packageName => { +Object.keys(packages).forEach((packageName) => { console.log(`=> Checking ${packageName}`); - const packagePath = path.resolve(baseDir, 'packages', packageName); + const packagePath = path.resolve(baseDir, "packages", packageName); let files = listPackageFiles(packagePath); - for(const file of files) { - let content = fs.readFileSync(file, 'utf-8'); + for (const file of files) { + let content = fs.readFileSync(file, "utf-8"); let relPath = path.relative(packagePath, file); let ecmaVersion = clientEcmascriptVersion; if ( packages[packageName].serverFiles?.includes(relPath) || - relPath.endsWith('_server.js') || - file.endsWith('/server.js') + relPath.endsWith("_server.js") || + file.endsWith("/server.js") ) { // Is a server file, which can use some newer syntax ecmaVersion = serverEcmascriptVersion; } + if (packages[packageName].ignoredFiles?.includes(relPath)) { + // is a server file that may use a lot of newer syntax, such as TLA. + ecmaVersion = latestEcmascriptVersion; + } + try { acorn.parse(content, { ecmaVersion, }); } catch (error) { - console.log(''); + console.log(""); console.error(`Failed to parse ${file}: `, error.message); - let line = content.split('\n')[error.loc.line - 1]; + let line = content.split("\n")[error.loc.line - 1]; console.log(line); - console.log(''); + console.log(""); process.exitCode = 1; } } }); - function listPackageFiles(rootPath) { let result = []; function walk(absPath) { let dirents = fs.readdirSync(absPath, { withFileTypes: true }); - - for(const dirent of dirents) { + + for (const dirent of dirents) { if ( - dirent.name === 'package.js' || - dirent.name.startsWith('.') || - + dirent.name === "package.js" || + dirent.name.startsWith(".") || // Only include js files - !dirent.name.endsWith('.js') || - + !dirent.name.endsWith(".js") || // Exclude tests - dirent.name === 'tests' || - dirent.name === 'tests.js' || - dirent.name.endsWith('_tests.js') || - dirent.name.endsWith('-tests.js') + dirent.name === "tests" || + dirent.name === "tests.js" || + dirent.name.endsWith("_tests.js") || + dirent.name.endsWith("_test.js") || + dirent.name.endsWith("-tests.js") ) { continue; } diff --git a/scripts/admin/copy-dev-bundle-from-jenkins.sh b/scripts/admin/copy-dev-bundle-from-jenkins.sh index ab6bfdb13a..58931c5162 100755 --- a/scripts/admin/copy-dev-bundle-from-jenkins.sh +++ b/scripts/admin/copy-dev-bundle-from-jenkins.sh @@ -27,7 +27,7 @@ if [ $# -ne 1 ]; then exit 1 fi -DIRNAME=$(aws s3 ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!(dev-bundle-.+--'${arg}'--.+)/!') +DIRNAME=$(aws s3 ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!(dev-bundle-.+--'${arg}')/!') if [ -z "$DIRNAME" ]; then echo "build not found" 1>&2 @@ -39,7 +39,7 @@ echo Found build $DIRNAME trap "echo Found surprising number of tarballs." EXIT # Check to make sure the proper number of each kind of file is there. aws s3 ls s3://com.meteor.jenkins/$DIRNAME/ | \ - perl -nle 'if (/\.tar\.gz/) { ++$TAR } else { die "something weird" } END { exit !($TAR == 3) }' + perl -nle 'if (/\.tar\.gz/) { ++$TAR } else { die "something weird" } END { exit !($TAR == 4) }' trap - EXIT diff --git a/scripts/admin/copy-dev-bundle-mac-m1-from-jenkins.sh b/scripts/admin/copy-dev-bundle-mac-m1-from-jenkins.sh index 80606dd1c7..6cb1a761ff 100755 --- a/scripts/admin/copy-dev-bundle-mac-m1-from-jenkins.sh +++ b/scripts/admin/copy-dev-bundle-mac-m1-from-jenkins.sh @@ -27,7 +27,7 @@ if [ $# -ne 1 ]; then exit 1 fi -DIRNAME=$(aws s3 ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!(dev-bundle-.+--'${arg}'--.+mac-m1)/!') +DIRNAME=$(aws s3 ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!(dev-bundle-.+--'${arg}'.+mac-m1)/!') if [ -z "$DIRNAME" ]; then echo "build not found" 1>&2 diff --git a/scripts/admin/launch-meteor b/scripts/admin/launch-meteor index 1ec76b4280..69e3afb265 100755 --- a/scripts/admin/launch-meteor +++ b/scripts/admin/launch-meteor @@ -60,6 +60,8 @@ if [ ! -x "$METEOR_WAREHOUSE_DIR/meteor" ]; then PLATFORM="os.linux.x86_32" elif [ "${LINUX_ARCH}" = "x86_64" ] ; then PLATFORM="os.linux.x86_64" + elif [ "${LINUX_ARCH}" = "aarch64" ] ; then + PLATFORM="os.linux.aarch64" else echo "Unusable architecture: ${LINUX_ARCH}" echo "Meteor only supports i686 and x86_64 for now." diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index f6a2edccb5..2432e8857d 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "2.13.3-rc.1", + "version": "3.3.1-rc.2", "recommended": false, "official": false, "description": "Meteor experimental release" diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index 2e8d355c59..7b89d5c0a6 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,7 +1,7 @@ -{ - "track": "METEOR", - "version": "2.13.3", - "recommended": false, - "official": true, - "description": "The Official Meteor Distribution" -} +{ + "track": "METEOR", + "version": "3.3.2", + "recommended": false, + "official": true, + "description": "The Official Meteor Distribution" +} diff --git a/scripts/admin/publish-meteor-tool-on-all-platforms.sh b/scripts/admin/publish-meteor-tool-on-all-platforms.sh index 2e96214eae..8d1cd11ba2 100755 --- a/scripts/admin/publish-meteor-tool-on-all-platforms.sh +++ b/scripts/admin/publish-meteor-tool-on-all-platforms.sh @@ -42,7 +42,7 @@ main () { echo # XXX there is no os.windows.x86_64 as we don't build for it at the moment - PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.windows.x86_32 ) + PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.windows.x86_32 os.linux.aarch64 ) for PLATFORM in ${PLATFORMS[@]}; do COMMAND="`dirname $0`/publish-meteor-tool-on-arch.sh $GITSHA $PLATFORM $SESSION_FILE" echo $COMMAND diff --git a/scripts/admin/publish-meteor-tool-on-arch.sh b/scripts/admin/publish-meteor-tool-on-arch.sh index 9041ac4035..795f43a140 100755 --- a/scripts/admin/publish-meteor-tool-on-arch.sh +++ b/scripts/admin/publish-meteor-tool-on-arch.sh @@ -18,7 +18,7 @@ main () { echo "usage: $0 " 1>&2 echo "The passed sha1 is checked out and published from the machines." 1>&2 echo "Options for platform:" 1>&2 - echo " os.osx.x86_64 os.linux.x86_64 os.linux.x86_32" 1>&2 + echo " os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.linux.aarch64" 1>&2 echo " os.windows.x86_32 os.windows.x86_64" 1>&2 exit 1 fi @@ -33,7 +33,7 @@ main () { METEOR="$CHECKOUT_DIR/meteor" - UNIX_PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 ) + UNIX_PLATFORMS=( os.osx.x86_64 os.linux.x86_64 os.linux.x86_32 os.linux.aarch64 ) WINDOWS_PLATFORMS=( os.windows.x86_32 os.windows.x86_64 ) if [[ $PLATFORM =~ ^(os\.linux|os\.osx) ]] ; then diff --git a/scripts/admin/update-semver/index.js b/scripts/admin/update-semver/index.js index 46fcbd8ff2..ddcbde1792 100644 --- a/scripts/admin/update-semver/index.js +++ b/scripts/admin/update-semver/index.js @@ -78,10 +78,17 @@ async function main() { * @type {string[]} */ let args = process.argv.slice(2); + // if gets bigger turn into a function + const dir = args[1]?.includes("blaze") + ? "packages/non-core/blaze/packages" + : "packages"; const releaseNumber = await getReleaseNumber(); if (args[0].startsWith('@all')) { const [_, type] = args[0].split('.'); - const allPackages = await getDirectories('../../../packages'); + + + + const allPackages = await getDirectories(`../../../${ dir }`); args = allPackages.map((packageName) => `${ packageName }.${ type }`); } @@ -116,7 +123,7 @@ async function main() { .filter((value, index, self) => self.findIndex((v) => v.name === value.name) === index); for (const { name, release } of packages) { - const filePath = `../../../packages/${ name }/package.js`; + const filePath = `../../../${ dir }/${ name }/package.js`; const [code, err] = await getFile(filePath); // if there is an error reading the file, we will skip it. if (err) continue; @@ -130,6 +137,10 @@ async function main() { //}); const [_, version] = line.split(':'); if (!version) continue; + + // for updating all packages + if (version.includes("-alpha300")) continue; + const getVersionValue = (value) => { const removeQuotes = (v) => v @@ -162,12 +173,13 @@ async function main() { const version = semver.inc(currentVersion, 'prerelease', release); if (name === 'meteor-tool') return version; - return version.replace(release, `${ release }${ releaseNumber }`); + return version?.replace(release, `${ release }${ releaseNumber }`); } return semver.inc(currentVersion, release); } - const newVersion = incrementNewVersion(release); + const n = incrementNewVersion(release); + const newVersion = n?.replace(n, `${n}`) console.log(`Updating ${ name } from ${ currentVersion } to ${ newVersion }`); const newCode = code.replace(rawVersion, ` '${ newVersion }',`); await fs.promises.writeFile(filePath, newCode); diff --git a/scripts/admin/update-semver/package-lock.json b/scripts/admin/update-semver/package-lock.json index 80901d6328..10b77a0c9f 100644 --- a/scripts/admin/update-semver/package-lock.json +++ b/scripts/admin/update-semver/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "semver": "^7.3.8" + "semver": "^7.5.2" } }, "node_modules/lru-cache": { @@ -24,9 +24,10 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -53,9 +54,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "requires": { "lru-cache": "^6.0.0" } diff --git a/scripts/admin/update-semver/package.json b/scripts/admin/update-semver/package.json index 3ba0bf697b..4f875a48cf 100644 --- a/scripts/admin/update-semver/package.json +++ b/scripts/admin/update-semver/package.json @@ -11,6 +11,6 @@ "author": "grubba27", "license": "MIT", "dependencies": { - "semver": "^7.3.8" + "semver": "^7.5.2" } } diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index e24cb94592..6f06d676a6 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -5,17 +5,17 @@ set -u UNAME=$(uname) ARCH=$(uname -m) -NODE_VERSION=14.21.4 -MONGO_VERSION_64BIT=6.0.3 +NODE_VERSION=22.18.0 +MONGO_VERSION_64BIT=7.0.16 MONGO_VERSION_32BIT=3.2.22 -NPM_VERSION=6.14.17 +NPM_VERSION=10.9.3 if [ "$UNAME" == "Linux" ] ; then NODE_BUILD_NUMBER= - if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then + if [[ "$ARCH" != "i686" && "$ARCH" != "x86_64" && "$ARCH" != "aarch64" ]] ; then echo "Unsupported architecture: $ARCH" - echo "Meteor only supports i686 and x86_64 for now." + echo "Meteor only supports i686, x86_64 and aarch64 for now." exit 1 fi @@ -40,6 +40,8 @@ elif [ "$UNAME" == "Darwin" ] ; then echo "Meteor only supports x86_64 for now." exit 1 fi + else + NODE_BUILD_NUMBER="${NODE_BUILD_NUMBER:="187"}" fi OS="macos" @@ -65,6 +67,9 @@ then elif [ "$ARCH" == "x86_64" ] then NODE_TGZ="node-v${NODE_VERSION}-linux-x64.tar.gz" + elif [ "$ARCH" == "aarch64" ] + then + NODE_TGZ="node-v${NODE_VERSION}-linux-arm64.tar.gz" else echo "Unknown architecture: $UNAME $ARCH" exit 1 diff --git a/scripts/dev-bundle-server-package.js b/scripts/dev-bundle-server-package.js index 6218244bad..ef92f51625 100644 --- a/scripts/dev-bundle-server-package.js +++ b/scripts/dev-bundle-server-package.js @@ -10,23 +10,22 @@ var packageJson = { dependencies: { // Keep the versions of these packages consistent with the versions // found in dev-bundle-tool-package.js. - fibers: "5.0.1", - "meteor-promise": "0.9.0", - promise: "8.1.0", - "@meteorjs/reify": "0.24.0", - "@babel/parser": "7.15.3", - "@types/underscore": "1.11.2", - underscore: "1.13.1", - "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - "@types/semver": "5.4.0", - semver: "5.4.1" + promise: "8.3.0", + "@meteorjs/reify": "0.25.4", + "@babel/parser": "7.25.0", + "lru-cache": "6.0.0", + underscore: "1.13.7", + "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/81bce1f99625e62af73338f63afcf2b44c6cfa5e", + "@types/semver": "7.5.8", + semver: "7.6.3" }, // These are only used in dev mode (by shell.js) so end-users can avoid // needing to install them if they use `npm install --production`. devDependencies: { + "@types/underscore": "1.11.15", split2: "3.2.2", - multipipe: "1.0.2", - chalk: "0.5.1" + multipipe: "2.0.1", + chalk: "4.1.2" } }; diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 4b8999ed25..b8043936a5 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -10,30 +10,27 @@ var packageJson = { dependencies: { // Explicit dependency because we are replacing it with a bundled version // and we want to make sure there are no dependencies on a higher version - npm: "6.14.17", - pacote: "https://github.com/meteor/pacote/tarball/a81b0324686e85d22c7688c47629d4009000e8b8", - "node-gyp": "8.0.0", - "node-pre-gyp": "0.15.0", - typescript: "4.9.4", - "@meteorjs/babel": "7.18.0-beta.6", + npm: "10.9.3", + "node-gyp": "10.2.0", + "@mapbox/node-pre-gyp": "1.0.11", + typescript: "5.6.3", + "@meteorjs/babel": "7.20.0", // Keep the versions of these packages consistent with the versions // found in dev-bundle-server-package.js. - "meteor-promise": "0.9.0", - fibers: "5.0.1", - "@meteorjs/reify": "0.24.0", + "@meteorjs/reify": "0.25.4", // So that Babel can emit require("@babel/runtime/helpers/...") calls. - "@babel/runtime": "7.15.3", + "@babel/runtime": "7.25.0", // For backwards compatibility with isopackets that still depend on // babel-runtime rather than @babel/runtime. "babel-runtime": "7.0.0-beta.3", - "@types/underscore": "1.11.2", - underscore: "1.13.1", + "@types/underscore": "1.11.15", + underscore: "1.13.7", "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - "@types/semver": "5.4.0", - semver: "5.4.1", + "@types/semver": "7.5.8", + semver: "7.6.3", request: "2.88.2", uuid: "3.4.0", - "graceful-fs": "4.2.6", + "graceful-fs": "4.2.11", fstream: "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d", tar: "6.1.11", 'tar-fs': "2.1.1", @@ -41,16 +38,18 @@ var packageJson = { // https://github.com/jprichardson/node-kexec/pull/37 applied. // TODO: We should replace this with: https://github.com/jprichardson/node-kexec/pull/38 kexec: "https://github.com/meteor/node-kexec/tarball/f29f54037c7db6ad29e1781463b182e5929215a0", - "source-map": "0.7.3", - chalk: "4.1.1", - sqlite3: "5.0.2", + "source-map": "0.7.4", + chalk: "4.1.2", + // TODO: maybe replace with https://www.npmjs.com/package/better-sqlite3 + sqlite3: "5.1.7", + inquirer: "8.2.6", "http-proxy": "1.18.1", "is-reachable": "3.1.0", "wordwrap": "1.0.0", - "moment": "2.29.1", + "moment": "2.30.1", "rimraf": "2.6.2", "glob": "7.1.6", - ignore: "3.3.7", + ignore: "5.3.2", // XXX: When we update this, see if it fixes this Github issue: // https://github.com/jgm/CommonMark/issues/276 . If it does, remove the // workaround from the tool. @@ -58,16 +57,19 @@ var packageJson = { escope: "3.6.0", split2: "3.2.2", multipipe: "2.0.1", - pathwatcher: "8.1.0", + pathwatcher: "8.1.2", "vscode-nsfw": "2.1.8", + "@parcel/watcher": "2.5.1", // The @wry/context package version must be compatible with the // version constraint imposed by optimism/package.json. optimism: "0.16.1", "@wry/context": "0.6.0", - 'lru-cache': '4.1.5', - "anser": "2.0.1", + 'lru-cache': '6.0.0', + "anser": "2.1.1", 'xmlbuilder2': '1.8.1', - "ws": "7.4.5" + "ws": "7.4.5", + "open":"8.4.2", + "acorn": "8.14.1", } }; diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 1d7f874e40..f96509b205 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -108,21 +108,12 @@ Function Add-Python { "$pythonExe" } -# Nodejs 14 official download source has been discontinued, we are switching to our custom source https://static.meteor.com Function Add-NodeAndNpm { if ("${NODE_VERSION}" -match "-rc\.\d+$") { $nodeUrlBase = 'https://nodejs.org/download/rc' } else { $nodeUrlBase = 'https://nodejs.org/dist' } -} - -Function Add-Node14AndNpm { - if ("${NODE_VERSION}" -match "-rc\.\d+$") { - $nodeUrlBase = 'https://nodejs.org/download/rc' - } else { - $nodeUrlBase = 'https://static.meteor.com/dev-bundle-node-os' - } $nodeArchitecture = 'win-x64' @@ -194,9 +185,8 @@ Function Add-Node14AndNpm { # Let's install the npm version we really want. Write-Host "Installing npm@${NPM_VERSION}..." -ForegroundColor Magenta - & "$tempNpmCmd" install --prefix="$dirLib" --no-bin-links --save ` - --cache="$dirNpmCache" --nodedir="$dirTempNode" npm@${NPM_VERSION} | - Write-Debug + Write-Host (& "$tempNpmCmd" install --prefix="$dirLib" --no-bin-links --save ` + --cache="$dirNpmCache" --nodedir="$dirTempNode" npm@${NPM_VERSION} 2>&1) if ($LASTEXITCODE -ne 0) { throw "Couldn't install npm@${NPM_VERSION}." @@ -315,13 +305,6 @@ Function Add-NpmModulesFromJsBundleFile { cd node_modules - # Since we install a patched version of pacote in $Destination\lib\node_modules, - # we need to remove npm's bundled version to make it use the new one. - if (Test-Path "pacote") { - Remove-DirectoryRecursively "npm\node_modules\pacote" - & "$($Commands.node)" -e "require('fs').renameSync('pacote', 'npm\\node_modules\\pacote')" - } - cd "$previousCwd" } @@ -350,7 +333,7 @@ $env:npm_config_cache = "$dirNpmCache" $env:PATH = "$env:PATH;$dirBin" # Install Node.js and npm and get their paths to use from here on. -$toolCmds = Add-Node14AndNpm +$toolCmds = Add-NodeAndNpm "Location of node.exe:" & Get-Command node | Select-Object -ExpandProperty Definition @@ -394,10 +377,6 @@ $npmToolArgs = @{ } Add-NpmModulesFromJsBundleFile @npmToolArgs -# Leaving these probably doesn't hurt, but are removed for consistency w/ Unix. -Remove-Item $(Join-Path $dirLib 'package.json') -Remove-Item $(Join-Path $dirLib 'package-lock.json') - Write-Host "Done writing node_modules build(s)..." -ForegroundColor Magenta Write-Host "Removing temp scratch $dirTemp" -ForegroundColor Magenta diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 671648d73e..792539fe66 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -36,12 +36,6 @@ downloadNodeFromS3() { curl "${NODE_URL}" | tar zx --strip 1 } -# Nodejs 14 official download source has been discontinued, we are switching to our custom source https://static.meteor.com -downloadOfficialNode14() { - METEOR_NODE_URL="https://static.meteor.com/dev-bundle-node-os/v${NODE_VERSION}/${NODE_TGZ}" - echo "Downloading Node from ${METEOR_NODE_URL}" >&2 - curl "${METEOR_NODE_URL}" | tar zx --strip-components 1 -} downloadOfficialNode() { NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TGZ}" @@ -56,8 +50,7 @@ downloadReleaseCandidateNode() { } # Try each strategy in the following order: -extractNodeFromTarGz || downloadNodeFromS3 || \ - downloadOfficialNode14 || downloadReleaseCandidateNode +extractNodeFromTarGz || downloadNodeFromS3 || downloadOfficialNode || downloadReleaseCandidateNode # On macOS, download MongoDB from mongodb.com. On Linux, download a custom build # that is compatible with current distributions. If a 32-bit Linux is used, @@ -71,15 +64,16 @@ fi case $OS in macos) MONGO_BASE_URL="https://fastdl.mongodb.org/osx" ;; linux) - [ $ARCH = "i686" ] && + [ $ARCH = "i686" -o $ARCH = "aarch64" ] && MONGO_BASE_URL="https://fastdl.mongodb.org/linux" || MONGO_BASE_URL="https://github.com/meteor/mongodb-builder/releases/download/v${MONGO_VERSION}" ;; esac - if [ $OS = "macos" ] && [ "$(uname -m)" = "arm64" ] ; then - MONGO_NAME="mongodb-${OS}-x86_64-${MONGO_VERSION}" + MONGO_NAME="mongodb-${OS}-arm64-${MONGO_VERSION}" +elif [ $OS = "linux" ] && [ "$ARCH" = "aarch64" ] ; then + MONGO_NAME="mongodb-linux-aarch64-ubuntu2204-${MONGO_VERSION}" else MONGO_NAME="mongodb-${OS}-${ARCH}-${MONGO_VERSION}" fi @@ -89,6 +83,13 @@ MONGO_URL="${MONGO_BASE_URL}/${MONGO_TGZ}" echo "Downloading Mongo from ${MONGO_URL}" curl -L "${MONGO_URL}" | tar zx +# The tarball outputs as folder name "mongodb-macos-aarch64-X.X.X" even though the URL and the tarball name suggest "mongodb-macos-arm64-X.X.X" +# So we need to rename the folder to match the expected folder name +# Watch out for newer versions of the tarball that might already be named correctly +if [ $OS = "macos" ] && [ "$(uname -m)" = "arm64" ] ; then + MONGO_NAME=$(echo "$MONGO_NAME" | sed 's/arm64/aarch64/g') +fi + # Put Mongo binaries in the right spot (mongodb/bin) mkdir -p "mongodb/bin" mv "${MONGO_NAME}/bin/mongod" "mongodb/bin" @@ -101,7 +102,11 @@ export PATH="$DIR/bin:$PATH" cd "$DIR/lib" # Overwrite the bundled version with the latest version of npm. npm install "npm@$NPM_VERSION" -npm config set python `which python3` +# Starting from npm v9.5.1 we can't set the python (and many others) config +# https://github.com/npm/cli/issues/6126 +# for now we'll not set it anymore and see if it works +# if it doesn't, we can set python3 in other ways +#npm config set python `which python3` which node which npm npm version @@ -148,6 +153,11 @@ cd "${DIR}/build/npm-tool-install" node "${CHECKOUT_DIR}/scripts/dev-bundle-tool-package.js" >package.json npm install cp -R node_modules/* "${DIR}/lib/node_modules/" + +#Also copy package.json and package-lock.json to lib folder so that npm +# keep everything installed correctly +cp package.json "${DIR}/lib/" +cp package-lock.json "${DIR}/lib/" # Also include node_modules/.bin, so that `meteor npm` can make use of # commands like node-gyp and node-pre-gyp. cp -R node_modules/.bin "${DIR}/lib/node_modules/" @@ -169,16 +179,7 @@ delete () { rm -rf "$1" } -# Since we install a patched version of pacote in $DIR/lib/node_modules, -# we need to remove npm's bundled version to make it use the new one. -if [ -d "pacote" ] -then - delete npm/node_modules/pacote - mv pacote npm/node_modules/ -fi - delete sqlite3/deps -delete sqlite3/node_modules/node-pre-gyp delete wordwrap/test delete moment/min diff --git a/scripts/make-release-tarballs.sh b/scripts/make-release-tarballs.sh index 562b67823c..3ae13bce53 100755 --- a/scripts/make-release-tarballs.sh +++ b/scripts/make-release-tarballs.sh @@ -12,13 +12,17 @@ done echo "BRANCH_NAME = $BRANCH_NAME" echo "VERSION = $VERSION" -git fetch origin && git checkout release/METEOR@"$VERSION" && - git reset --hard origin/"$BRANCH_NAME" && - git clean -df && - ./meteor admin make-bootstrap-tarballs --target-arch os.windows.x86_64 "$VERSION" win64 && +git fetch origin +git checkout release/METEOR@"$VERSION" +git reset --hard origin/"$BRANCH_NAME" +git clean -df + +./meteor admin make-bootstrap-tarballs --target-arch os.windows.x86_64 "$VERSION" win64 && aws s3 cp --acl public-read win64/meteor-bootstrap-os.windows.x86_64.tar.gz s3://com.meteor.static/packages-bootstrap/"$VERSION"/ && ./meteor admin make-bootstrap-tarballs --target-arch os.linux.x86_64 "$VERSION" linux64 && aws s3 cp --acl public-read linux64/meteor-bootstrap-os.linux.x86_64.tar.gz s3://com.meteor.static/packages-bootstrap/"$VERSION"/ && + ./meteor admin make-bootstrap-tarballs --target-arch os.linux.aarch64 "$VERSION" linux64 && + aws s3 cp --acl public-read linux64/meteor-bootstrap-os.linux.aarch64.tar.gz s3://com.meteor.static/packages-bootstrap/"$VERSION"/ && ./meteor admin make-bootstrap-tarballs --target-arch os.osx.x86_64 "$VERSION" osx && aws s3 cp --acl public-read osx/meteor-bootstrap-os.osx.x86_64.tar.gz s3://com.meteor.static/packages-bootstrap/"$VERSION"/ && ./meteor admin make-bootstrap-tarballs --target-arch os.osx.arm64 "$VERSION" osx && diff --git a/scripts/test-balancer/package-lock.json b/scripts/test-balancer/package-lock.json index 675392c218..88bd5ca6d3 100644 --- a/scripts/test-balancer/package-lock.json +++ b/scripts/test-balancer/package-lock.json @@ -1,27 +1,37 @@ { "name": "test-balancer", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "sax": { + "packages": { + "": { + "name": "test-balancer", + "version": "0.0.1", + "dependencies": { + "xml2js": "^0.4.19" + } + }, + "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, - "xml2js": { + "node_modules/xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": "1.2.4", - "xmlbuilder": "9.0.4" + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" } }, - "xmlbuilder": { + "node_modules/xmlbuilder": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", - "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=" + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", + "engines": { + "node": ">=4.0" + } } } } diff --git a/scripts/windows/appveyor/install.ps1 b/scripts/windows/appveyor/install.ps1 deleted file mode 100644 index ced6023ad5..0000000000 --- a/scripts/windows/appveyor/install.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -ο»Ώ# Appveyor already sets $PLATFORM to exactly what we don't want, so -# we'll prepend it with 'windows_' if that seems to be the case. -If ($env:PLATFORM -Match '^x86|x64$') { - $env:PLATFORM = "windows_${env:PLATFORM}" -} - -$dirCheckout = (Get-Item $PSScriptRoot).parent.parent.parent.FullName -$meteorBat = Join-Path $dirCheckout 'meteor.bat' - -Write-Host "Updating submodules recursively..." -ForegroundColor Magenta -# Appveyor suggests -q flag for 'git submodule...' https://goo.gl/4TFAHm -& git.exe -C "$dirCheckout" submodule -q update --init --recursive - -If ($LASTEXITCODE -ne 0) { - throw "Updating submodules failed." -} - -# The `meteor --get-ready` command is susceptible to EPERM errors, so -# we attempt it three times. -$attempt = 3 -$success = $false -while ($attempt -gt 0 -and -not $success) { - - Write-Host "Running 'meteor --get-ready'..." -ForegroundColor Magenta - # By redirecting error to host, we avoid a shocking/false error color, - # since --get-ready and --version can print (anything) to STDERR and - # PowerShell will interpret that as something being terribly wrong. - & "$meteorBat" --get-ready - - If ($LASTEXITCODE -eq 0) { - $success = $true - } else { - $attempt-- - } - -} - -If ($LASTEXITCODE -ne 0) { - throw "Running .\meteor --get-ready failed three times." -} diff --git a/scripts/windows/ci/install.ps1 b/scripts/windows/ci/install.ps1 new file mode 100644 index 0000000000..07cccb0c50 --- /dev/null +++ b/scripts/windows/ci/install.ps1 @@ -0,0 +1,56 @@ +# Appveyor already sets $PLATFORM to exactly what we don't want, so +# we'll prepend it with 'windows_' if that seems to be the case. +If ($env:PLATFORM -Match '^x86|x64$') { + $env:PLATFORM = "windows_${env:PLATFORM}" +} + +# Check if we're running in a CI environment +$isCI = $env:GITHUB_ACTIONS -eq "true" + +$dirCheckout = (Get-Item $PSScriptRoot).parent.parent.parent.FullName +$meteorBat = Join-Path $dirCheckout 'meteor.bat' + +Write-Host "Resetting git checkout..." -ForegroundColor Magenta +& git.exe -C "$dirCheckout" reset --hard +& git.exe -C "$dirCheckout" submodule foreach --recursive 'git reset --hard' + +Write-Host "Updating submodules recursively..." -ForegroundColor Magenta +# Appveyor suggests -q flag for 'git submodule...' https://goo.gl/4TFAHm +& git.exe -C "$dirCheckout" submodule -q update --init --recursive + +# Only throw locally +If ($LASTEXITCODE -ne 0 -and -not $isCI) { + throw "Updating submodules failed." +} + +# The `meteor npm install` subcommand should work +& "$meteorBat" npm install +If ($LASTEXITCODE -ne 0) { + throw "'meteor npm install' failed." +} + +# Only `meteor --get-ready` get-ready locally to have better control on CI +# The `meteor --get-ready` command is susceptible to EPERM errors, so +# we attempt it three times. +If (-not $isCI) { + $attempt = 3 + $success = $false + while ($attempt -gt 0 -and -not $success) { + + Write-Host "Running 'meteor --get-ready'..." -ForegroundColor Magenta + # By redirecting error to host, we avoid a shocking/false error color, + # since --get-ready and --version can print (anything) to STDERR and + # PowerShell will interpret that as something being terribly wrong. + & "$meteorBat" --get-ready + + If ($LASTEXITCODE -eq 0) { + $success = $true + } else { + $attempt-- + } + } + + If ($LASTEXITCODE -ne 0) { + throw "Running .\meteor --get-ready failed three times." + } +} diff --git a/scripts/windows/appveyor/test.ps1 b/scripts/windows/ci/test.ps1 similarity index 53% rename from scripts/windows/appveyor/test.ps1 rename to scripts/windows/ci/test.ps1 index f8ef08707d..fb813d33fa 100644 --- a/scripts/windows/appveyor/test.ps1 +++ b/scripts/windows/ci/test.ps1 @@ -1,4 +1,4 @@ -ο»Ώ# For now, we only have one script. +# For now, we only have one script. $jUnit = Join-Path $env:TEMP 'self-test-junit-0.xml' $tests = @( @@ -25,19 +25,6 @@ If ($selfTestExitCode -eq 0) { Write-Host "FAILURE! (Exit: $selfTestExitCode)" -ForegroundColor Red } -Write-Host "Uploading JUnit test results..." -ForegroundColor Magenta -$wc = New-Object 'System.Net.WebClient' -Get-ChildItem $env:TEMP 'self-test-junit-*.xml' | Foreach-Object { - Write-Host " - $($_.FullName)" -ForegroundColor Magenta - Write-Host " - as Artifact..." -ForegroundColor Magenta - Push-AppveyorArtifact $_.FullName - Write-Host " - as Test Results..." -ForegroundColor Magenta - $artifactPostUrl = ` - "https://ci.appveyor.com/api/testresults/junit/", - $env:APPVEYOR_JOB_ID -Join '' - $wc.UploadFile($artifactPostUrl, ($_.FullName)) -} - If ($selfTestExitCode -ne 0) { Exit $selfTestExitCode -} +} \ No newline at end of file diff --git a/tools/PERFORMANCE.md b/tools/PERFORMANCE.md index 7a8864bd84..635f84f78e 100644 --- a/tools/PERFORMANCE.md +++ b/tools/PERFORMANCE.md @@ -167,6 +167,94 @@ The Profiler is activated using `Profile.run(.)`, which will cause a report to b In addition to tool code, you can also use `Profile` in compiler plugins. If you want to use `Profile` in packages that are loaded into the tool (e.g. packages depended on by compiler plugins, or specially loaded into the tool as isopackets), you should always test `(typeof Profile !== 'undefined')` before accessing `Profile`, or pass it in from the tool as an option. +## Inspector Profiling + +In addition to the standard profiler, Meteor includes a more advanced profiling system based on Node.js's `inspector` module. This system generates `.cpuprofile` files that provide much more detailed performance data. + +### How to Use Inspector Profiling + +To enable inspector profiling, you need to specify which functions you want to profile through the `METEOR_INSPECT` environment variable: + +```bash +# Profile multiple functions +METEOR_INSPECT=bundler.bundle,compiler.compile meteor build ./output-build +``` + +Complete list for METEOR_INSPECT: +- bundler.bundle +- compiler.compile +- Babel.compile +- _readProjectMetadata +- initializeCatalog +- _downloadMissingPackages +- _saveChangeMetadata +- _realpath +- package-client + + +### Additional Configuration Options + +You can customize the inspector profiling behavior with the following environment variables: + +```bash +# Identifier for profile files +METEOR_INSPECT_CONTEXT=context_name + +# Directory where .cpuprofile files will be saved (default: ./profiling) +METEOR_INSPECT_OUTPUT=/path/to/directory + +# Sampling interval in ms - lower values = more details but uses more memory +METEOR_INSPECT_INTERVAL=500 + +# Maximum profile size in MB (default: 2000) +METEOR_INSPECT_MAX_SIZE=1000 +``` + +### Viewing the Results + +#### Chrome DevTools +The generated `.cpuprofile` files can be visualized in Chrome DevTools: + +1. Open Chrome DevTools +2. Go to the "Performance" or "Profiler" tab +3. Click "Load Profile" and select the generated .cpuprofile file + +#### Discoveryjs cpupro + +For a opensource interactive analysis of your `.cpuprofile` files, you can use [cpupro](https://discoveryjs.github.io/cpupro/), an open-source CPU profile viewer: + +1. Visit https://discoveryjs.github.io/cpupro/ in your browser +2. Drag and drop your `.cpuprofile` file onto the interface +3. Use the interactive visualization to explore your profile data + +cpupro offers several advantages over Chrome DevTools: +- Better handling of large profiles +- More flexible filtering options +- Advanced search capabilities +- Multiple visualization modes +- Ability to compare different profiles + +You can also run cpupro locally by installing it via npm: + + +### Important Considerations + +- Inspector profiling consumes more memory than the standard profiler +- To avoid out-of-memory (OOM) errors, consider increasing Node's memory limit: + ```bash + NODE_OPTIONS="--max-old-space-size=4096" METEOR_INSPECT=bundler.bundle meteor ... + ``` +- Very large profiles (>2GB) will be automatically truncated to avoid OOM errors + +### When to Use Inspector Profiling + +Use inspector profiling when: +- You need more detailed analysis than the standard profiler provides +- You're investigating complex performance issues +- You want to identify specific bottlenecks in heavy functions like bundler or compiler + +The standard profiler (`METEOR_PROFILE`) remains the best option for quick and general analyses, while inspector profiling is more suitable for detailed diagnostics. + ## Known Areas for Improvement These are areas to improve or investigate, along with what's known, in no diff --git a/tools/README.md b/tools/README.md index c8c68fdb8c..d41096b175 100644 --- a/tools/README.md +++ b/tools/README.md @@ -105,6 +105,34 @@ Internally, every profiled function should be wrapped into a `Profile(fn)` call. The entry point should be started explicitly with the `Profile.run()` call. Otherwise, it won't start measuring anything. +### Inspector Profiling + +In addition to the standard profiler, you can use the more advanced inspector profiling: + +```bash +# Profile a specific function (e.g. bundler.bundle) +METEOR_INSPECT=bundler.bundle meteor run + +# Profile multiple functions +METEOR_INSPECT=bundler.bundle,compiler.compile meteor build +``` + +Additional options: +```bash +# Output directory for .cpuprofile files +METEOR_INSPECT_OUTPUT=/path/to/directory + +# Name to identify profile files +METEOR_INSPECT_CONTEXT=project_xyz + +# Sampling interval (lower = more details, more memory) +METEOR_INSPECT_INTERVAL=500 +``` + +The generated `.cpuprofile` files can be opened in Chrome DevTools through the "Performance" or "Profiler" tab. + +For more details, see the `PERFORMANCE.md` file. + ## Debugging Currently, to debug the tool with `node-inspector`, you can set the ` @@ -164,4 +192,4 @@ a custom try/catch/finally system with recovery. See ## More information For more information about a particular part of Meteor Tool, see subdirectories' -README.md files and the top-level intro comments in the bigger files. +README.md files and the top-level intro comments in the bigger files. \ No newline at end of file diff --git a/tools/cli/commands-cordova.js b/tools/cli/commands-cordova.js index 30a449ea46..fb0f743ee2 100644 --- a/tools/cli/commands-cordova.js +++ b/tools/cli/commands-cordova.js @@ -3,6 +3,7 @@ import main from './main.js'; import { Console } from '../console/console.js'; import catalog from '../packaging/catalog/catalog.js'; import buildmessage from '../utils/buildmessage.js'; +var files = require('../fs/files'); import { CORDOVA_PLATFORMS, ensureDevBundleDependencies, @@ -10,30 +11,30 @@ import { } from '../cordova/index.js'; import {PlatformList} from "../project-context"; -function createProjectContext(appDir) { +async function createProjectContext(appDir) { import { ProjectContext } from '../project-context.js'; const projectContext = new ProjectContext({ projectDir: appDir }); - main.captureAndExit('=> Errors while initializing project:', () => { + await main.captureAndExit('=> Errors while initializing project:', async () => { // We're just reading metadata here; we don't need to resolve constraints. - projectContext.readProjectMetadata(); + await projectContext.readProjectMetadata(); }); return projectContext; } -function doAddPlatform(options) { +async function doAddPlatform(options) { import { CordovaProject } from '../cordova/project.js'; Console.setVerbose(!!options.verbose); - const projectContext = createProjectContext(options.appDir); + const projectContext = await createProjectContext(options.appDir); const platformsToAdd = options.args; let installedPlatforms = projectContext.platformList.getPlatforms(); - main.captureAndExit('', 'adding platforms', () => { + await main.captureAndExit('', 'adding platforms', async () => { for (var platform of platformsToAdd) { if (installedPlatforms.includes(platform)) { buildmessage.error(`${platform}: platform is already added`); @@ -47,38 +48,40 @@ function doAddPlatform(options) { } const cordovaProject = new CordovaProject(projectContext); + await cordovaProject.init(); + if (buildmessage.jobHasMessages()) return; installedPlatforms = installedPlatforms.concat(platformsToAdd); const cordovaPlatforms = filterPlatforms(installedPlatforms); - cordovaProject.ensurePlatformsAreSynchronized(cordovaPlatforms); + await cordovaProject.ensurePlatformsAreSynchronized(cordovaPlatforms); if (buildmessage.jobHasMessages()) { return; } // Only write the new platform list when we have successfully synchronized. - projectContext.platformList.write(installedPlatforms); + await projectContext.platformList.write(installedPlatforms); for (var platform of platformsToAdd) { Console.info(`${platform}: added platform`); if (cordovaPlatforms.includes(platform)) { - cordovaProject.checkPlatformRequirements(platform); + await cordovaProject.checkPlatformRequirements(platform); } } }); } -function doRemovePlatform(options) { +async function doRemovePlatform(options) { import { CordovaProject } from '../cordova/project.js'; import { PlatformList } from '../project-context.js'; - const projectContext = createProjectContext(options.appDir); + const projectContext = await createProjectContext(options.appDir); const platformsToRemove = options.args; let installedPlatforms = projectContext.platformList.getPlatforms(); - main.captureAndExit('', 'removing platforms', () => { + await main.captureAndExit('', 'removing platforms', async () => { for (platform of platformsToRemove) { // Explain why we can't remove server or browser platforms if (PlatformList.DEFAULT_PLATFORMS.includes(platform)) { @@ -102,28 +105,32 @@ version of Meteor`); if (process.platform !== 'win32') { const cordovaProject = new CordovaProject(projectContext); + await cordovaProject.init(); if (buildmessage.jobHasMessages()) return; const cordovaPlatforms = filterPlatforms(installedPlatforms); - cordovaProject.ensurePlatformsAreSynchronized(cordovaPlatforms); + await cordovaProject.ensurePlatformsAreSynchronized(cordovaPlatforms); } }); } // Add one or more Cordova platforms -main.registerCommand({ - name: 'add-platform', - options: { - verbose: { type: Boolean, short: "v" } +main.registerCommand( + { + name: 'add-platform', + options: { + verbose: { type: Boolean, short: 'v' }, + }, + minArgs: 1, + maxArgs: Infinity, + requiresApp: true, + catalogRefresh: new catalog.Refresh.Never(), + notOnWindows: false, }, - minArgs: 1, - maxArgs: Infinity, - requiresApp: true, - catalogRefresh: new catalog.Refresh.Never(), - notOnWindows: false -}, function (options) { - ensureDevBundleDependencies(); - doAddPlatform(options); -}); + async function(options) { + await ensureDevBundleDependencies(); + await doAddPlatform(options); + } +); // Remove one or more Cordova platforms main.registerCommand({ @@ -132,17 +139,17 @@ main.registerCommand({ maxArgs: Infinity, requiresApp: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - ensureDevBundleDependencies(); - doRemovePlatform(options); +}, async function (options) { + await ensureDevBundleDependencies(); + await doRemovePlatform(options); }); main.registerCommand({ name: 'list-platforms', requiresApp: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - const projectContext = createProjectContext(options.appDir); +}, async function (options) { + const projectContext = await createProjectContext(options.appDir); const installedPlatforms = projectContext.platformList.getPlatforms(); @@ -200,9 +207,9 @@ main.registerCommand({ maxArgs: Infinity, requiresApp: true, catalogRefresh: new catalog.Refresh.Never(), -}, function (options) { +}, async function (options) { Console.setVerbose(!!options.verbose); - ensureDevBundleDependencies(); + await ensureDevBundleDependencies(); Console.info("Cordova dependencies are installed."); }); diff --git a/tools/cli/commands-packages-query.js b/tools/cli/commands-packages-query.js index 08597650f1..7f31e40131 100644 --- a/tools/cli/commands-packages-query.js +++ b/tools/cli/commands-packages-query.js @@ -27,7 +27,7 @@ var MAX_RECENT_VERSIONS = 5; // Estimate the publication date for a release. Since we have failed to keep // track of publication times of release versions in the past, we will try to // guess that the release was published at the same time as the tool. -var getReleaseVersionPublishedOn = function (versionRecord) { +var getReleaseVersionPublishedOn = async function (versionRecord) { if (versionRecord.published) { return new Date(versionRecord.published); } @@ -38,7 +38,7 @@ var getReleaseVersionPublishedOn = function (versionRecord) { var toolPackage = versionRecord.tool.split('@'); var toolName = toolPackage[0]; var toolVersion = toolPackage[1]; - var toolRecord = catalog.official.getVersion(toolName, toolVersion); + var toolRecord = await catalog.official.getVersion(toolName, toolVersion); if (! toolRecord || ! toolRecord.published) { return null; } @@ -111,8 +111,8 @@ var formatHiddenVersions = function (hiddenVersions, oldestShownVersion) { }; // Converts an object to an EJSON string with the right spacing. -function formatEJSON(data) { - const { EJSON } = loadIsopackage('ejson'); +async function formatEJSON(data) { + const { EJSON } = await loadIsopackage('ejson'); return EJSON.stringify(data, { indent: true }) + "\n"; } @@ -137,7 +137,7 @@ var padLongformDate = function (dateStr) { // - packageDir: If we are running in a package directory, this will contain // the source root of that package. If we are running from inside a package, // we want that package to show up in our results. -var getTempContext = function (options) { +var getTempContext = async function (options) { var projectContext; // If we are running in an app, we will use it to create a // (mostly immutable) projectContext. @@ -161,9 +161,10 @@ var getTempContext = function (options) { // packages if we can't read them. If this turns out to be a frequent problem, // we can give a warning, instead of failing in the future. For now, we want // to err on the side of consistency. - main.captureAndExit("=> Errors while reading local packages:", function () { - projectContext.initializeCatalog(); + await main.captureAndExit("=> Errors while reading local packages:", function () { + return projectContext.initializeCatalog(); }); + return projectContext; }; @@ -412,32 +413,35 @@ var PackageQuery = function (options) { // We don't want to show pre-releases and un-migrated versions to the user // unless they explicitly ask us about it. self.showHiddenVersions = options.showHiddenVersions; - - // Collect the data for this package, including looking up any specific - // package version that we care about. - if (options.version) { - var versionRecord = self._getVersionRecord(options.version); - if (! versionRecord) { - self.data = null; - return; - } - self.data = versionRecord.local ? - self._getLocalVersion(versionRecord) : - self._getOfficialVersion(versionRecord); - } else { - self.data = self._collectPackageData(); - } + self.version = options.version; }; Object.assign(PackageQuery.prototype, { + init: async function() { + const self = this; + // Collect the data for this package, including looking up any specific + // package version that we care about. + if (self.version) { + var versionRecord = await self._getVersionRecord(self.version); + if (! versionRecord) { + self.data = null; + return; + } + self.data = versionRecord.local ? + await self._getLocalVersion(versionRecord) : + await self._getOfficialVersion(versionRecord); + } else { + self.data = await self._collectPackageData(); + } + }, // Find and return a version record for a given version. Mark the version // record as local, if it is a local version of the package. - _getVersionRecord: function (version) { + _getVersionRecord: async function (version) { var self = this; // We allow local version to override remote versions in meteor show, so we // should start by checking if this is a local version first. - var versionRecord = self.localCatalog.getLatestVersion(self.name); + var versionRecord = await self.localCatalog.getLatestVersion(self.name); // If we asked for "local" as the version number, and found any local version // at all, we are done. @@ -454,7 +458,7 @@ Object.assign(PackageQuery.prototype, { // If we haven't found a local record, or if the local record that we found // doesn't match the version that we asked for, then we have to go look in // the server catalog. - versionRecord = catalog.official.getVersion(self.name, version); + versionRecord = await catalog.official.getVersion(self.name, version); return versionRecord; }, // Print the query information to screen. @@ -462,13 +466,13 @@ Object.assign(PackageQuery.prototype, { // options: // - ejson: Don't pretty-print the data. Print a machine-readable ejson // object. - print: function (options) { + print: async function (options) { var self = this; // If we are asking for an EJSON-style output, we will only print out the // relevant fields. if (options.ejson) { - Console.rawInfo(formatEJSON( + Console.rawInfo(await formatEJSON( self.data.version ? self._generateVersionObject(self.data) : self._generatePackageObject(self.data))); @@ -496,7 +500,7 @@ Object.assign(PackageQuery.prototype, { // per-version information that is relevant to the package as a whole, such // as git, description,etc. // - versions: an array of objects representing versions of this package. - _collectPackageData: function () { + _collectPackageData: async function () { var self = this; var data = { name: self.metaRecord.name, @@ -507,7 +511,7 @@ Object.assign(PackageQuery.prototype, { // Collect surface information about available versions, starting with the // versions available on the server. var serverVersionRecords = - catalog.official.getSortedVersionRecords(self.name); + await catalog.official.getSortedVersionRecords(self.name); var totalVersions = serverVersionRecords.length; // If we are not going to show hidden versions, then we shouldn't waste time @@ -549,16 +553,17 @@ Object.assign(PackageQuery.prototype, { // Process the catalog records into our preferred format, and look up any // other per-version information that we might need. - data["versions"] = _.map(serverVersionRecords, function (versionRecord) { - return self._getOfficialVersion(versionRecord); - }); + data["versions"] = []; + for (const versionRecord of serverVersionRecords) { + data["versions"].push(await self._getOfficialVersion(versionRecord)) + } // The local version doesn't count against the version limit. Look up relevant // information about the local version. - var localVersion = self.localCatalog.getLatestVersion(self.name); + var localVersion = await self.localCatalog.getLatestVersion(self.name); var local; if (localVersion) { - local = self._getLocalVersion(localVersion); + local = await self._getLocalVersion(localVersion); data["versions"].push(local); totalVersions++; } @@ -583,7 +588,7 @@ Object.assign(PackageQuery.prototype, { deprecatedMessage: local.deprecatedMessage }; } else { - var mainlineRecord = catalog.official.getLatestMainlineVersion(self.name); + var mainlineRecord = await catalog.official.getLatestMainlineVersion(self.name); if (mainlineRecord) { var pkgExports = new PkgExports(mainlineRecord.exports); var implies = new PkgImplies(mainlineRecord.dependencies); @@ -623,7 +628,7 @@ Object.assign(PackageQuery.prototype, { // - packageName: name of the dependency // - constraint: constraint for that dependency // - weak: true if this is a weak dependency. - _getOfficialVersion: function (versionRecord) { + _getOfficialVersion: async function (versionRecord) { var self = this; var version = versionRecord.version; var name = self.name; @@ -648,7 +653,7 @@ Object.assign(PackageQuery.prototype, { // Processing and formatting architectures takes time, so we don't want to // do this if we don't have to. if (self.showArchitecturesOS) { - var allBuilds = catalog.official.getAllBuilds(self.name, version); + var allBuilds = await catalog.official.getAllBuilds(self.name, version); var architectures = _.map(allBuilds, function (build) { if (! build['buildArchitectures']) { return "unknown"; @@ -707,7 +712,7 @@ Object.assign(PackageQuery.prototype, { // - packageName: name of the dependency // - constraint: constraint for that dependency // - weak: true if this is a weak dependency. - _getLocalVersion: function (localRecord) { + _getLocalVersion: async function (localRecord) { var self = this; var data = { name: self.name, @@ -739,7 +744,7 @@ Object.assign(PackageQuery.prototype, { } var readmeInfo; - main.captureAndExit( + await main.captureAndExit( "=> Errors while reading local packages:", "reading " + data["directory"], function () { @@ -829,16 +834,24 @@ Object.assign(PackageQuery.prototype, { // Sometimes, there is a server package and a local package with the same // version. In this case, we prefer the local package. Explain our choice to // the user. - if (data.local && - catalog.official.getVersion(data.name, data.version)) { - Console.info(); - Console.info( - "This package version is built locally from source.", - "The same version of this package also exists on the package server.", - "To view its metadata, run", - Console.command("'meteor show " + data.name + "@" + data.version + "'"), - "from outside the project."); - } + // This is a side effect, it is not needed to be awaited. + (async function () { + if ( + data.local && + (await catalog.official.getVersion(data.name, data.version)) + ) { + Console.info(); + Console.info( + "This package version is built locally from source.", + "The same version of this package also exists on the package server.", + "To view its metadata, run", + Console.command( + "'meteor show " + data.name + "@" + data.version + "'" + ), + "from outside the project." + ); + } + })(); }, // Returns a user-friendly object from this PackageQuery to the caller. Takes // in a data object with the same keys as _displayVersion. @@ -1087,17 +1100,19 @@ var ReleaseQuery = function (options) { // Aggregate the query data. If we are asking for a specific version, get data // for a specific version, otherwise aggregate the data about this release // track in general. - self.data = options.version ? - self._getVersionDetails(options.version) : - self._getReleaseData(); + self.version = options.version; }; Object.assign(ReleaseQuery.prototype, { + init: async function () { + const self = this; + self.data = self.version ? await self._getVersionDetails(self.version) : await self._getReleaseData(); + }, // Prints the data from this ReleaseQuery to the terminal. Takes the following // options: // - ejson: Don't pretty-print the data. Return a machine-readable ejson // object. - print: function (options) { + print: async function (options) { var self = this; // If we are asking for an EJSON-style output, print out the relevant fields. @@ -1108,7 +1123,7 @@ Object.assign(ReleaseQuery.prototype, { ]; var packageFields = [ "name", "maintainers", "versions" ]; var fields = self.data.version ? versionFields : packageFields; - Console.rawInfo(formatEJSON(_.pick(self.data, fields))); + Console.rawInfo(await formatEJSON(_.pick(self.data, fields))); return; } @@ -1133,14 +1148,14 @@ Object.assign(ReleaseQuery.prototype, { // - publishedOn: date this version was published // - packages: map of packages that go into this version // - tool: the tool package@version for this release version - _getVersionDetails: function (version) { + _getVersionDetails: async function (version) { var self = this; var versionRecord = - catalog.official.getReleaseVersion(self.name, version); + await catalog.official.getReleaseVersion(self.name, version); if (! versionRecord) { return null; } - var publishDate = getReleaseVersionPublishedOn(versionRecord); + var publishDate = await getReleaseVersionPublishedOn(versionRecord); return { track: self.name, version: version, @@ -1169,14 +1184,14 @@ Object.assign(ReleaseQuery.prototype, { // this version. // - publishedBy: username of the publisher // - publishedOn: date the version was published - _getReleaseData: function () { + _getReleaseData: async function () { var self = this; var data = { track: self.metaRecord.name, maintainers: _.pluck(self.metaRecord.maintainers, "username") }; data["defaultVersion"] = - catalog.official.getDefaultReleaseVersionRecord(self.name); + await catalog.official.getDefaultReleaseVersionRecord(self.name); // Collect information about versions. var versions; @@ -1184,9 +1199,9 @@ Object.assign(ReleaseQuery.prototype, { // There is no obvious way to get an absolute ranking of all release // versions, so this is unsorted. If we have to, we will deal with sorting // this at display time. - versions = catalog.official.getReleaseVersionRecords(self.name); + versions = await catalog.official.getReleaseVersionRecords(self.name); } else { - versions = catalog.official.getSortedRecommendedReleaseRecords(self.name); + versions = await catalog.official.getSortedRecommendedReleaseRecords(self.name); versions.reverse(); } @@ -1201,13 +1216,14 @@ Object.assign(ReleaseQuery.prototype, { if (self.showHiddenVersions) { versionFields.push("orderKey"); } - data["versions"] = _.map(versions, function (versionRecord) { - var data = _.pick(versionRecord, versionFields); - data.publishedBy = versionRecord.publishedBy["username"]; - data.publishedOn = getReleaseVersionPublishedOn(versionRecord); - return data; - }); - data["totalVersions"] = catalog.official.getNumReleaseVersions(self.name); + data["versions"] = []; + for (const versionRecord of versions) { + const pickedValues = _.pick(versionRecord, versionFields); + pickedValues.publishedBy = versionRecord.publishedBy["username"]; + pickedValues.publishedOn = await getReleaseVersionPublishedOn(versionRecord); + data["versions"].push(pickedValues); + } + data["totalVersions"] = await catalog.official.getNumReleaseVersions(self.name); return data; }, // Displays information about a specific release version in a human-readable @@ -1384,13 +1400,13 @@ main.registerCommand({ catalogRefresh: new catalog.Refresh.OnceAtStart( { maxAge: DEFAULT_MAX_AGE_MS, ignoreErrors: true }) -}, function (options) { +}, async function (options) { var fullName; var name; var version; // Because of the new projectContext interface, we need to initialize the // project context in order to load the local catalog. This is not ideal. - var projectContext = getTempContext(options); + var projectContext = await getTempContext(options); // If the user specified a query, process it. if (! _.isEmpty(options.args)) { @@ -1416,7 +1432,7 @@ main.registerCommand({ } // Use the projectContext to get the name of the package. var currentVersion = - projectContext.localCatalog.getVersionBySourceRoot(options.packageDir); + await projectContext.localCatalog.getVersionBySourceRoot(options.packageDir); name = currentVersion.packageName; version = "local"; fullName = name + "@local"; @@ -1431,8 +1447,8 @@ main.registerCommand({ // remote record contains data like 'homepage' and 'maintainers', that the // local record does not). var packageRecord = - catalog.official.getPackage(name) || - projectContext.localCatalog.getPackage(name); + await catalog.official.getPackage(name) || + await projectContext.localCatalog.getPackage(name); if (packageRecord) { query = new PackageQuery({ metaRecord: packageRecord, @@ -1442,19 +1458,21 @@ main.registerCommand({ showArchitecturesOS: options.ejson, showDependencies: !! version }); + await query.init(); } // If this is not a package, it might be a release. Let's check if there is // a release by this name. There are no local releases, so we only need to // check the official catalog. if (! query) { - var releaseRecord = catalog.official.getReleaseTrack(name); + var releaseRecord = await catalog.official.getReleaseTrack(name); if (releaseRecord) { query = new ReleaseQuery({ metaRecord: releaseRecord, version: version, showHiddenVersions: options["show-all"] }); + await query.init(); } } // If we have failed to create a query, or if we have created a query and it @@ -1464,7 +1482,7 @@ main.registerCommand({ return itemNotFound(fullName); } - query.print({ ejson: !! options.ejson }); + await query.print({ ejson: !! options.ejson }); return 0; }); @@ -1491,7 +1509,7 @@ main.registerCommand({ catalogRefresh: new catalog.Refresh.OnceAtStart( { maxAge: DEFAULT_MAX_AGE_MS, ignoreErrors: true }) -}, function (options) { +}, async function (options) { if (options.args.length === 0) { Console.info( "To show all packages, do", Console.command("meteor search .")); @@ -1500,13 +1518,13 @@ main.registerCommand({ // Because of the new projectContext interface, we need to initialize the // project context in order to load the local catalog. - var projectContext = getTempContext(options); + var projectContext = await getTempContext(options); // XXX We should push the queries into SQLite! var allPackages = _.union( - catalog.official.getAllPackageNames(), - projectContext.localCatalog.getAllPackageNames()); - var allReleases = catalog.official.getAllReleaseTracks(); + await catalog.official.getAllPackageNames(), + await projectContext.localCatalog.getAllPackageNames()); + var allReleases = await catalog.official.getAllReleaseTracks(); var matchingPackages = []; var matchingReleases = []; @@ -1522,7 +1540,7 @@ main.registerCommand({ } // Do not return true on broken packages, unless requested in options. - var filterBroken = function (match, isRelease, name) { + var filterBroken = async function (match, isRelease, name) { // If the package does not match, or it is not a package at all or if we // don't want to filter anyway, we do not care. if (!match || isRelease) { @@ -1532,12 +1550,12 @@ main.registerCommand({ if (!options["show-all"]) { // If we can't find a version in the local catalog, we want to get the // latest mainline (ie: non-RC) version from the official catalog. - vr = projectContext.localCatalog.getLatestVersion(name) || - catalog.official.getLatestMainlineVersion(name); + vr = await projectContext.localCatalog.getLatestVersion(name) || + await catalog.official.getLatestMainlineVersion(name); } else { // We want the latest version of this package, and we don't care if it is // a release candidate. - vr = projectContext.projectCatalog.getLatestVersion(name); + vr = await projectContext.projectCatalog.getLatestVersion(name); } if (!vr) { return false; @@ -1573,15 +1591,15 @@ main.registerCommand({ // little sense to require you to be online to find out what packages you // own; and the consequence of not mentioning your group packages until // you update to a new version of meteor is not that dire. - selector = function (name, isRelease) { + selector = async function (name, isRelease) { var record; // XXX make sure search works while offline if (isRelease) { - record = catalog.official.getReleaseTrack(name); + record = await catalog.official.getReleaseTrack(name); } else { - record = catalog.official.getPackage(name); + record = await catalog.official.getPackage(name); } - return filterBroken( + return await filterBroken( (name.match(search) && record && !!_.findWhere(record.maintainers, {username: username})), isRelease, name); @@ -1593,16 +1611,16 @@ main.registerCommand({ }; } - buildmessage.enterJob({ title: 'Searching packages' }, function () { - _.each(allPackages, function (pack) { - if (selector(pack, false)) { + await buildmessage.enterJob({ title: 'Searching packages' }, async function () { + for (const pack of allPackages) { + if (await selector(pack, false)) { var vr; if (!options['show-all']) { vr = - projectContext.localCatalog.getLatestVersion(pack) || - catalog.official.getLatestMainlineVersion(pack); + await projectContext.localCatalog.getLatestVersion(pack) || + await catalog.official.getLatestMainlineVersion(pack); } else { - vr = projectContext.projectCatalog.getLatestVersion(pack); + vr = await projectContext.projectCatalog.getLatestVersion(pack); } if (vr) { matchingPackages.push({ @@ -1613,10 +1631,10 @@ main.registerCommand({ }); } } - }); - _.each(allReleases, function (track) { + } + for (const track of allReleases) { if (selector(track, true)) { - var vr = catalog.official.getDefaultReleaseVersionRecord(track); + var vr = await catalog.official.getDefaultReleaseVersionRecord(track); if (vr) { matchingReleases.push({ name: track, @@ -1626,7 +1644,7 @@ main.registerCommand({ }); } } - }); + } }); if (options.ejson) { @@ -1634,7 +1652,7 @@ main.registerCommand({ packages: matchingPackages, releases: matchingReleases }; - Console.rawInfo(formatEJSON(ret)); + Console.rawInfo(await formatEJSON(ret)); return 0; } diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index 9f26b97089..408654581b 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -36,12 +36,12 @@ import { updateMeteorToolSymlink } from "../packaging/updater.js"; // Specifically, it returns an object with the following keys: // - record : (a package or version record) // - isRelease : true if it is a release instead of a package. -var getReleaseOrPackageRecord = function(name) { - var rec = catalog.official.getPackage(name); +var getReleaseOrPackageRecord = async function(name) { + var rec = await catalog.official.getPackage(name); var rel = false; if (!rec) { // Not a package! But is it a release track? - rec = catalog.official.getReleaseTrack(name); + rec = await catalog.official.getReleaseTrack(name); if (rec) { rel = true; } @@ -51,8 +51,9 @@ var getReleaseOrPackageRecord = function(name) { // Seriously, this dies if it can't refresh. Only call it if you're sure you're // OK that the command doesn't work while offline. -var refreshOfficialCatalogOrDie = function (options) { - if (!catalog.refreshOrWarn(options)) { +var refreshOfficialCatalogOrDie = async function (options) { + const isUpToDate = await catalog.refreshOrWarn(options); + if (!isUpToDate) { Console.error( "This command requires an up-to-date package catalog. Exiting."); throw new main.ExitWithCode(1); @@ -93,7 +94,7 @@ main.registerCommand({ options: { 'allow-incompatible-update': { type: Boolean } } -}, function (options) { +}, async function (options) { // If we're in an app, make sure that we can build the current app. Otherwise // just make sure that we can build some fake app. @@ -103,8 +104,8 @@ main.registerCommand({ neverWritePackageMap: true, allowIncompatibleUpdate: options['allow-incompatible-update'] }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.initializeCatalog(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.initializeCatalog(); }); // Add every local package (including tests) and every release package to this @@ -122,8 +123,8 @@ main.registerCommand({ } // Now finish building and downloading. - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); // We don't display package changes because they'd include all these packages // not actually in the app! @@ -143,14 +144,14 @@ main.registerCommand({ options: { 'allow-incompatible-update': { type: Boolean } } -}, function (options) { +}, async function (options) { var projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, allowIncompatibleUpdate: options['allow-incompatible-update'] }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole(); @@ -167,13 +168,13 @@ main.registerCommand({ // // Takes in a packageSource and a connection to the package server. Returns 0 on // success and an exit code on failure. -var updatePackageMetadata = function (packageSource, conn) { +var updatePackageMetadata = async function (packageSource, conn) { var name = packageSource.name; var version = packageSource.version; // You can't change the metadata of a record that doesn't exist. var existingRecord = - catalog.official.getVersion(name, version); + await catalog.official.getVersion(name, version); if (! existingRecord) { Console.error( "You can't call", Console.command("`meteor publish --update`"), @@ -184,7 +185,7 @@ var updatePackageMetadata = function (packageSource, conn) { // Load in the user's documentation, and check that it isn't blank. var readmeInfo; - main.captureAndExit( + await main.captureAndExit( "=> Errors while publishing:", "reading documentation", function () { readmeInfo = packageSource.processReadme(); @@ -200,11 +201,11 @@ var updatePackageMetadata = function (packageSource, conn) { }; // Finally, call to the server. - main.captureAndExit( + await main.captureAndExit( "=> Errors while publishing:", "updating package metadata", - function () { - packageClient.updatePackageMetadata({ + async function () { + await packageClient.updatePackageMetadata({ packageSource: packageSource, readmeInfo: readmeInfo, connection: conn @@ -217,7 +218,7 @@ var updatePackageMetadata = function (packageSource, conn) { "outside the current project directory."); // Refresh, so that we actually learn about the thing we just published. - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); return 0; }; @@ -244,7 +245,7 @@ main.registerCommand({ // obviously incorrect submissions before they ever hit the wire. catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }), 'allow-incompatible-update': { type: Boolean } -}, function (options) { +}, async function (options) { if (options.create && options['existing-version']) { // Make up your mind! Console.error( @@ -301,16 +302,17 @@ main.registerCommand({ }); } - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", async function () { // Just get up to initializing the catalog. We're going to mutate the // constraints file a bit before we prepare the build. - projectContext.initializeCatalog(); + await projectContext.initializeCatalog(); }); + let conn; if (!process.env.METEOR_TEST_NO_PUBLISH) { // Connect to the package server and log in. try { - var conn = packageClient.loggedInPackagesConnection(); + conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; @@ -353,13 +355,13 @@ main.registerCommand({ // need. Don't bother building the package, just update the metadata and // return the result. if (options.update) { - return updatePackageMetadata(packageSource, conn); + return await updatePackageMetadata(packageSource, conn); } // Fail early if the package record exists, but we don't think that it does // and are passing in the --create flag! if (options.create) { - var packageInfo = catalog.official.getPackage(packageName); + var packageInfo = await catalog.official.getPackage(packageName); if (packageInfo) { Console.error( "Package already exists. To create a new version of an existing "+ @@ -402,14 +404,14 @@ main.registerCommand({ }); // Now resolve constraints and build packages. - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); // We don't display the package map delta here, because it includes adding the // package's test and all the test's dependencies. if (!options['no-lint']) { - const warnings = projectContext.getLintingMessagesForLocalPackages(); + const warnings = await projectContext.getLintingMessagesForLocalPackages(); if (warnings && warnings.hasMessages()) { Console.arrowError( "Errors linting your package; run with --no-lint to ignore."); @@ -438,11 +440,11 @@ main.registerCommand({ // We have initialized everything, so perform the publish operation. var binary = isopack.platformSpecific(); - main.captureAndExit( - "=> Errors while publishing:", + await main.captureAndExit( + "=> Errors while publishing:" + packageSource.name, "publishing the package", - function () { - packageClient.publishPackage({ + async function () { + await packageClient.publishPackage({ projectContext: projectContext, packageSource: packageSource, connection: conn, @@ -457,7 +459,7 @@ main.registerCommand({ // We are only publishing one package, so we should close the connection, and // then exit with the previous error code. - conn.close(); + await conn.close(); // Warn the user if their package is not good for all architectures. if (binary && options['existing-version']) { @@ -487,7 +489,7 @@ main.registerCommand({ } // Refresh, so that we actually learn about the thing we just published. - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); return 0; }); @@ -502,7 +504,7 @@ main.registerCommand({ // publish-for-arch you want to reproduce the exact same setup as when // you ran 'publish', but support the option in case it comes up. 'allow-incompatible-update': { type: Boolean } -}, function (options) { +}, async function (options) { // argument processing var all = options.args[0].split('@'); if (all.length !== 2) { @@ -513,7 +515,7 @@ main.registerCommand({ var name = all[0]; var versionString = all[1]; - var packageInfo = catalog.official.getPackage(name); + var packageInfo = await catalog.official.getPackage(name); if (! packageInfo) { Console.error( "You can't call " + Console.command("`meteor publish-for-arch`") + @@ -528,7 +530,7 @@ main.registerCommand({ return 1; } - var pkgVersion = catalog.official.getVersion(name, versionString); + var pkgVersion = await catalog.official.getVersion(name, versionString); if (! pkgVersion) { Console.error( "You can't call", Console.command("`meteor publish-for-arch`"), @@ -591,8 +593,8 @@ main.registerCommand({ // or we're running from the same release as the published package. // Download the source to the package. - var sourceTarball = buildmessage.enterJob("downloading package source", function () { - return httpHelpers.getUrlWithResuming({ + var sourceTarball = await buildmessage.enterJob("downloading package source", async function () { + return await httpHelpers.getUrlWithResuming({ url: pkgVersion.source.url, encoding: null }); @@ -603,9 +605,9 @@ main.registerCommand({ } var sourcePath = files.mkdtemp('package-source'); - buildmessage.enterJob("extracting package source", () => { + await buildmessage.enterJob("extracting package source", async () => { // XXX check tarballHash! - files.extractTarGz(sourceTarball, sourcePath); + await files.extractTarGz(sourceTarball, sourcePath); }); // XXX Factor out with packageClient.bundleSource so that we don't @@ -641,13 +643,13 @@ main.registerCommand({ }); // Just get up to initializing the catalog. We're going to mutate the // constraints file a bit before we prepare the build. - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.initializeCatalog(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.initializeCatalog(); }); projectContext.projectConstraintsFile.addConstraints( [utils.parsePackageConstraint(name + "@=" + versionString)]); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole({ title: "Some package versions changed since this package was published!" @@ -660,25 +662,25 @@ main.registerCommand({ var conn; try { - conn = packageClient.loggedInPackagesConnection(); + conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; } - main.captureAndExit( + await main.captureAndExit( "=> Errors while publishing build:", ("publishing package " + name + " for architecture " + isopk.buildArchitectures()), - function () { - packageClient.createAndPublishBuiltPackage( + async function () { + await packageClient.createAndPublishBuiltPackage( conn, isopk, projectContext.isopackCache); } ); Console.info('Published ' + name + '@' + versionString + '.'); - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); return 0; }); @@ -704,11 +706,12 @@ main.registerCommand({ 'skip-tree-hashing': { type: Boolean }, }, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { + let conn try { - var conn = packageClient.loggedInPackagesConnection(); + conn = await packageClient.loggedInPackagesConnection(); } catch (err) { - packageClient.handlePackageServerConnectionError(err); + await packageClient.handlePackageServerConnectionError(err); return 1; } @@ -726,7 +729,7 @@ main.registerCommand({ } // Fill in the order key and any other generated release.json fields. - main.captureAndExit( + await main.captureAndExit( "=> Errors in release schema:", "double-checking release schema", function () { @@ -796,7 +799,7 @@ main.registerCommand({ // authorized to publish before we do any complicated/long operations, and // before we publish its packages. if (! options['create-track']) { - var trackRecord = catalog.official.getReleaseTrack(relConf.track); + var trackRecord = await catalog.official.getReleaseTrack(relConf.track); if (!trackRecord) { Console.error( 'There is no release track named ' + relConf.track + @@ -806,7 +809,7 @@ main.registerCommand({ // Check with the server to see if we're organized (we can't due this // locally due to organizations). - if (!packageClient.amIAuthorized(relConf.track,conn, true)) { + if (!await packageClient.amIAuthorized(relConf.track, conn, true)) { Console.error('You are not an authorized maintainer of ' + relConf.track + "."); Console.error('Only authorized maintainers may publish new versions.'); @@ -856,15 +859,17 @@ main.registerCommand({ // though this temporary directory does not have any cordova platforms forceIncludeCordovaUnibuild: true }); - // Read metadata and initialize catalog. - main.captureAndExit("=> Errors while building for release:", function () { - projectContext.initializeCatalog(); + await main.captureAndExit("=> Errors while building for release:", async function () { + await projectContext.initializeCatalog(); }); // Ensure that all packages and their tests are built. (We need to build // tests so that we can include their sources in source tarballs.) var allPackagesWithTests = projectContext.localCatalog.getAllPackageNames(); + /** + * @type {Array} + */ var allPackages = projectContext.localCatalog.getAllNonTestPackageNames({ includeNonCore: false, }); @@ -875,18 +880,26 @@ main.registerCommand({ ); // Build! - main.captureAndExit("=> Errors while building for release:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while building for release:", async function () { + await projectContext.prepareProjectForBuild(); }); // No need to display the PackageMapDelta here, since it would include all // of the packages! relConf.packages = {}; var toPublish = []; - Console.info(`Will publish new version for MeteorJS: ${relConf.version}`); - main.captureAndExit("=> Errors in release packages:", function () { - _.each(allPackages, function (packageName) { - buildmessage.enterJob("checking consistency of " + packageName, function () { + + await main.captureAndExit("=> Errors in release packages:", async function () { + const publishList = []; + for (const name of allPackages) { + if (name === "meteor-tool") { // to be sure that is the last so things do not break + continue; + } + publishList.push(name) + } + publishList.push("meteor-tool"); + for (const packageName of publishList) { + await buildmessage.enterJob("checking consistency of " + packageName, async function () { var packageSource = projectContext.localCatalog.getPackageSource( packageName); if (! packageSource) { @@ -903,7 +916,7 @@ main.registerCommand({ // Let's get the server version that this local package is // overwriting. If such a version exists, we will need to make sure // that the contents are the same. - var oldVersionRecord = catalog.official.getVersion( + var oldVersionRecord = await catalog.official.getVersion( packageName, packageSource.version); // Include this package in our release. @@ -939,7 +952,7 @@ main.registerCommand({ // First try with the non-simplified build architecture // list, which is likely to be something like // os+web.browser+web.browser.legacy+web.cordova: - catalog.official.getBuildWithPreciseBuildArchitectures( + await catalog.official.getBuildWithPreciseBuildArchitectures( oldVersionRecord, isopk.buildArchitectures(), ) || @@ -947,7 +960,7 @@ main.registerCommand({ // list (e.g. os+web.browser+web.cordova), to match packages // published before the web.browser.legacy architecture was // introduced (in Meteor 1.7). - catalog.official.getBuildWithPreciseBuildArchitectures( + await catalog.official.getBuildWithPreciseBuildArchitectures( oldVersionRecord, isopk.buildArchitectures(true), ); @@ -968,7 +981,7 @@ main.registerCommand({ // new release is being published. packageName === "meteor-tool") { // Save the isopack, just to get its hash. - var bundleBuildResult = packageClient.bundleBuild( + var bundleBuildResult = await packageClient.bundleBuild( isopk, projectContext.isopackCache, ); @@ -977,18 +990,18 @@ main.registerCommand({ (bundleBuildResult.treeHash !== existingBuild.build.treeHash); } - if (somethingChanged) { - buildmessage.error( - "Something changed in package " + packageName + "@" + - isopk.version + ". Please upgrade its version number."); - } + // if (somethingChanged) { + // buildmessage.error( + // "Something changed in package " + packageName + "@" + + // isopk.version + ". Please upgrade its version number."); + // } } }); - }); + } }); if (options['dry-run']) { - main.captureAndExit("=> Dry run", function () { + await main.captureAndExit("=> Dry run", function () { buildmessage.error( "This is not an error but it was just a validation" + " and nothing was published. Remove --dry-run to publish."); @@ -999,11 +1012,11 @@ main.registerCommand({ // We now have an object of packages that have new versions on disk that // don't exist in the server catalog. Publish them. var unfinishedBuilds = {}; - _.each(toPublish, function (packageName) { - main.captureAndExit( + for (const packageName of toPublish) { + await main.captureAndExit( "=> Errors while publishing:", "publishing package " + packageName, - function () { + async function () { var isopk = projectContext.isopackCache.getIsopack(packageName); if (! isopk) { throw Error("no isopack for " + packageName); @@ -1015,17 +1028,16 @@ main.registerCommand({ } var binary = isopk.platformSpecific(); - packageClient.publishPackage({ + await packageClient.publishPackage({ projectContext: projectContext, packageSource: packageSource, connection: conn, - new: ! catalog.official.getPackage(packageName), + new: ! await catalog.official.getPackage(packageName), doNotPublishBuild: binary }); if (buildmessage.jobHasMessages()) { return; } - Console.info( 'Published ' + packageName + '@' + packageSource.version + '.'); @@ -1033,7 +1045,7 @@ main.registerCommand({ unfinishedBuilds[packageName] = packageSource.version; } }); - }); + } // Set the remaining release information. For now, when we publish from // checkout, we always set 'meteor-tool' as the tool. We don't include the @@ -1042,24 +1054,24 @@ main.registerCommand({ delete relConf.packages["meteor-tool"]; } - main.captureAndExit( + await main.captureAndExit( "=> Errors while publishing release:", "publishing release", - function () { + async function () { // Create the new track, if we have been told to. if (options['create-track']) { // XXX maybe this job title should be left on the screen too? some sort // of enterJob/progress option that lets you do that? - buildmessage.enterJob("creating a new release track", function () { - packageClient.callPackageServerBM( - conn, 'createReleaseTrack', { name: relConf.track } ); + await buildmessage.enterJob("creating a new release track", async function () { + await packageClient.callPackageServerBM( + conn, 'createReleaseTrack', { name: relConf.track }); }); if (buildmessage.jobHasMessages()) { return; } } - buildmessage.enterJob("creating a new release version", function () { + await buildmessage.enterJob("creating a new release version", async function () { var record = { track: relConf.track, version: relConf.version, @@ -1071,10 +1083,10 @@ main.registerCommand({ }; if (relConf.patchFrom) { - packageClient.callPackageServerBM( + await packageClient.callPackageServerBM( conn, 'createPatchReleaseVersion', record, relConf.patchFrom); } else { - packageClient.callPackageServerBM( + await packageClient.callPackageServerBM( conn, 'createReleaseVersion', record); } }); @@ -1082,7 +1094,7 @@ main.registerCommand({ ); // Learn about it. - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); Console.info("Done creating " + relConf.track + "@" + relConf.version + "!"); Console.info(); @@ -1099,13 +1111,13 @@ main.registerCommand({ Console.info("Skipping git tag: bad format for git."); } else { Console.info("Creating git tag " + gitTag); - utils.runGitInCheckout('tag', gitTag); + await utils.runGitInCheckout('tag', gitTag); var fail = false; try { Console.info( "Pushing git tag (this should fail if you are not from Meteor Software)"); - utils.runGitInCheckout('push', 'git@github.com:meteor/meteor.git', - 'refs/tags/' + gitTag); + await utils.runGitInCheckout('push', 'git@github.com:meteor/meteor.git', + 'refs/tags/' + gitTag); } catch (err) { Console.error( "Failed to push git tag. Please push git tag manually!"); @@ -1156,17 +1168,18 @@ main.registerCommand({ 'allow-incompatible-update': { type: Boolean } }, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: true }) -}, function (options) { +}, async function (options) { var projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, allowIncompatibleUpdate: options['allow-incompatible-update'] }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + + await main.captureAndExit("=> Errors while initializing project:", async function () { + return await projectContext.prepareProjectForBuild(); }); + // No need to display the PackageMapDelta here, since we're about to list all // of the packages anyway! - const showJson = !!options['json']; const showTree = !!options['tree']; @@ -1176,7 +1189,7 @@ main.registerCommand({ weak: '[weak]', skipped: 'package skipped', missing: 'missing?' - } + }; if (showJson && showTree) { throw new Error('can only run for one option,found --json and --tree'); @@ -1188,8 +1201,8 @@ main.registerCommand({ const showDetails = !!options['details']; // Load package details of all used packages (inc. dependencies) const packageDetails = new Map; - projectContext.packageMap.eachPackage(function (name, info) { - packageDetails.set(name, projectContext.projectCatalog.getVersion(name, info.version)); + await projectContext.packageMap.eachPackage(async function (name, info) { + packageDetails.set(name, await projectContext.projectCatalog.getVersion(name, info.version)); }); // Build a set of top level package names @@ -1202,7 +1215,7 @@ main.registerCommand({ const dontExpand = new Set(topLevelSet.values()); // Recursive function that outputs each package - const printPackage = function ({ packageToPrint, isWeak, indent1, indent2, parent }) { + const printPackage = async function ({ packageToPrint, isWeak, indent1, indent2, parent }) { const packageName = packageToPrint.packageName; const depsObj = packageToPrint.dependencies || {}; let deps = Object.keys(depsObj).sort(); @@ -1243,7 +1256,7 @@ main.registerCommand({ if (showJson) { if (expandedAlready) { // on expanded packages we only want to add minimal information to - // keep the json file compact, so we make the value a string + // keep the json file compact, so we make the value a stirng if (topLevelSet.has(packageName)) { parent[packageName] = `${packageToPrint.version}-${suffixes.topLevel}` } else { @@ -1262,7 +1275,7 @@ main.registerCommand({ version: packageToPrint.version, local: isLocal, weak: isWeak, - newerVersion: !isLocal && getNewerVersion(packageName, packageToPrint.version, catalog.official) + newerVersion: !isLocal && await getNewerVersion(packageName, packageToPrint.version, catalog.official) }); Object.entries(infoSource).forEach(([key, value]) => { @@ -1279,7 +1292,8 @@ main.registerCommand({ if (shouldExpand) { dontExpand.add(packageName); - deps.forEach((dep, index) => { + let index = 0; + for (const dep of deps) { const references = depsObj[dep].references || []; const weakRef = references.length > 0 && references.every(r => r.weak); const last = ((index + 1) === deps.length); @@ -1290,7 +1304,7 @@ main.registerCommand({ const newIndent1 = indent2 + (last ? '└─' : 'β”œβ”€'); const newIndent2 = indent2 + (last ? ' ' : 'β”‚ '); if (child) { - printPackage({ + await printPackage({ packageToPrint: child, isWeak: weakRef, indent1: newIndent1, @@ -1305,7 +1319,7 @@ main.registerCommand({ if (showJson) { if (child) { - printPackage({ + await printPackage({ packageToPrint: child, isWeak: weakRef, parent: parent[packageName].dependencies @@ -1316,17 +1330,18 @@ main.registerCommand({ parent[packageName].dependencies = suffixes.missing; } } - }); + index++; + } } }; const topLevelNames = Array.from(topLevelSet.values()).sort(); - topLevelNames.forEach((dep, index) => { + for (const dep of topLevelNames) { const topLevelPackage = packageDetails.get(dep); if (topLevelPackage) { // Force top level packages to be expanded dontExpand.delete(topLevelPackage.packageName); - printPackage({ + await printPackage({ packageToPrint: topLevelPackage, isWeak: false, indent1: '', @@ -1334,7 +1349,7 @@ main.registerCommand({ parent: jsonOut }) } - }); + } if (showJson) { // we can't use Console here, because it pretty prints the output with @@ -1352,7 +1367,7 @@ main.registerCommand({ // Iterate over packages that are used directly by this app (not indirect // dependencies). - projectContext.projectConstraintsFile.eachConstraint(function (constraint) { + await projectContext.projectConstraintsFile.eachConstraintAsync(async function (constraint) { var packageName = constraint.package; // Skip isobuild:* pseudo-packages. @@ -1364,7 +1379,7 @@ main.registerCommand({ if (! mapInfo) { throw Error("no version for used package " + packageName); } - var versionRecord = projectContext.projectCatalog.getVersion( + var versionRecord = await projectContext.projectCatalog.getVersion( packageName, mapInfo.version); if (! versionRecord) { throw Error("no version record for " + packageName + "@" + @@ -1376,7 +1391,7 @@ main.registerCommand({ versionAddendum = "+"; anyBuiltLocally = true; } else if (mapInfo.kind === 'versioned') { - if (getNewerVersion(packageName, mapInfo.version, catalog.official)) { + if (await getNewerVersion(packageName, mapInfo.version, catalog.official)) { versionAddendum = "*"; newVersionsAvailable = true; } @@ -1421,7 +1436,7 @@ main.registerCommand({ return 0; }); -var getNewerVersion = function (packageName, curVersion, whichCatalog) { +var getNewerVersion = async function (packageName, curVersion, whichCatalog) { // Check to see if there are later versions available, returning the // latest version if there are. // @@ -1434,9 +1449,9 @@ var getNewerVersion = function (packageName, curVersion, whichCatalog) { // that we'll find something when we look in the catalog. var latest; if (/-/.test(curVersion)) { - latest = whichCatalog.getLatestVersion(packageName); + latest = await whichCatalog.getLatestVersion(packageName); } else { - latest = whichCatalog.getLatestMainlineVersion(packageName); + latest = await whichCatalog.getLatestMainlineVersion(packageName); } if (! latest) { // Shouldn't happen: we've chosen a published version of this package, @@ -1464,7 +1479,7 @@ var getNewerVersion = function (packageName, curVersion, whichCatalog) { // decided not to with good reason. Returns something other than 0, if it is not // safe to proceed (ex: our release track is fundamentally unsafe or there is // weird catalog corruption). -var maybeUpdateRelease = function (options) { +var maybeUpdateRelease = async function (options) { // We are only updating packages, so we are not updating the release. if (options["packages-only"]) { return 0; @@ -1487,7 +1502,7 @@ var maybeUpdateRelease = function (options) { // XXX better error checking on release.current.name // XXX add a method to release.current. var releaseTrack = release.current ? - release.current.getReleaseTrack() : catalog.DEFAULT_TRACK; + await release.current.getReleaseTrack() : catalog.DEFAULT_TRACK; // Unless --release was passed (in which case we ought to already have // springboarded to that release), go get the latest release and switch to @@ -1498,7 +1513,7 @@ var maybeUpdateRelease = function (options) { // double-springboard. (We might miss an super recently published release, // but that's probably OK.) if (! release.forced) { - var latestRelease = release.latestKnown(releaseTrack); + var latestRelease = await release.latestKnown(releaseTrack); // Are we on some track without ANY recommended releases at all, // and the user ran 'meteor update' without specifying a release? We @@ -1512,8 +1527,8 @@ var maybeUpdateRelease = function (options) { if (release.current && ! release.current.isRecommended() && options.appDir && ! options.patch) { - var releaseVersion = release.current.getReleaseVersion(); - var newerRecommendedReleases = getLaterReleaseVersions( + var releaseVersion = await release.current.getReleaseVersion(); + var newerRecommendedReleases = await getLaterReleaseVersions( releaseTrack, releaseVersion); if (!newerRecommendedReleases.length) { // When running 'meteor update' without --release in an app, @@ -1555,7 +1570,7 @@ var maybeUpdateRelease = function (options) { throw new Error("don't have a proper release?"); } - updateMeteorToolSymlink(true); + await updateMeteorToolSymlink(true); // If we're not in an app, then we're basically done. The only thing left to // do is print out some messages explaining what happened (and advising the @@ -1588,7 +1603,7 @@ var maybeUpdateRelease = function (options) { // We get here if the user ran 'meteor update' and we didn't // find a new version. Console.info( - "The latest version of Meteor, " + release.current.getReleaseVersion() + + "The latest version of Meteor, " + await release.current.getReleaseVersion() + ", is already installed on this computer. Run " + Console.command("'meteor update'") + " inside of a particular " + "project directory to update that project to " + @@ -1606,8 +1621,8 @@ var maybeUpdateRelease = function (options) { alwaysWritePackageMap: true, allowIncompatibleUpdate: true // disregard `.meteor/versions` if necessary }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.readProjectMetadata(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.readProjectMetadata(); }); if (projectContext.releaseFile.fullReleaseName === release.current.name) { @@ -1641,7 +1656,7 @@ var maybeUpdateRelease = function (options) { "Cannot patch update unless a release is set."); return 1; } - var record = catalog.official.getReleaseVersion( + var record = await catalog.official.getReleaseVersion( projectContext.releaseFile.releaseTrack, projectContext.releaseFile.releaseVersion); if (!record) { @@ -1655,7 +1670,7 @@ var maybeUpdateRelease = function (options) { "You are at the latest patch version."); return 0; } - var patchRecord = catalog.official.getReleaseVersion( + var patchRecord = await catalog.official.getReleaseVersion( projectContext.releaseFile.releaseTrack, updateTo); // It looks like you are not at the latest patch version, // technically. But, in practice, we cannot update you to the latest patch @@ -1675,14 +1690,17 @@ var maybeUpdateRelease = function (options) { } else if (release.explicit) { // You have explicitly specified a release, and we have springboarded to // it. So, we will use that release to update you to itself, if we can. - releaseVersion = release.current.getReleaseVersion(); + releaseVersion = await release.current.getReleaseVersion(); } else { // We are not doing a patch update, or a specific release update, so we need // to try all recommended releases on our track, whose order key is greater // than the app's. - releaseVersion = getLaterReleaseVersions( - projectContext.releaseFile.releaseTrack, - projectContext.releaseFile.releaseVersion)[0]; + releaseVersion = ( + await getLaterReleaseVersions( + projectContext.releaseFile.releaseTrack, + projectContext.releaseFile.releaseVersion + ) + )[0]; if (! releaseVersion) { // We could not find any releases newer than the one that we are on, on @@ -1708,7 +1726,7 @@ var maybeUpdateRelease = function (options) { // Update every package in .meteor/packages to be (semver)>= the version // set for that package in the release we are updating to - var releaseRecord = catalog.official.getReleaseVersion(releaseTrack, releaseVersion); + var releaseRecord = await catalog.official.getReleaseVersion(releaseTrack, releaseVersion); projectContext.projectConstraintsFile.updateReleaseConstraints(releaseRecord); // Download and build packages and write the new versions to .meteor/versions. @@ -1717,11 +1735,11 @@ var maybeUpdateRelease = function (options) { // to upgrade packages and have to do it again. Maybe we shouldn't? Note // that if we change this, that changes the upgraders interface, which // expects a projectContext that is fully prepared for build. - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); - projectContext.writeReleaseFileAndDevBundleLink(releaseName); + await projectContext.writeReleaseFileAndDevBundleLink(releaseName); projectContext.packageMapDelta.displayOnConsole({ title: ("Changes to your project's package version selections from " + @@ -1744,12 +1762,12 @@ var maybeUpdateRelease = function (options) { return 0; }; -function getLaterReleaseVersions(releaseTrack, releaseVersion) { - var releaseInfo = catalog.official.getReleaseVersion( +async function getLaterReleaseVersions(releaseTrack, releaseVersion) { + var releaseInfo = await catalog.official.getReleaseVersion( releaseTrack, releaseVersion); var orderKey = (releaseInfo && releaseInfo.orderKey) || null; - return catalog.official.getSortedRecommendedReleaseVersions( + return await catalog.official.getSortedRecommendedReleaseVersions( releaseTrack, orderKey); } @@ -1767,7 +1785,7 @@ main.registerCommand({ minArgs: 0, maxArgs: Infinity, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: true }) -}, function (options) { +}, async function (options) { // If you are specifying packages individually, you probably don't want to // update the release. if (options.args.length > 0) { @@ -1791,7 +1809,7 @@ main.registerCommand({ return 1; } - var releaseUpdateStatus = maybeUpdateRelease(options); + var releaseUpdateStatus = await maybeUpdateRelease(options); // If we encountered an error and cannot proceed, return. if (releaseUpdateStatus !== 0) { return releaseUpdateStatus; @@ -1812,8 +1830,8 @@ main.registerCommand({ alwaysWritePackageMap: true, allowIncompatibleUpdate: options["allow-incompatible-update"] }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.readProjectMetadata(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.readProjectMetadata(); }); // If no packages have been specified, then we will send in a request to @@ -1848,10 +1866,19 @@ main.registerCommand({ if (options["all-packages"]) { Console.error("You cannot both specify a list of packages to" + " update and pass --all-packages."); - exit(1) + process.exit(1) } upgradePackageNames = options.args; + + if (upgradePackageNames.some(name => name.includes("@"))) { + Console.error( + "Package names can not contain \"@\". If you are trying to", + "update a package to a specific version, instead use", + Console.command('"meteor add"') + ); + process.exit(1); + } } // We want to use the project's release for constraints even if we are // currently running a newer release (eg if we ran 'meteor update --patch' and @@ -1862,11 +1889,12 @@ main.registerCommand({ var releaseRecordForConstraints = null; if (! files.inCheckout() && projectContext.releaseFile.normalReleaseSpecified()) { - releaseRecordForConstraints = catalog.official.getReleaseVersion( + releaseRecordForConstraints = await catalog.official.getReleaseVersion( projectContext.releaseFile.releaseTrack, projectContext.releaseFile.releaseVersion); if (! releaseRecordForConstraints) { - throw Error("unknown release " + + console.log(projectContext.releaseFile, releaseRecordForConstraints) + throw Error("unknown release: " + projectContext.releaseFile.displayReleaseName); } } @@ -1900,15 +1928,15 @@ main.registerCommand({ } // Try to resolve constraints, allowing the given packages to be upgraded. - projectContext.reset({ + await projectContext.reset({ releaseForConstraints: releaseRecordForConstraints, upgradePackageNames: upgradePackageNames, upgradeIndirectDepPatchVersions: upgradeIndirectDepPatchVersions }); - main.captureAndExit( - "=> Errors while upgrading packages:", "upgrading packages", function () { - projectContext.resolveConstraints(); - if (buildmessage.jobHasMessages()) { + await main.captureAndExit( + "=> Errors while upgrading packages:", "upgrading packages", async function () { + await projectContext.resolveConstraints(); + if (await buildmessage.jobHasMessages()) { return; } @@ -1921,12 +1949,12 @@ main.registerCommand({ } }); } - if (buildmessage.jobHasMessages()) { + if (await buildmessage.jobHasMessages()) { return; } // Finish preparing the project. - projectContext.prepareProjectForBuild(); + await projectContext.prepareProjectForBuild(); } ); @@ -1954,10 +1982,10 @@ main.registerCommand({ var nonlatestDirectDeps = []; var nonlatestIndirectDeps = []; var deprecatedDeps = []; - projectContext.packageMap.eachPackage(function (name, info) { + await projectContext.packageMap.eachPackage(async function(name, info) { var selectedVersion = info.version; var catalog = projectContext.projectCatalog; - var latestVersion = getNewerVersion(name, selectedVersion, catalog); + var latestVersion = await getNewerVersion(name, selectedVersion, catalog); if (latestVersion) { var rec = { name: name, selectedVersion: selectedVersion, latestVersion: latestVersion }; @@ -2022,13 +2050,13 @@ main.registerCommand({ requiresApp: true, catalogRefresh: new catalog.Refresh.Never(), 'allow-incompatible-update': { type: Boolean } -}, function (options) { +}, async function (options) { var projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, allowIncompatibleUpdate: options['allow-incompatible-update'] }); - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", async function () { + await projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole(); @@ -2049,8 +2077,8 @@ main.registerCommand({ name: 'admin run-background-updater', hidden: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - updater.tryToDownloadUpdate({ +}, async function (options) { + await updater.tryToDownloadUpdate({ showBanner: true, printErrors: true }); @@ -2065,7 +2093,7 @@ main.registerCommand({ name: 'admin wipe-all-packages', hidden: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { tropohouse.default.wipeAllPackages(); }); @@ -2079,7 +2107,7 @@ main.registerCommand({ name: 'admin check-package-versions', hidden: true, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { if (!files.inCheckout()) { Console.error("Must run from checkout."); return 1; @@ -2095,10 +2123,9 @@ main.registerCommand({ // though this temporary directory does not have any cordova platforms forceIncludeCordovaUnibuild: true }); - // Read metadata and initialize catalog. - main.captureAndExit("=> Errors while building for release:", function () { - projectContext.initializeCatalog(); + await main.captureAndExit("=> Errors while building for release:", async function () { + await projectContext.initializeCatalog(); }); var allPackages = projectContext.localCatalog.getAllNonTestPackageNames(); @@ -2106,14 +2133,14 @@ main.registerCommand({ Console.info("Listing packages where the checkout version doesn't match the", "latest version on the package server."); - _.each(allPackages, function (packageName) { - var checkoutVersion = projectContext.localCatalog.getLatestVersion(packageName).version; - var remoteLatestVersion = catalog.official.getLatestVersion(packageName).version; + for (const packageName of allPackages) { + var checkout = projectContext.localCatalog.getLatestVersion(packageName); + var remote = await catalog.official.getLatestVersion(packageName); - if (checkoutVersion !== remoteLatestVersion) { - Console.info(packageName, checkoutVersion, remoteLatestVersion); + if (checkout.version !== remote.version) { + Console.info(packageName, checkout.version, remote.version); } - }); + } }); /////////////////////////////////////////////////////////////////////////////// @@ -2129,16 +2156,16 @@ main.registerCommand({ maxArgs: Infinity, requiresApp: true, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: true }) -}, function (options) { +}, async function (options) { var projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, allowIncompatibleUpdate: options["allow-incompatible-update"] }); - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", async function () { // We're just reading metadata here --- we're not going to resolve // constraints until after we've made our changes. - projectContext.initializeCatalog(); + return await projectContext.initializeCatalog(); }); let exitCode = 0; @@ -2176,8 +2203,8 @@ main.registerCommand({ changed && projectContext.cordovaPluginsFile.write(plugins); } - ensureDevBundleDependencies(); - cordovaPluginAdd(); + await ensureDevBundleDependencies(); + await cordovaPluginAdd(); } if (_.isEmpty(packagesToAdd)) { @@ -2192,9 +2219,9 @@ main.registerCommand({ // constraints. Don't run the constraint solver until you have added all of // them -- add should be an atomic operation regardless of the package // order. - var messages = buildmessage.capture(function () { - _.each(packagesToAdd, function (packageReq) { - buildmessage.enterJob("adding package " + packageReq, function () { + var messages = await buildmessage.capture(async function () { + for (const packageReq of packagesToAdd) { + await buildmessage.enterJob("adding package " + packageReq, async function () { var constraint = utils.parsePackageConstraint(packageReq, { useBuildmessage: true }); @@ -2204,40 +2231,40 @@ main.registerCommand({ // It's OK to make errors based on looking at the catalog, because this // is a OnceAtStart command. - var packageRecord = projectContext.projectCatalog.getPackage( - constraint.package); + var packageRecord = await projectContext.projectCatalog.getPackage( + constraint.package); if (! packageRecord) { buildmessage.error("no such package"); return; } - _.each(constraint.versionConstraint.alternatives, function (subConstr) { + for (const subConstr of constraint.versionConstraint.alternatives) { if (subConstr.versionString === null) { - return; + continue; } // Figure out if this version exists either in the official catalog or // the local catalog. (This isn't the same as using the combined // catalog, since it's OK to type "meteor add foo@1.0.0" if the local // package is 1.1.0 as long as 1.0.0 exists.) - var versionRecord = projectContext.localCatalog.getVersion( - constraint.package, subConstr.versionString); + var versionRecord = await projectContext.localCatalog.getVersion( + constraint.package, subConstr.versionString); if (! versionRecord) { // XXX #2846 here's an example of something that might require a // refresh - versionRecord = catalog.official.getVersion( - constraint.package, subConstr.versionString); + versionRecord = await catalog.official.getVersion( + constraint.package, subConstr.versionString); } if (! versionRecord) { buildmessage.error("no such version " + constraint.package + "@" + - subConstr.versionString); + subConstr.versionString); } - }); + } if (buildmessage.jobHasMessages()) { return; } var current = projectContext.projectConstraintsFile.getConstraint( - constraint.package); + constraint.package); // Check that the constraint is new. If we are already using the package // at the same constraint in the app, we will log an info message later @@ -2246,35 +2273,35 @@ main.registerCommand({ if (! current) { constraintsToAdd.push(constraint); } else if (! current.constraintString && - ! constraint.constraintString) { + ! constraint.constraintString) { infoMessages.push( - constraint.package + + constraint.package + " without a version constraint has already been added."); } else if (current.constraintString === constraint.constraintString) { infoMessages.push( - constraint.package + " with version constraint " + + constraint.package + " with version constraint " + constraint.constraintString + " has already been added."); } else { // We are changing an existing constraint. if (current.constraintString) { infoMessages.push( - "Currently using " + constraint.package + + "Currently using " + constraint.package + " with version constraint " + current.constraintString + "."); } else { infoMessages.push( - "Currently using " + constraint.package + + "Currently using " + constraint.package + " without any version constraint."); } if (constraint.constraintString) { infoMessages.push("The version constraint will be changed to " + - constraint.constraintString + "."); + constraint.constraintString + "."); } else { infoMessages.push("The version constraint will be removed."); } constraintsToAdd.push(constraint); } }); - }); + } }); if (messages.hasMessages()) { Console.arrowError("Errors while parsing arguments:", 1); @@ -2286,8 +2313,8 @@ main.registerCommand({ projectContext.projectConstraintsFile.addConstraints(constraintsToAdd); // Run the constraint solver, download packages, etc. - messages = buildmessage.capture(function () { - projectContext.prepareProjectForBuild(); + messages = await buildmessage.capture(function () { + return projectContext.prepareProjectForBuild(); }); if (messages.hasMessages()) { Console.arrowError("Errors while adding packages:", 1); @@ -2303,23 +2330,23 @@ main.registerCommand({ // Show descriptions of directly added packages. Console.info(); - _.each(constraintsToAdd, function (constraint) { + for (const constraint of constraintsToAdd) { var version = projectContext.packageMap.getInfo(constraint.package).version; - var versionRecord = projectContext.projectCatalog.getVersion( - constraint.package, version); - var deprecatedMessage = "" + var versionRecord = await projectContext.projectCatalog.getVersion( + constraint.package, version); + var deprecatedMessage = ""; if (versionRecord.deprecated) { if (versionRecord.deprecatedMessage) { deprecatedMessage = ` - DEPRECATED: ${versionRecord.deprecatedMessage}` } else { - deprecatedMessage = ' - DEPRECATED' + deprecatedMessage = ' - DEPRECATED'; } } Console.info( - constraint.package + + constraint.package + (versionRecord.description ? (": " + versionRecord.description) : "") + deprecatedMessage ); - }); + } return exitCode; }); @@ -2337,15 +2364,16 @@ main.registerCommand({ maxArgs: Infinity, requiresApp: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { var projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, allowIncompatibleUpdate: options["allow-incompatible-update"] }); - main.captureAndExit("=> Errors while initializing project:", function () { + + await main.captureAndExit("=> Errors while initializing project:", async function () { // We're just reading metadata here --- we're not going to resolve // constraints until after we've made our changes. - projectContext.readProjectMetadata(); + return await projectContext.readProjectMetadata(); }); let exitCode = 0; @@ -2383,7 +2411,7 @@ main.registerCommand({ changed && projectContext.cordovaPluginsFile.write(plugins); } - ensureDevBundleDependencies(); + await ensureDevBundleDependencies(); cordovaPluginRemove(); } @@ -2418,14 +2446,14 @@ main.registerCommand({ // Run the constraint solver, rebuild local packages, etc. This will write // our changes to .meteor/packages if it succeeds. - main.captureAndExit("=> Errors after removing packages", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors after removing packages", function () { + return projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole(); // Log that we removed the constraints. It is possible that there are // constraints that we officially removed that the project still 'depends' on, - // which is why we do this in addition to displaying the PackageMapDelta. + // which is why we do this in addition to dislpaying the PackageMapDelta. _.each(packagesToRemove, function (packageName) { Console.info(packageName + ": removed dependency"); }); @@ -2441,7 +2469,7 @@ main.registerCommand({ main.registerCommand({ name: 'refresh', catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { // We already did it! return 0; }); @@ -2466,7 +2494,7 @@ main.registerCommand({ list: { type: Boolean } }, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { var name = options.args[0]; // Yay, checking that options are correct. @@ -2483,12 +2511,12 @@ main.registerCommand({ } // Now let's get down to business! Fetching the thing. - var fullRecord = getReleaseOrPackageRecord(name); + var fullRecord = await getReleaseOrPackageRecord(name); var record = fullRecord.record; if (!options.list) { try { - var conn = packageClient.loggedInPackagesConnection(); + var conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; @@ -2498,19 +2526,19 @@ main.registerCommand({ if (options.add) { Console.info("Adding a maintainer to " + name + "..."); if (fullRecord.release) { - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'addReleaseMaintainer', name, options.add); } else { - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'addMaintainer', name, options.add); } } else if (options.remove) { Console.info("Removing a maintainer from " + name + "..."); if (fullRecord.release) { - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'removeReleaseMaintainer', name, options.remove); } else { - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'removeMaintainer', name, options.remove); } Console.info("Success."); @@ -2523,8 +2551,8 @@ main.registerCommand({ // Update the catalog so that we have this information, and find the record // again so that the message below is correct. - refreshOfficialCatalogOrDie(); - fullRecord = getReleaseOrPackageRecord(name); + await refreshOfficialCatalogOrDie(); + fullRecord = await getReleaseOrPackageRecord(name); record = fullRecord.record; } @@ -2569,7 +2597,7 @@ main.registerCommand({ // we assume that all packages have been published (along with the release // obviously) and we want to be sure to only bundle the published versions. catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { var releaseNameAndVersion = options.args[0]; // We get this as an argument, so it is an OS path. Make it a standard path. @@ -2579,7 +2607,7 @@ main.registerCommand({ var releaseTrack = trackAndVersion[0]; var releaseVersion = trackAndVersion[1]; - var releaseRecord = catalog.official.getReleaseVersion( + var releaseRecord = await catalog.official.getReleaseVersion( releaseTrack, releaseVersion); if (!releaseRecord) { // XXX this could also mean package unknown. @@ -2595,7 +2623,7 @@ main.registerCommand({ var toolPackage = toolPackageVersion.package; var toolVersion = toolPackageVersion.version; - var toolPkgBuilds = catalog.official.getAllBuilds( + var toolPkgBuilds = await catalog.official.getAllBuilds( toolPackage, toolVersion); if (!toolPkgBuilds) { // XXX this could also mean package unknown. @@ -2626,7 +2654,7 @@ main.registerCommand({ // check if the passed arch is in the list var arch = options['target-arch']; if (! osArches.includes(arch)) { - throw new Error( + throw new Error( arch + ": the arch is not available for the release. Available arches: " + osArches.join(', ')); } @@ -2640,19 +2668,19 @@ main.registerCommand({ // Before downloading anything, check that the catalog contains everything we // need for the OSes that the tool is built for. - main.captureAndExit("=> Errors finding builds:", function () { - _.each(osArches, function (osArch) { - _.each(releaseRecord.packages, function (pkgVersion, pkgName) { - buildmessage.enterJob({ + await main.captureAndExit("=> Errors finding builds:", async function () { + for (const osArch of osArches) { + for (const [pkgName, pkgVersion] of Object.entries(releaseRecord.packages)) { + await buildmessage.enterJob({ title: "looking up " + pkgName + "@" + pkgVersion + " on " + osArch - }, function () { - if (!catalog.official.getBuildsForArches(pkgName, pkgVersion, [osArch])) { + }, async function () { + if (!(await catalog.official.getBuildsForArches(pkgName, pkgVersion, [osArch]))) { buildmessage.error("missing build of " + pkgName + "@" + pkgVersion + " for " + osArch); } }); - }); - }); + } + } }); files.mkdir_p(outputDirectory); @@ -2662,11 +2690,11 @@ main.registerCommand({ var tmpDataFile = files.pathJoin(dataTmpdir, 'packages.data.db'); var tmpCatalog = new catalogRemote.RemoteCatalog(); - tmpCatalog.initialize({ + await tmpCatalog.initialize({ packageStorage: tmpDataFile }); try { - packageClient.updateServerPackageData(tmpCatalog, null); + await packageClient.updateServerPackageData(tmpCatalog, null); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 2; @@ -2676,8 +2704,8 @@ main.registerCommand({ // so we should ensure that once it is downloaded, it knows it is recommended // rather than having a little identity crisis and thinking that a past // release is the latest recommended until it manages to sync. - tmpCatalog.forceRecommendRelease(releaseTrack, releaseVersion); - tmpCatalog.closePermanently(); + await tmpCatalog.forceRecommendRelease(releaseTrack, releaseVersion); + await tmpCatalog.closePermanently(); if (files.exists(tmpDataFile + '-wal')) { throw Error("Write-ahead log still exists for " + tmpDataFile + " so the data file will be incomplete!"); @@ -2686,7 +2714,7 @@ main.registerCommand({ var packageMap = packageMapModule.PackageMap.fromReleaseVersion(releaseRecord); - _.each(osArches, function (osArch) { + for (const osArch of osArches) { var tmpdir = files.mkdtemp(); Console.info("Building tarball for " + osArch); @@ -2702,11 +2730,11 @@ main.registerCommand({ files.pathJoin(tmpdir, '.meteor'), { platform: targetPlatform }); - main.captureAndExit( + await main.captureAndExit( "=> Errors downloading packages for " + osArch + ":", - function () { - tmpTropo.downloadPackagesMissingFromMap(packageMap, { - serverArchitectures: [osArch] + async function () { + await tmpTropo.downloadPackagesMissingFromMap(packageMap, { + serverArchitectures: [osArch], }); } ); @@ -2724,26 +2752,26 @@ main.registerCommand({ var toolIsopackPath = tmpTropo.packagePath(toolPackage, toolVersion); var toolIsopack = new isopack.Isopack; - toolIsopack.initFromPath(toolPackage, toolIsopackPath); + await toolIsopack.initFromPath(toolPackage, toolIsopackPath); var toolRecord = _.findWhere(toolIsopack.toolsOnDisk, {arch: osArch}); if (!toolRecord) { throw Error("missing tool for " + osArch); } - tmpTropo.linkToLatestMeteor(files.pathJoin( + await tmpTropo.linkToLatestMeteor(files.pathJoin( tmpTropo.packagePath(toolPackage, toolVersion, true), toolRecord.path, 'meteor')); if (options.unpacked) { - files.cp_r(tmpTropo.root, outputDirectory); + await files.cp_r(tmpTropo.root, outputDirectory); } else { - files.createTarball( + await files.createTarball( tmpTropo.root, files.pathJoin(outputDirectory, 'meteor-bootstrap-' + osArch + '.tar.gz')); } - }); + } return 0; }); @@ -2755,7 +2783,7 @@ main.registerCommand({ maxArgs: 1, hidden: true, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { var bannersFile = options.args[0]; try { var bannersData = files.readFile(bannersFile, 'utf8'); @@ -2774,14 +2802,14 @@ main.registerCommand({ } try { - var conn = packageClient.loggedInPackagesConnection(); + var conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; } try { - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'setBannersOnReleases', bannersData.track, bannersData.banners); } catch (e) { @@ -2790,7 +2818,7 @@ main.registerCommand({ } // Refresh afterwards. - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); return 0; }); @@ -2802,7 +2830,7 @@ main.registerCommand({ unrecommend: { type: Boolean, short: "u" } }, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { // We want the most recent information. //refreshOfficialCatalogOrDie(); @@ -2815,7 +2843,7 @@ main.registerCommand({ } // Now let's get down to business! Fetching the thing. - var record = catalog.official.getReleaseTrack(name); + var record = await catalog.official.getReleaseTrack(name); if (!record) { Console.error(); Console.error('There is no release track named ' + name); @@ -2823,7 +2851,7 @@ main.registerCommand({ } try { - var conn = packageClient.loggedInPackagesConnection(); + var conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; @@ -2832,13 +2860,13 @@ main.registerCommand({ try { if (options.unrecommend) { Console.info("Unrecommending " + name + "@" + version + "..."); - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, 'unrecommendVersion', name, version); Console.info("Success."); Console.info(name + "@" + version, "is no longer a recommended release"); } else { Console.info("Recommending " + options.args[0] + "..."); - packageClient.callPackageServer(conn, 'recommendVersion', name, version); + await packageClient.callPackageServer(conn, 'recommendVersion', name, version); Console.info("Success."); Console.info(name + "@" + version, "is now a recommended release"); } @@ -2846,8 +2874,8 @@ main.registerCommand({ packageClient.handlePackageServerConnectionError(err); return 1; } - conn.close(); - refreshOfficialCatalogOrDie(); + await conn.close(); + await refreshOfficialCatalogOrDie(); return 0; }); @@ -2858,7 +2886,7 @@ main.registerCommand({ minArgs: 2, maxArgs: 2, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { // We want the most recent information. //refreshOfficialCatalogOrDie(); @@ -2866,7 +2894,7 @@ main.registerCommand({ var url = options.args[1]; // Now let's get down to business! Fetching the thing. - var record = catalog.official.getPackage(name); + var record = await catalog.official.getPackage(name); if (!record) { Console.error(); Console.error('There is no package named ' + name); @@ -2874,7 +2902,7 @@ main.registerCommand({ } try { - var conn = packageClient.loggedInPackagesConnection(); + var conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; @@ -2884,15 +2912,15 @@ main.registerCommand({ Console.rawInfo( "Changing homepage on " + name + " to " + url + "...\n"); - packageClient.callPackageServer(conn, - '_changePackageHomepage', name, url); + await packageClient.callPackageServer(conn, + '_changePackageHomepage', name, url); Console.info(" done"); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; } - conn.close(); - refreshOfficialCatalogOrDie(); + await conn.close(); + await refreshOfficialCatalogOrDie(); return 0; }); @@ -2906,7 +2934,7 @@ main.registerCommand({ }, hidden: true, catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { +}, async function (options) { // We don't care about having the most recent information, but we do want the // option to either unmigrate a specific version, or to unmigrate an entire @@ -2920,11 +2948,11 @@ main.registerCommand({ versions = [nSplit[1]]; name = nSplit[0]; } else { - versions = catalog.official.getSortedVersions(name); + versions = await catalog.official.getSortedVersions(name); } try { - var conn = packageClient.loggedInPackagesConnection(); + var conn = await packageClient.loggedInPackagesConnection(); } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; @@ -2933,22 +2961,22 @@ main.registerCommand({ try { var status = options.success ? "successfully" : "unsuccessfully"; // XXX: This should probably use progress bars instead. - _.each(versions, function (version) { + for (const version of versions) { Console.rawInfo( "Setting " + name + "@" + version + " as " + status + " migrated ...\n"); - packageClient.callPackageServer( + await packageClient.callPackageServer( conn, '_changeVersionMigrationStatus', name, version, !options.success); Console.info("done."); - }); + } } catch (err) { packageClient.handlePackageServerConnectionError(err); return 1; } conn.close(); - refreshOfficialCatalogOrDie(); + await refreshOfficialCatalogOrDie(); return 0; }); diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 1af6ed7a18..bb4bbea6cc 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -1,3 +1,5 @@ +import { getMeteorConfig } from "../tool-env/meteor-config"; + var main = require('./main.js'); var _ = require('underscore'); var files = require('../fs/files'); @@ -19,10 +21,104 @@ const { red, yellow } = require('../console/console.js').colors; +const inquirer = require('inquirer'); +const semver = require("semver"); + var projectContextModule = require('../project-context.js'); var release = require('../packaging/release.js'); const { Profile } = require("../tool-env/profile"); +const open = require('open') + +const { exec, spawn } = require("child_process"); +/** + * Run a command in the shell. + * @param command + * @return {Promise} + */ +const runCommand = async (command) => { + return new Promise((resolve, reject) => { + exec(command, { env: process.env }, (error, stdout) => { + if (error) { + console.log(red`error: ${ error.message }`); + reject(error); + return; + } + resolve(stdout); + }); + }) +} +/** + * + * @param {Promise<() => T>} fn + * @returns {Promise<[T, null]> | Promise<[null, Error]>} + */ +const tryRun = async (fn) => { + try { return [await fn(), null] } catch (e) { return [null, e] } +} + +/** + * + * @param {string} bash command + * @param {[string, null] | [null, Error]}} Result or Error + * @returns + */ +const bash = + (text, ...values) => + tryRun(() => runCommand(String.raw({ raw: text }, ...values))); + +/** + * Run a command in the shell and stream output in real-time. + * @param {string} command The command to execute. + * @param {string[]} args Arguments for the command. + * @return {Promise} Resolves with the exit code. + */ +const runLiveCommand = (command, args = []) => { + return new Promise((resolve, reject) => { + const childProcess = spawn(command, args, { + shell: true, + env: { ...process.env, FORCE_COLOR: "1", TERM: "xterm-256color" }, + stdio: "inherit", + }); + + const cleanup = () => { + childProcess.removeAllListeners(); + }; + + childProcess.on("close", (code) => { + cleanup(); + resolve(code); + }); + + childProcess.on("error", (error) => { + Console.error(error.message); + cleanup(); + reject(error); + }); + }); +}; + +/** + * Executes an async function and captures success or error. + * @param {() => Promise} fn The async function to execute. + * @returns {Promise<[T, null] | [null, Error]>} Result or Error tuple. + */ +const tryRunLive = async (fn) => { + try { + return [await fn(), null]; + } catch (e) { + return [null, e]; + } +}; + +/** + * Runs a Bash command with live logging. + * @param {string} text The bash command to execute. + * @param {...string} values Additional arguments. + * @returns {Promise<[number, null] | [null, Error]>} Exit code or Error. + */ +const bashLive = (text, ...values) => + tryRunLive(() => runLiveCommand(String.raw({ raw: text }, ...values))); import { ensureDevBundleDependencies } from '../cordova/index.js'; import { CordovaRunner } from '../cordova/runner.js'; @@ -167,13 +263,49 @@ export function parseRunTargets(targets) { }); }; -const excludableWebArchs = ['web.browser', 'web.browser.legacy', 'web.cordova']; -function filterWebArchs(webArchs, excludeArchsOption) { - if (excludeArchsOption) { - const excludeArchs = excludeArchsOption.trim().split(/\s*,\s*/) - .filter(arch => excludableWebArchs.includes(arch)); - webArchs = webArchs.filter(arch => !excludeArchs.includes(arch)); +function filterWebArchs(webArchs, excludeArchsOption, appDir, options) { + const platforms = (options.platforms || []); + const isBuildMode = platforms?.length > 0; + if (isBuildMode) { + // Build Mode + const isModernOnlyPlatform = platforms.includes('modern') && !platforms.includes('legacy'); + if (isModernOnlyPlatform) { + webArchs = webArchs.filter(arch => arch !== 'web.browser.legacy'); + } + const hasCordovaPlatforms = platforms.includes('android') || platforms.includes('ios'); + if (!hasCordovaPlatforms) { + webArchs = webArchs.filter(arch => arch !== 'web.cordova'); + } + } else { + // Dev & Test Mode + const isCordovaDev = (options.args || []).some(arg => ['ios', 'ios-device', 'android', 'android-device'].includes(arg)); + if (!isCordovaDev) { + const excludeArchsOptions = excludeArchsOption ? excludeArchsOption.trim().split(/\s*,\s*/) : []; + const hasExcludeArchsOptions = (excludeArchsOptions?.length || 0) > 0; + const hasModernArchsOnlyEnabled = appDir && getMeteorConfig()?.modern?.webArchOnly !== false; + if (hasExcludeArchsOptions && hasModernArchsOnlyEnabled) { + console.warn('modern.webArchOnly and --exclude-archs are both active. If both are set, --exclude-archs takes priority.'); + } + const automaticallyIgnoredLegacyArchs = (!hasExcludeArchsOptions && hasModernArchsOnlyEnabled) ? ['web.browser.legacy', 'web.cordova'] : []; + if (hasExcludeArchsOptions || automaticallyIgnoredLegacyArchs.length) { + const excludeArchs = [...excludeArchsOptions, ...automaticallyIgnoredLegacyArchs]; + webArchs = webArchs.filter(arch => !excludeArchs.includes(arch)); + } + } } + + const forcedInclArchs = process.env.METEOR_FORCE_INCLUDE_ARCHS; + if (forcedInclArchs != null) { + const nextInclArchs = forcedInclArchs.trim().split(/\s*,\s*/); + webArchs = Array.from(new Set([...webArchs, ...nextInclArchs])); + } + + const forcedExclArchs = process.env.METEOR_FORCE_EXCLUDE_ARCHS; + if (forcedExclArchs != null) { + const nextExclArchs = forcedExclArchs.trim().split(/\s*,\s*/); + webArchs = webArchs.filter(_webArch => !nextExclArchs.includes(_webArch)); + } + return webArchs; } @@ -187,7 +319,7 @@ main.registerCommand({ requiresRelease: false, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, function () { Console.rawInfo(archinfo.host() + "\n"); }); @@ -201,7 +333,7 @@ main.registerCommand({ requiresRelease: false, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (release.current === null) { if (! options.appDir) { throw new Error("missing release, but not in an app?"); @@ -215,9 +347,9 @@ main.registerCommand({ } if (release.current.isCheckout()) { - var gitLog = utils.runGitInCheckout( + var gitLog = (await utils.runGitInCheckout( 'log', - '--format=%h%d', '-n 1').trim(); + '--format=%h%d', '-n 1')).trim(); Console.error("Unreleased, running from a checkout at " + gitLog); return 1; } @@ -311,6 +443,7 @@ var runCommandOptions = { maxArgs: Infinity, options: { port: { type: String, short: "p", default: DEFAULT_PORT }, + open: { type: Boolean, short: "o", default: false }, 'mobile-server': { type: String }, 'cordova-server-port': { type: String }, 'app-port': { type: String }, @@ -318,7 +451,8 @@ var runCommandOptions = { ...inspectOptions, 'no-release-check': { type: Boolean }, production: { type: Boolean }, - 'raw-logs': { type: Boolean }, + 'raw-logs': { type: Boolean, default: true }, + timestamps: { type: Boolean, default: false }, // opposite of --raw-logs settings: { type: String, short: "s" }, verbose: { type: Boolean, short: "v" }, // With --once, meteor does not re-run the project if it crashes @@ -332,7 +466,7 @@ var runCommandOptions = { // of top-level dependencies. 'allow-incompatible-update': { type: Boolean }, 'extra-packages': { type: String }, - 'exclude-archs': { type: String } + 'exclude-archs': { type: String }, }, catalogRefresh: new catalog.Refresh.Never() }; @@ -342,7 +476,7 @@ main.registerCommand(Object.assign( runCommandOptions ), doRunCommand); -function doRunCommand(options) { +async function doRunCommand(options) { Console.setVerbose(!!options.verbose); // Additional args are interpreted as run targets @@ -363,10 +497,10 @@ function doRunCommand(options) { includePackages: includePackages, }); - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", function () { // We're just reading metadata here --- we'll wait to do the full build // preparation until after we've started listening on the proxy, etc. - projectContext.readProjectMetadata(); + return projectContext.readProjectMetadata(); }); if (release.explicit) { @@ -402,9 +536,7 @@ function doRunCommand(options) { ); } - if (options['raw-logs']) { - runLog.setRawLogs(true); - } + runLog.setRawLogs(options['raw-logs'] && !options.timestamps); let webArchs = projectContext.platformList.getWebArchs(); if (! _.isEmpty(runTargets) || @@ -413,31 +545,38 @@ function doRunCommand(options) { webArchs.push("web.cordova"); } } - webArchs = filterWebArchs(webArchs, options['exclude-archs']); - const buildMode = options.production ? 'production' : 'development' + + webArchs = filterWebArchs(webArchs, options['exclude-archs'], options.appDir, options); + // Set the webArchs to include for compilation later + global.includedWebArchs = webArchs; + + const buildMode = options.production ? 'production' : 'development'; let cordovaRunner; - if (!_.isEmpty(runTargets)) { + const shouldDisableCordova = Boolean(JSON.parse(process.env.METEOR_CORDOVA_DISABLE || 'false')); + if (!shouldDisableCordova && !_.isEmpty(runTargets)) { - function prepareCordovaProject() { + async function prepareCordovaProject() { import { CordovaProject } from '../cordova/project.js'; - main.captureAndExit('', 'preparing Cordova project', () => { + await main.captureAndExit('', 'preparing Cordova project', async () => { + // TODO -> Have to change CordovaProject constructor here. const cordovaProject = new CordovaProject(projectContext, { settingsFile: options.settings, mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), cordovaServerPort: parsedCordovaServerPort, buildMode }); + await cordovaProject.init(); if (buildmessage.jobHasMessages()) return; cordovaRunner = new CordovaRunner(cordovaProject, runTargets); - cordovaRunner.checkPlatformsForRunTargets(); + await cordovaRunner.checkPlatformsForRunTargets(); }); } - ensureDevBundleDependencies(); - prepareCordovaProject(); + await ensureDevBundleDependencies(); + await prepareCordovaProject(); } var runAll = require('../runners/run-all.js'); @@ -461,7 +600,19 @@ function doRunCommand(options) { cordovaServerPort: parsedCordovaServerPort, once: options.once, noReleaseCheck: options['no-release-check'] || process.env.METEOR_NO_RELEASE_CHECK, - cordovaRunner: cordovaRunner + cordovaRunner: cordovaRunner, + onBuilt: function () { + // Opens a browser window when it finishes building + if (options.open) { + console.log("=> Opening your app in a browser..."); + if (process.env.ROOT_URL) { + open(process.env.ROOT_URL) + } else { + open(`http://localhost:${options.port}`) + } + } + }, + open: options.open, }); } @@ -487,7 +638,7 @@ main.registerCommand({ requiresApp: true, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (!options.appDir) { Console.error( "The " + Console.command("'meteor shell'") + " command must be run", @@ -511,6 +662,31 @@ main.registerCommand({ /////////////////////////////////////////////////////////////////////////////// // create /////////////////////////////////////////////////////////////////////////////// + +/** + * list of all the available skeletons similar to the property below + * { + * clock: { repo: 'https://github.com/meteor/clock' }, + * leaderboard: { repo: 'https://github.com/meteor/leaderboard' }, + * } + * @typedef {Object.} Skeletons + */ +/** + * Resolves into json with + * @returns {Promise<[Skeletons, null]> | Promise<[null, Error]>} + */ +function getExamplesJSON(){ + return tryRun(async () => { + const response = await httpHelpers.request({ + url: "https://cdn.meteor.com/static/meteor.json", + method: "GET", + useSessionHeader: true, + useAuthHeader: true, + }); + return JSON.parse(response.body); + }); +} + const DEFAULT_SKELETON = "react"; export const AVAILABLE_SKELETONS = [ "apollo", @@ -521,16 +697,31 @@ export const AVAILABLE_SKELETONS = [ DEFAULT_SKELETON, "typescript", "vue", - 'vue-2', "svelte", "tailwind", "chakra-ui", "solid", ]; +const SKELETON_INFO = { + "apollo": "To create a basic Apollo + React app", + "bare": "To create an empty app", + "blaze": "To create an app using Blaze", + "full": "To create a more complete scaffolded app", + "minimal": "To create an app with as few Meteor packages as possible", + "react": "To create a basic React-based app", + "typescript": "To create an app using TypeScript and React", + "vue": "To create a basic Vue3-based app", + "svelte": "To create a basic Svelte app", + "tailwind": "To create an app using React and Tailwind", + "chakra-ui": "To create an app Chakra UI and React", + "solid": "To create a basic Solid app" +} + main.registerCommand({ name: 'create', maxArgs: 1, + minArgs: 0, options: { list: { type: Boolean }, example: { type: String }, @@ -541,17 +732,18 @@ main.registerCommand({ blaze: { type: Boolean }, react: { type: Boolean }, vue: { type: Boolean }, - 'vue-2': { type: Boolean }, typescript: { type: Boolean }, apollo: { type: Boolean }, svelte: { type: Boolean }, tailwind: { type: Boolean }, 'chakra-ui': { type: Boolean }, solid: { type: Boolean }, - prototype: { type: Boolean } + prototype: { type: Boolean }, + from: { type: String }, }, + pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { // Creating a package is much easier than creating an app, so if that's what // we are doing, do that first. (For example, we don't springboard to the // latest release to create a package if we are inside an app) @@ -559,24 +751,27 @@ main.registerCommand({ var packageName = options.args[0]; if (options.prototype) { Console.error( - `The ${Console.command('--prototype')} option is no longer supported for packages.` + `The ${Console.command( + "--prototype" + )} option is no longer supported for packages.` ); Console.error(); - throw new main.ShowUsage; + throw new main.ShowUsage(); } if (options.list || options.example) { Console.error("No package examples exist at this time."); Console.error(); - throw new main.ShowUsage; + throw new main.ShowUsage(); } if (!packageName) { Console.error("Please specify the name of the package."); - throw new main.ShowUsage; + throw new main.ShowUsage(); } - utils.validatePackageNameOrExit( - packageName, {detailedColonExplanation: true}); + utils.validatePackageNameOrExit(packageName, { + detailedColonExplanation: true, + }); // When we create a package, avoid introducing a colon into the file system // by naming the directory after the package name without the prefix. @@ -591,8 +786,9 @@ main.registerCommand({ // with at least two colons. Therefore we will at least try to // discourage people from putting a ton of colons in their package names // here. - Console.error(packageName + - ": Package names may not have more than one colon."); + Console.error( + packageName + ": Package names may not have more than one colon." + ); return 1; } @@ -601,7 +797,7 @@ main.registerCommand({ var packageDir; if (options.appDir) { - packageDir = files.pathResolve(options.appDir, 'packages', fsName); + packageDir = files.pathResolve(options.appDir, "packages", fsName); } else { packageDir = files.pathResolve(fsName); } @@ -613,9 +809,8 @@ main.registerCommand({ return 1; } - var transform = function (x) { - var xn = - x.replace(/~name~/g, packageName).replace(/~fs-name~/g, fsName); + var transform = async function (x) { + var xn = x.replace(/~name~/g, packageName).replace(/~fs-name~/g, fsName); // If we are running from checkout, comment out the line sourcing packages // from a release, with the latest release filled in (in case they do want @@ -624,12 +819,12 @@ main.registerCommand({ var relString; if (release.current.isCheckout()) { xn = xn.replace(/~cc~/g, "//"); - var rel = catalog.official.getDefaultReleaseVersion(); + var rel = await catalog.official.getDefaultReleaseVersion(); // the no-release case should never happen except in tests. relString = rel ? rel.version : "no-release"; } else { xn = xn.replace(/~cc~/g, ""); - relString = release.current.getDisplayName({noPrefix: true}); + relString = release.current.getDisplayName({ noPrefix: true }); } // If we are not in checkout, write the current release here. @@ -637,35 +832,37 @@ main.registerCommand({ }; try { - files.cp_r(files.pathJoin(__dirnameConverted, '..', 'static-assets', 'skel-pack'), packageDir, { - transformFilename: function (f) { - return transform(f); - }, - transformContents: function (contents, f) { - if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { - return Buffer.from(transform(contents.toString())); - } else { - return contents; - } - }, - ignore: [/^local$/], - preserveSymlinks: true, - }); + await files.cp_r( + files.pathJoin(__dirnameConverted, "..", "static-assets", "skel-pack"), + packageDir, + { + transformFilename: function (f) { + return transform(f); + }, + transformContents: async function (contents, f) { + if (/(\.html|\.[jt]sx?|\.css)/.test(f)) { + return Buffer.from(await transform(contents.toString())); + } else { + return contents; + } + }, + ignore: [/^local$/], + preserveSymlinks: true, + } + ); } catch (err) { Console.error("Could not create package: " + err.message); return 1; } - var displayPackageDir = - files.convertToOSPath(files.pathRelative(files.cwd(), packageDir)); + var displayPackageDir = files.convertToOSPath( + files.pathRelative(files.cwd(), packageDir) + ); // Since the directory can't have colons, the directory name will often not // match the name of the package exactly, therefore we should tell people // where it was created. - Console.info( - packageName + ": created in", - Console.path(displayPackageDir) - ); + Console.info(packageName + ": created in", Console.path(displayPackageDir)); return 0; } @@ -680,61 +877,100 @@ main.registerCommand({ // (In particular, it's not sufficient to create the new app with // this version of the tools, and then stamp on the correct release // at the end.) - if (! release.current.isCheckout() && !release.forced) { - if (release.current.name !== release.latestKnown()) { - throw new main.SpringboardToLatestRelease; + if (!release.current.isCheckout() && !release.forced) { + if (release.current.name !== (await release.latestKnown())) { + throw new main.SpringboardToLatestRelease(); } } if (options.list) { Console.info("Available examples:"); - _.each(EXAMPLE_REPOSITORIES, function (repoInfo, name) { - const branchInfo = repoInfo.branch ? `/tree/${repoInfo.branch}` : ''; + const [json, err] = await getExamplesJSON() + if (err) { + Console.error("Failed to fetch examples:", err.message); + Console.info("Using cached examples.json"); + } + const examples = err ? EXAMPLE_REPOSITORIES : json; + _.each(examples, function (repoInfo, name) { + const branchInfo = repoInfo.branch ? `/tree/${repoInfo.branch}` : ""; Console.info( Console.command(`${name}: ${repoInfo.repo}${branchInfo}`), - Console.options({ indent: 2 })); + Console.options({ indent: 2 }) + ); }); Console.info(); - Console.info("To create an example, simply", Console.command("git clone"), - "the relevant repository and branch (run", - Console.command("'meteor create --example '"), - " to see the full command)."); - return 0; - }; - - if (options.example) { - const repoInfo = EXAMPLE_REPOSITORIES[options.example]; - if (!repoInfo) { - Console.error(`${options.example}: no such example.`); - Console.error( - "List available applications with", - Console.command("'meteor create --list'") + "."); - return 1; - } - - const branchOption = repoInfo.branch ? ` -b ${repoInfo.branch}` : ''; - const path = options.args.length === 1 ? ` ${options.args[0]}` : ''; - - Console.info(`To create the ${options.example} example, please run:`); Console.info( - Console.command(`git clone ${repoInfo.repo}${branchOption}${path}`), - Console.options({ indent: 2 })); - + "To create an example, simply", + Console.command("'meteor create --example '") + ); return 0; } - var appPathAsEntered; - if (options.args.length === 1) { - appPathAsEntered = options.args[0]; - } else { - throw new main.ShowUsage; + /** + * + * @returns {{appPathAsEntered: string, skeleton: string }} + */ + const setup = async () => { + // meteor create app-name + if (options.args.length === 1) { + const appPathAsEntered = options.args[0]; + const skeletonExplicitOption = + AVAILABLE_SKELETONS.find(skeleton => !!options[skeleton]); + + const skeleton = skeletonExplicitOption || DEFAULT_SKELETON; + + console.log(`Using ${green`${skeleton}`} skeleton`); + return { + appPathAsEntered, + skeleton + } + } + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + const prompt = inquirer.createPromptModule(); + // meteor create + // need to ask app name and skeleton + const r = await prompt([ + { + type: 'input', + name: 'appPathAsEntered', + message: `What is the name/path of your ${yellow`app`}? `, + default(){ + return 'my-app'; + } + }, + { + type: 'list', + name: 'skeleton', + message: `Which ${yellow`skeleton`} do you want to use?`, + choices: AVAILABLE_SKELETONS.map(skeleton => {return `${capitalizeFirstLetter(skeleton)} # ${SKELETON_INFO[skeleton]}`}), + default(){ + return `${capitalizeFirstLetter(DEFAULT_SKELETON)} # ${SKELETON_INFO[DEFAULT_SKELETON]}`; + }, + filter(val) { + const skel = val.split(' ')[0]; + console.log(`Using ${green`${skel}`} skeleton`); + return skel.toLowerCase(); + } + } + ]) + return r; } + + var { + appPathAsEntered, + skeleton + } = await setup(); + Console.setPretty(true) // to not lose the console + var appPath = files.pathResolve(appPathAsEntered); if (files.findAppDir(appPath)) { Console.error( - "You can't create a Meteor project inside another Meteor project."); + "You can't create a Meteor project inside another Meteor project." + ); return 1; } @@ -746,48 +982,216 @@ main.registerCommand({ appName = files.pathBasename(appPath); } - var transform = function (x) { return x.replace(/~name~/g, appName); }; // These file extensions are usually metadata, not app code - var nonCodeFileExts = ['.txt', '.md', '.json', '.sh']; + var nonCodeFileExts = [".txt", ".md", ".json", ".sh"]; var destinationHasCodeFiles = false; // If the directory doesn't exist, it clearly doesn't have any source code // inside itself if (files.exists(appPath)) { - destinationHasCodeFiles = _.any(files.readdir(appPath), - function thisPathCountsAsAFile(filePath) { - // We don't mind if there are hidden files or directories (this includes - // .git) and we don't need to check for .meteor here because the command - // will fail earlier - var isHidden = /^\./.test(filePath); - if (isHidden) { - // Not code - return false; - } + destinationHasCodeFiles = _.any( + files.readdir(appPath), + function thisPathCountsAsAFile(filePath) { + // We don't mind if there are hidden files or directories (this includes + // .git) and we don't need to check for .meteor here because the command + // will fail earlier + var isHidden = /^\./.test(filePath); + if (isHidden) { + // Not code + return false; + } - // We do mind if there are non-hidden directories, because we don't want - // to recursively check everything to do some crazy heuristic to see if - // we should try to create an app. - var stats = files.stat(files.pathJoin(appPath, filePath)); - if (stats.isDirectory()) { - // Could contain code + // We do mind if there are non-hidden directories, because we don't want + // to recursively check everything to do some crazy heuristic to see if + // we should try to create an app. + var stats = files.stat(files.pathJoin(appPath, filePath)); + if (stats.isDirectory()) { + // Could contain code + return true; + } + + // Check against our file extension white list + var ext = files.pathExtname(filePath); + if (ext == "" || nonCodeFileExts.includes(ext)) { + return false; + } + + // Everything not matched above is considered to be possible source code return true; } - - // Check against our file extension white list - var ext = files.pathExtname(filePath); - if (ext == '' || nonCodeFileExts.includes(ext)) { - return false; - } - - // Everything not matched above is considered to be possible source code - return true; + ); + } + function cmd(text) { + Console.info( + Console.command(text), + Console.options({ + indent: 2, + }) + ); + } + // Setup fn, which is called after the app is created, to print a message + // about how to run the app. + async function setupMessages() { + // We are actually working with a new meteor project at this point, so + // set up its context. + var projectContext = new projectContextModule.ProjectContext({ + projectDir: appPath, + // Write .meteor/versions even if --release is specified. + alwaysWritePackageMap: true, + // examples come with a .meteor/versions file, but we shouldn't take it + // too seriously + allowIncompatibleUpdate: true, }); + await main.captureAndExit( + "=> Errors while creating your project", + async function () { + await projectContext.readProjectMetadata(); + if (buildmessage.jobHasMessages()) { + return; + } + + await projectContext.releaseFile.write( + release.current.isCheckout() ? "none" : release.current.name + ); + if (buildmessage.jobHasMessages()) { + return; + } + + // Also, write package version constraints from the current release + // If we are on a checkout, we don't need to do this as running from + // checkout still pins all package versions and if the user updates + // to a real release, the packages file will subsequently get updated + if (!release.current.isCheckout()) { + projectContext.projectConstraintsFile.updateReleaseConstraints( + release.current._manifest + ); + } + + // Any upgrader that is in this version of Meteor doesn't need to be run on + // this project. + var upgraders = require("../upgraders.js"); + projectContext.finishedUpgraders.appendUpgraders( + upgraders.allUpgraders() + ); + + await projectContext.prepareProjectForBuild(); + } + ); + // No need to display the PackageMapDelta here, since it would include all of + // the packages (or maybe an unpredictable subset based on what happens to be + // in the template's versions file). + + // Since some of the project skeletons include npm `devDependencies`, we need + // to make sure they're included when running `npm install`. + await require("./default-npm-deps.js").install(appPath, { + includeDevDependencies: true, + }); + + var appNameToDisplay = + appPathAsEntered === "." ? "current directory" : `'${appPathAsEntered}'`; + + var message = `Created a new Meteor app in ${appNameToDisplay}`; + + message += "."; + + Console.info(message + "\n"); + + // Print a nice message telling people we created their new app, and what to + // do next. + Console.info("To run your new app:"); + + + + if (appPathAsEntered !== ".") { + // Wrap the app path in quotes if it contains spaces + const appPathWithQuotesIfSpaces = + appPathAsEntered.indexOf(" ") === -1 + ? appPathAsEntered + : `'${appPathAsEntered}'`; + + // Don't tell people to 'cd .' + cmd("cd " + appPathWithQuotesIfSpaces); + } + + cmd("meteor"); + + Console.info(""); + Console.info( + "If you are new to Meteor, try some of the learning resources here:" + ); + Console.info( + Console.url("https://docs.meteor.com/"), + Console.options({ indent: 2 }) + ); + + Console.info(""); + Console.info( + "When you’re ready to deploy and host your new Meteor application, check out Cloud:" + ); + Console.info( + Console.url("https://galaxycloud.app/"), + Console.options({ indent: 2 }) + ); + + } + + /** + * + * @param {string} url + */ + const setupExampleByURL = async (url) => { + const [ok, err] = await bash`git --version`; + if (err) throw new Error("git is not installed"); + const isWindows = process.platform === "win32"; + + // Set GIT_TERMINAL_PROMPT=0 to disable prompting + process.env.GIT_TERMINAL_PROMPT = 0; + + const gitCommand = isWindows + ? `git clone --progress ${url} "${files.convertToOSPath(appPath)}"` + : `git clone --progress ${url} ${appPath}`; + const [okClone, errClone] = await bash`${gitCommand}`; + const errorMessage = errClone && typeof errClone === "string" ? errClone : errClone?.message; + if (errorMessage && errorMessage.includes("Cloning into")) { + throw new Error("error cloning skeleton"); + } + // remove .git folder from the example + await files.rm_recursive_async(files.pathJoin(appPath, ".git")); + await setupMessages(); + }; + + if (options.example) { + const [json, err] = await getExamplesJSON(); + + if (err) { + Console.error("Failed to fetch examples:", err.message); + Console.info("Using cached examples.json"); + } + + const examples = err ? EXAMPLE_REPOSITORIES : json; + const repoInfo = examples[options.example]; + if (!repoInfo) { + Console.error(`${options.example}: no such example.`); + Console.error( + "List available applications with", + Console.command("'meteor create --list'") + "." + ); + return 1; + } + // repoInfo.repo is the URL of the repo, and repoInfo.branch is the branch + await setupExampleByURL(repoInfo.repo); + return 0; + } + + + if (options.from) { + await setupExampleByURL(options.from); + return 0; } var toIgnore = [/^local$/, /^\.id$/]; @@ -797,156 +1201,85 @@ main.registerCommand({ toIgnore.push(/(\.html|\.js|\.css)/); } - const skeletonExplicitOption = AVAILABLE_SKELETONS.find(skeleton => - !!options[skeleton]); - const skeleton = skeletonExplicitOption || DEFAULT_SKELETON; - files.cp_r(files.pathJoin(__dirnameConverted, '..', 'static-assets', - `skel-${skeleton}`), appPath, { - transformFilename: function (f) { - return transform(f); - }, - transformContents: function (contents, f) { + const copyFromLocalSkeleton = async () => { + await files.cp_r( + skeletonPath, + appPath, + { + transformFilename: function (f) { + return transform(f); + }, + transformContents: function (contents, f) { + // check if this app is just for prototyping if it is then we need to add autopublish and insecure in the packages file + if (/packages/.test(f)) { + const prototypePackages = () => + "autopublish # Publish all data to the clients (for prototyping)\n" + + "insecure # Allow all DB writes from clients (for prototyping)"; - // check if this app is just for prototyping if it is then we need to add autopublish and insecure in the packages file - if ((/packages/).test(f)) { - - const prototypePackages = - () => - 'autopublish # Publish all data to the clients (for prototyping)\n' + - 'insecure # Allow all DB writes from clients (for prototyping)'; - - // XXX: if there is the need to add more options maybe we should have a better abstraction for this if-else - if (options.prototype) { - return Buffer.from(contents.toString().replace(/~prototype~/g, prototypePackages())) - } else { - return Buffer.from(contents.toString().replace(/~prototype~/g, '')) - } + // XXX: if there is the need to add more options maybe we should have a better abstraction for this if-else + if (options.prototype) { + return Buffer.from( + contents.toString().replace(/~prototype~/g, prototypePackages()) + ); + } else { + return Buffer.from(contents.toString().replace(/~prototype~/g, "")); + } + } + if (/(\.html|\.[jt]sx?|\.css)/.test(f)) { + return Buffer.from(transform(contents.toString())); + } else { + return contents; + } + }, + ignore: toIgnore, + preserveSymlinks: true, } - if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { - return Buffer.from(transform(contents.toString())); - } else { - return contents; - } - }, - ignore: toIgnore, - preserveSymlinks: true, - }); + ); + }; - // We are actually working with a new meteor project at this point, so - // set up its context. - var projectContext = new projectContextModule.ProjectContext({ - projectDir: appPath, - // Write .meteor/versions even if --release is specified. - alwaysWritePackageMap: true, - // examples come with a .meteor/versions file, but we shouldn't take it - // too seriously - allowIncompatibleUpdate: true - }); - - main.captureAndExit("=> Errors while creating your project", function () { - projectContext.readProjectMetadata(); - if (buildmessage.jobHasMessages()) { - return; - } - - projectContext.releaseFile.write( - release.current.isCheckout() ? "none" : release.current.name); - if (buildmessage.jobHasMessages()) { - return; - } - - // Also, write package version constraints from the current release - // If we are on a checkout, we don't need to do this as running from - // checkout still pins all package versions and if the user updates - // to a real release, the packages file will subsequently get updated - if (!release.current.isCheckout()) { - projectContext.projectConstraintsFile - .updateReleaseConstraints(release.current._manifest); - } - - // Any upgrader that is in this version of Meteor doesn't need to be run on - // this project. - var upgraders = require('../upgraders.js'); - projectContext.finishedUpgraders.appendUpgraders(upgraders.allUpgraders()); - - projectContext.prepareProjectForBuild(); - }); - // No need to display the PackageMapDelta here, since it would include all of - // the packages (or maybe an unpredictable subset based on what happens to be - // in the template's versions file). - - // Since some of the project skeletons include npm `devDependencies`, we need - // to make sure they're included when running `npm install`. - require("./default-npm-deps.js").install( - appPath, - { includeDevDependencies: true } + // Check if the local skeleton path exists + const skeletonPath = files.pathJoin( + __dirnameConverted, + "..", + "static-assets", + `skel-${skeleton}` ); - var appNameToDisplay = appPathAsEntered === "." ? - "current directory" : `'${appPathAsEntered}'`; + const useLocalSkeleton = files.exists(skeletonPath) || + options.prototype || + release.explicit; + if (useLocalSkeleton) { + // Use local skeleton + await copyFromLocalSkeleton(); + } else { + try { + // Prototype option should use local skeleton. + // Maybe we should use a different skeleton for prototype + if (options.prototype) throw new Error("Using prototype option"); + // if using the release option we should use the default skeleton + // using it as it was before 2.x + if (release.explicit) throw new Error("Using release option"); - var message = `Created a new Meteor app in ${appNameToDisplay}`; - - message += "."; - - Console.info(message + "\n"); - - // Print a nice message telling people we created their new app, and what to - // do next. - Console.info("To run your new app:"); - - function cmd(text) { - Console.info(Console.command(text), Console.options({ - indent: 2 - })); - } - - if (appPathAsEntered !== ".") { - // Wrap the app path in quotes if it contains spaces - const appPathWithQuotesIfSpaces = appPathAsEntered.indexOf(' ') === -1 ? - appPathAsEntered : - `'${appPathAsEntered}'`; - - // Don't tell people to 'cd .' - cmd("cd " + appPathWithQuotesIfSpaces); - } - - cmd("meteor"); - - Console.info(""); - Console.info("If you are new to Meteor, try some of the learning resources here:"); - Console.info( - Console.url("https://www.meteor.com/tutorials"), - Console.options({ indent: 2 })); - - Console.info(""); - Console.info("When you’re ready to deploy and host your new Meteor application, check out Cloud:"); - Console.info( - Console.url("https://www.meteor.com/cloud"), - Console.options({ indent: 2 })); - - if (!!skeletonExplicitOption) { - // Notify people about the skeleton options - Console.info([ - "", - "To start with a different app template, try one of the following:", - "", - ].join("\n")); - - cmd("meteor create --bare # to create an empty app"); - cmd("meteor create --minimal # to create an app with as few Meteor packages as possible"); - cmd("meteor create --full # to create a more complete scaffolded app"); - cmd("meteor create --react # to create a basic React-based app"); - cmd("meteor create --vue # to create a basic Vue3-based app"); - cmd("meteor create --vue-2 # to create a basic Vue2-based app"); - cmd("meteor create --apollo # to create a basic Apollo + React app"); - cmd("meteor create --svelte # to create a basic Svelte app"); - cmd("meteor create --typescript # to create an app using TypeScript and React"); - cmd("meteor create --blaze # to create an app using Blaze"); - cmd("meteor create --tailwind # to create an app using React and Tailwind"); - cmd("meteor create --chakra-ui # to create an app Chakra UI and React"); - cmd("meteor create --solid # to create a basic Solid app"); + // If local skeleton doesn't exist, use setupExampleByURL + await setupExampleByURL(`https://github.com/meteor/skel-${skeleton}`); + } catch (e) { + if ( + e.message !== "Using prototype option" && + e.message !== "Using release option" + ) { + // something has happened while creating the app using git clone + Console.error( + `Something has happened while creating your app using git clone. + Will use cached version of skeletons. + Error message: `, + e.message + ); + } + // For prototype or release options, use local skeleton + await copyFromLocalSkeleton(); + } } + await setupMessages(); Console.info(""); }); @@ -983,9 +1316,9 @@ main.registerCommand({ name: "build", ...buildCommands, }, async function (options) { - return Profile.run( + return await Profile.run( "meteor build", - () => Promise.await(buildCommand(options)) + async () => await buildCommand(options) ); }); @@ -1006,16 +1339,16 @@ main.registerCommand({ "for more information."); Console.error(); - return Profile.run( + return await Profile.run( "meteor bundle", - () => Promise.await(buildCommand({ + async () => await buildCommand({ ...options, _bundleOnly: true, - })) + }) ); }); -var buildCommand = function (options) { +var buildCommand = async function (options) { Console.setVerbose(!!options.verbose); if (options.headless) { // There's no point in spinning the spinner when we're running @@ -1044,10 +1377,10 @@ var buildCommand = function (options) { allowIncompatibleUpdate: options['allow-incompatible-update'] }); - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", function () { // TODO Fix the nested Profile.run warning here, without interfering // with METEOR_PROFILE output for other commands, like `meteor run`. - projectContext.prepareProjectForBuild(); + return projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole(); @@ -1066,7 +1399,7 @@ var buildCommand = function (options) { let selectedPlatforms = null; if (options.platforms) { const platformsArray = options.platforms.split(","); - + const excludableWebArchs = ['web.browser', 'web.browser.legacy', 'web.cordova']; platformsArray.forEach(plat => { if (![...excludableWebArchs, 'android', 'ios'].includes(plat)) { throw new Error(`Not allowed platform on '--platforms' flag: ${plat}`) @@ -1113,9 +1446,9 @@ on an OS X system."); // For example, if we want to build only android, there is no need to build // web.browser. let webArchs; + const baseWebArchs = projectContext.platformList.getWebArchs(); if (selectedPlatforms) { - const filteredArchs = projectContext.platformList - .getWebArchs() + const filteredArchs = baseWebArchs .filter(arch => selectedPlatforms.includes(arch)); if ( @@ -1126,6 +1459,11 @@ on an OS X system."); } webArchs = filteredArchs.length ? filteredArchs : undefined; + } else { + webArchs = filterWebArchs(baseWebArchs, options['exclude-archs'], options.appDir, { + ...options, + platforms: projectContext.platformList.getPlatforms(), + }); } var buildDir = projectContext.getProjectLocalDirectory('build_tar'); @@ -1156,7 +1494,7 @@ ${Console.command("meteor build ../output")}`, }); var bundler = require('../isobuild/bundler.js'); - var bundleResult = bundler.bundle({ + var bundleResult = await bundler.bundle({ projectContext: projectContext, outputPath: bundlePath, buildOptions: { @@ -1182,15 +1520,15 @@ ${Console.command("meteor build ../output")}`, } if (!options.directory) { - main.captureAndExit('', 'creating server tarball', () => { + await main.captureAndExit('', 'creating server tarball', async () => { try { var outputTar = options._bundleOnly ? outputPath : files.pathJoin(outputPath, appName + '.tar.gz'); - files.createTarball(files.pathJoin(buildDir, 'bundle'), outputTar); + await files.createTarball(files.pathJoin(buildDir, 'bundle'), outputTar); } catch (err) { buildmessage.exception(err); - files.rm_recursive(buildDir); + await files.rm_recursive(buildDir); } }); } @@ -1198,34 +1536,35 @@ ${Console.command("meteor build ../output")}`, if (!_.isEmpty(cordovaPlatforms)) { let cordovaProject; - main.captureAndExit('', () => { + await main.captureAndExit('', async () => { import { pluginVersionsFromStarManifest, displayNameForPlatform, } from '../cordova/index.js'; - ensureDevBundleDependencies(); + await ensureDevBundleDependencies(); - buildmessage.enterJob({ title: "preparing Cordova project" }, () => { + await buildmessage.enterJob({ title: "preparing Cordova project" }, async() => { import { CordovaProject } from '../cordova/project.js'; cordovaProject = new CordovaProject(projectContext, { settingsFile: options.settings, mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), cordovaServerPort: parsedCordovaServerPort }); + await cordovaProject.init(); if (buildmessage.jobHasMessages()) return; const pluginVersions = pluginVersionsFromStarManifest( bundleResult.starManifest); - cordovaProject.prepareFromAppBundle(bundlePath, pluginVersions); + await cordovaProject.prepareFromAppBundle(bundlePath, pluginVersions); }); for (platform of cordovaPlatforms) { - buildmessage.enterJob( + await buildmessage.enterJob( { title: `building Cordova app for \ -${displayNameForPlatform(platform)}` }, () => { +${displayNameForPlatform(platform)}` }, async () => { let buildOptions = { release: !options.debug }; const buildPath = files.pathJoin( @@ -1238,13 +1577,13 @@ ${displayNameForPlatform(platform)}` }, () => { // is utilized in the Cordova builder to write boilerplate HTML and // various config.xml settings (e.g. access policies) if (platform === 'ios') { - cordovaProject.prepareForPlatform(platform, buildOptions); + await cordovaProject.prepareForPlatform(platform, buildOptions); } else if (platform === 'android') { - cordovaProject.buildForPlatform(platform, {...buildOptions, argv: ["--packageType", options.packageType || "bundle"]}); + await cordovaProject.buildForPlatform(platform, {...buildOptions, argv: ["--packageType", options.packageType || "bundle"]}); } // Once prepared, copy the bundle to the final location. - files.cp_r(buildPath, + await files.cp_r(buildPath, files.pathJoin(platformOutputPath, 'project')); // Make some platform-specific adjustments to the resulting build. @@ -1263,7 +1602,7 @@ https://guide.meteor.com/cordova.html#submitting-ios const apkPath = files.pathJoin(buildPath, `app/build/outputs/${packageType}/${options.debug ? 'debug' : 'release'}`, options.debug ? `app-debug.${packageExtension}` : `${packageName}.${packageExtension}`); - console.log(apkPath) + console.log(apkPath); if (files.exists(apkPath)) { files.copyFile(apkPath, files.pathJoin(platformOutputPath, options.debug ? `app-debug.${packageExtension}` : `${packageName}.${packageExtension}`)); @@ -1282,7 +1621,12 @@ https://guide.meteor.com/cordova.html#submitting-android }); } - files.rm_recursive(buildDir); + await files.rm_recursive_deferred(buildDir); + + const npmShrinkwrapFilePath = files.pathJoin(bundlePath, 'programs/server/npm-shrinkwrap.json'); + if (files.exists(npmShrinkwrapFilePath)) { + files.chmod(npmShrinkwrapFilePath, 0o644); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -1301,8 +1645,8 @@ main.registerCommand({ 'allow-incompatible-updates': { type: Boolean } }, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - const {packageDir, appDir} = options; +}, async function (options) { + const { packageDir, appDir } = options; let projectContext = null; @@ -1320,10 +1664,11 @@ main.registerCommand({ lintPackageWithSourceRoot: packageDir }); - main.captureAndExit("=> Errors while setting up package:", () => + await main.captureAndExit("=> Errors while setting up package:", // Read metadata and initialize catalog. - projectContext.initializeCatalog() + async () => await projectContext.initializeCatalog() ); + const versionRecord = projectContext.localCatalog.getVersionBySourceRoot(packageDir); if (! versionRecord) { @@ -1346,12 +1691,12 @@ main.registerCommand({ } - main.captureAndExit("=> Errors prevented the build:", () => { - projectContext.prepareProjectForBuild(); - }); + await main.captureAndExit("=> Errors prevented the build:", async () => + await projectContext.prepareProjectForBuild() + ); - const bundler = require('../isobuild/bundler.js'); - const bundle = bundler.bundle({ + const bundler = await require('../isobuild/bundler.js'); + const bundle = await bundler.bundle({ projectContext: projectContext, outputPath: null, buildOptions: { @@ -1371,7 +1716,7 @@ main.registerCommand({ Console.warn(bundle.warnings.formatMessages()); return 1; } - + console.log(green`=> Done linting.`); return 0; }); @@ -1391,7 +1736,7 @@ main.registerCommand({ }, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { var mongoUrl; var usedMeteorAccount = false; @@ -1399,7 +1744,7 @@ main.registerCommand({ // localhost mode var findMongoPort = require('../runners/run-mongo.js').findMongoPort; - var mongoPort = findMongoPort(files.pathJoin(options.appDir, ".meteor", "local", "db")); + var mongoPort = await findMongoPort(files.pathJoin(options.appDir, ".meteor", "local", "db")); // XXX detect the case where Meteor is running, but MONGO_URL was // specified? @@ -1425,7 +1770,7 @@ to this command.`); // remote mode var site = qualifySitename(options.args[0]); - mongoUrl = deploy.temporaryMongoUrl(site); + mongoUrl = await deploy.temporaryMongoUrl(site); usedMeteorAccount = true; if (!mongoUrl) { @@ -1437,11 +1782,11 @@ to this command.`); console.log(`${yellow`$`} ${ purple`mongosh` } ${ blue(mongoUrl) }`); } else { if (usedMeteorAccount) { - auth.maybePrintRegistrationLink(); + await auth.maybePrintRegistrationLink(); } process.stdin.pause(); var runMongo = require('../runners/run-mongo.js'); - runMongo.runMongoShell(mongoUrl, + await runMongo.runMongoShell(mongoUrl, (err) => { console.log(red`Some error occured while trying to run mongosh.`); console.log(yellow`Check bellow for some more info:`); @@ -1467,7 +1812,7 @@ to this command.`); process.exit(1); }); - throw new main.WaitForExit; + throw new main.WaitForExit(); } }); @@ -1480,11 +1825,19 @@ main.registerCommand({ // Doesn't actually take an argument, but we want to print an custom // error message if they try to pass one. maxArgs: 1, + options: { + db: { type: Boolean }, + 'skip-cache': { type: Boolean }, + }, requiresApp: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (options.args.length !== 0) { - Console.error("meteor reset only affects the locally stored database."); + Console.error("'meteor reset' command only affects the local project cache."); + Console.error(); + Console.error("To remove also the local database use"); + Console.error( + Console.command("meteor reset --db"), Console.options({ indent: 2 })); Console.error(); Console.error("To reset a deployed application use"); Console.error( @@ -1501,24 +1854,50 @@ main.registerCommand({ "MONGO_URL will NOT be reset."); } - // XXX detect the case where Meteor is running the app, but - // MONGO_URL was set, so we don't see a Mongo process - var findMongoPort = require('../runners/run-mongo.js').findMongoPort; - var isRunning = !! findMongoPort(files.pathJoin(options.appDir, ".meteor", "local", "db")); - if (isRunning) { - Console.error("reset: Meteor is running."); - Console.error(); - Console.error( - "This command does not work while Meteor is running your application.", - "Exit the running Meteor development server."); - return 1; + const resetMeteorNmCachePromise = options['skip-cache'] ? Promise.resolve() : files.rm_recursive_async( + files.pathJoin(options.appDir, "node_modules", ".cache", "meteor") + ); + + if (options.db) { + // XXX detect the case where Meteor is running the app, but + // MONGO_URL was set, so we don't see a Mongo process + var findMongoPort = require('../runners/run-mongo.js').findMongoPort; + var isRunning = !! await findMongoPort(files.pathJoin(options.appDir, ".meteor", "local", "db")); + if (isRunning) { + Console.error("reset: Meteor is running."); + Console.error(); + Console.error( + "This command does not work while Meteor is running your application.", + "Exit the running Meteor development server."); + return 1; + } + + await Promise.all([ + files.rm_recursive_async( + files.pathJoin(options.appDir, ".meteor", "local") + ), + resetMeteorNmCachePromise, + ]); + + Console.info("Project reset."); + return; } - return files.rm_recursive_async( - files.pathJoin(options.appDir, '.meteor', 'local') - ).then(() => { - Console.info("Project reset."); + var allExceptDb = files.getPathsInDir(files.pathJoin('.meteor', 'local'), { + cwd: options.appDir, + maxDepth: 1, + }).filter(function (path) { + return !path.includes('.meteor/local/db'); }); + + var allRemovePromises = [ + ...allExceptDb.map((_path) => + files.rm_recursive_async(files.pathJoin(options.appDir, _path)) + ), + resetMeteorNmCachePromise + ]; + await Promise.all(allRemovePromises); + Console.info("Project reset."); }); /////////////////////////////////////////////////////////////////////////////// @@ -1563,17 +1942,17 @@ main.registerCommand({ }, catalogRefresh: new catalog.Refresh.Never() }, async function (...args) { - return Profile.run( + return await Profile.run( "meteor deploy", - () => Promise.await(deployCommand(...args)) + async () => await deployCommand(...args) ); }); -function deployCommand(options, { rawOptions }) { +async function deployCommand(options, { rawOptions }) { const site = options.args[0]; if (options.delete) { - return deploy.deleteApp(site); + return await deploy.deleteApp(site); } if (options.password) { @@ -1590,7 +1969,8 @@ function deployCommand(options, { rawOptions }) { Console.error( "You must be logged in to deploy, just enter your email address."); Console.error(); - if (! auth.registerOrLogIn()) { + const isRegistered = await auth.registerOrLogIn(); + if (! isRegistered) { return 1; } } @@ -1603,18 +1983,17 @@ function deployCommand(options, { rawOptions }) { "OVERRIDING DEPLOY ARCHITECTURE WITH LOCAL ARCHITECTURE.", "If your app contains binary code, it may break in unexpected " + "and terrible ways."); - buildArch = archinfo.host(); + buildArch = archinfo.host(); } const projectContext = new projectContextModule.ProjectContext({ projectDir: options.appDir, - serverArchitectures: _.uniq([buildArch, archinfo.host()]), + serverArchitectures: _.uniq([buildArch, archinfo.host()]), allowIncompatibleUpdate: options['allow-incompatible-update'] }); - - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", function () { // TODO Fix nested Profile.run warning here, too. - projectContext.prepareProjectForBuild(); + return projectContext.prepareProjectForBuild(); }); projectContext.packageMapDelta.displayOnConsole(); @@ -1641,7 +2020,7 @@ function deployCommand(options, { rawOptions }) { const isBuildOnly = !!options['build-only']; const waitForDeploy = !options['no-wait']; - const deployResult = deploy.bundleAndDeploy({ + const deployResult = await deploy.bundleAndDeploy({ projectContext, site, settingsFile: options.settings, @@ -1660,12 +2039,12 @@ function deployCommand(options, { rawOptions }) { }); if (deployResult === 0) { - auth.maybePrintRegistrationLink({ + await auth.maybePrintRegistrationLink({ leadingNewline: true, // If the user was already logged in at the beginning of the // deploy, then they've already been prompted to set a password // at least once before, so we use a slightly different message. - firstTime: ! loggedIn + firstTime: !loggedIn }); } @@ -1692,7 +2071,7 @@ main.registerCommand({ return options.add || options.remove || options.transfer; }, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (Object.keys(_.pick(options, 'add', 'remove', 'transfer', 'list')).length > 1) { Console.error( @@ -1700,7 +2079,7 @@ main.registerCommand({ return 1; } - auth.pollForRegistrationCompletion(); + await auth.pollForRegistrationCompletion(); var site = qualifySitename(options.args[0]); if (! auth.isLoggedIn()) { @@ -1711,13 +2090,13 @@ main.registerCommand({ } if (options.add) { - return deploy.changeAuthorized(site, "add", options.add); + return await deploy.changeAuthorized(site, "add", options.add); } else if (options.remove) { - return deploy.changeAuthorized(site, "remove", options.remove); + return await deploy.changeAuthorized(site, "remove", options.remove); } else if (options.transfer) { - return deploy.changeAuthorized(site, "transfer", options.transfer); + return await deploy.changeAuthorized(site, "transfer", options.transfer); } else { - return deploy.listAuthorized(site); + return await deploy.listAuthorized(site); } }); @@ -1730,6 +2109,7 @@ testCommandOptions = { catalogRefresh: new catalog.Refresh.Never(), options: { port: { type: String, short: "p", default: DEFAULT_PORT }, + open: { type: Boolean, short: "o", default: false }, 'mobile-server': { type: String }, 'cordova-server-port': { type: String }, 'debug-port': { type: String }, @@ -1743,7 +2123,8 @@ testCommandOptions = { // like progress bars and spinners are unimportant. headless: { type: Boolean }, verbose: { type: Boolean, short: "v" }, - 'raw-logs': { type: Boolean }, + 'raw-logs': { type: Boolean, default: true }, + timestamps: { type: Boolean, default: false }, // opposite of --raw-logs // Undocumented. See #Once once: { type: Boolean }, @@ -1793,7 +2174,10 @@ testCommandOptions = { 'extra-packages': { type: String }, - 'exclude-archs': { type: String } + 'exclude-archs': { type: String }, + + // Same as TINYTEST_FILTER + filter: { type: String, short: 'f' }, } }; @@ -1813,10 +2197,13 @@ main.registerCommand(Object.assign( return doTestCommand(options); }); -function doTestCommand(options) { +async function doTestCommand(options) { + if (options.filter) { + process.env.TINYTEST_FILTER = options.filter; + } // This "metadata" is accessed in a few places. Using a global // variable here was more expedient than navigating the many layers - // of abstraction across the the build process. + // of abstraction across the build process. // // As long as the Meteor CLI runs a single command as part of each // process, this should be safe. @@ -1866,14 +2253,14 @@ function doTestCommand(options) { // Download packages for our architecture, and for the deploy server's // architecture if we're deploying. - var serverArchitectures = [archinfo.host()]; - if (options.deploy && DEPLOY_ARCH !== archinfo.host()) { + const archInfoHost = archinfo.host(); + var serverArchitectures = [archInfoHost]; + if (options.deploy && DEPLOY_ARCH !== archInfoHost) { serverArchitectures.push(DEPLOY_ARCH); } - if (options['raw-logs']) { - runLog.setRawLogs(true); - } + runLog.setRawLogs(options['raw-logs'] && !options.timestamps); + var includePackages = []; if (options['extra-packages']) { @@ -1904,7 +2291,8 @@ function doTestCommand(options) { projectContextOptions.projectDirForLocalPackages = options.appDir; try { - require("./default-npm-deps.js").install(testRunnerAppDir); + const { install } = require("./default-npm-deps.js"); + await install(testRunnerAppDir); } catch (error) { if (error.code === 'EACCES' && options['test-app-path']) { Console.error( @@ -1935,22 +2323,22 @@ function doTestCommand(options) { // isopack cache that's specific to test-packages? See #3012. projectContext = new projectContextModule.ProjectContext(projectContextOptions); - main.captureAndExit("=> Errors while initializing project:", function () { + await main.captureAndExit("=> Errors while initializing project:", function () { // We're just reading metadata here --- we'll wait to do the full build // preparation until after we've started listening on the proxy, etc. - projectContext.readProjectMetadata(); + return projectContext.readProjectMetadata(); }); - main.captureAndExit("=> Errors while setting up tests:", function () { + await main.captureAndExit("=> Errors while setting up tests:", function () { // Read metadata and initialize catalog. - projectContext.initializeCatalog(); + return projectContext.initializeCatalog(); }); // Overwrite .meteor/release. - projectContext.releaseFile.write( + await projectContext.releaseFile.write( release.current.isCheckout() ? "none" : release.current.name); - var packagesToAdd = getTestPackageNames(projectContext, options.args); + var packagesToAdd = await getTestPackageNames(projectContext, options.args); // filter out excluded packages var excludedPackages = options.exclude && options.exclude.split(','); @@ -1984,7 +2372,7 @@ function doTestCommand(options) { // Write these changes to disk now, so that if the first attempt to prepare // the project for build hits errors, we don't lose them on // projectContext.reset. - projectContext.projectConstraintsFile.writeIfModified(); + await projectContext.projectConstraintsFile.writeIfModified(); } else if (options["test"]) { if (!options['driver-package']) { throw new Error("You must specify a driver package with --driver-package"); @@ -1999,7 +2387,7 @@ function doTestCommand(options) { projectContextOptions.projectLocalDir = files.pathJoin(testRunnerAppDir, '.meteor', 'local'); // Copy the existing build and isopacks to speed up the initial start - function copyDirIntoTestRunnerApp(allowSymlink, ...parts) { + async function copyDirIntoTestRunnerApp(allowSymlink, ...parts) { // Depending on whether the user has run `meteor run` or other commands, they // may or may not exist yet const appDirPath = files.pathJoin(options.appDir, ...parts); @@ -2013,23 +2401,23 @@ function doTestCommand(options) { // privileges since both paths refer to directories. files.symlink(appDirPath, testDirPath, "junction"); } else { - files.cp_r(appDirPath, testDirPath, { + await files.cp_r(appDirPath, testDirPath, { preserveSymlinks: true }); } } - copyDirIntoTestRunnerApp(false, '.meteor', 'local', 'build'); - copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'bundler-cache'); - copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'isopacks'); - copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'plugin-cache'); - copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'shell'); + await copyDirIntoTestRunnerApp(false, '.meteor', 'local', 'build'); + await copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'bundler-cache'); + await copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'isopacks'); + await copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'plugin-cache'); + await copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'shell'); projectContext = new projectContextModule.ProjectContext(projectContextOptions); - main.captureAndExit("=> Errors while setting up tests:", function () { + await main.captureAndExit("=> Errors while setting up tests:", async function () { // Read metadata and initialize catalog. - projectContext.initializeCatalog(); + return await projectContext.initializeCatalog(); }); } else { throw new Error("Unexpected: neither test-packages nor test"); @@ -2041,30 +2429,33 @@ function doTestCommand(options) { let cordovaRunner; + // TODO [FIBERS] -> Check cordova if (!_.isEmpty(runTargets)) { function prepareCordovaProject() { - main.captureAndExit('', 'preparing Cordova project', () => { + return main.captureAndExit('', 'preparing Cordova project', async () => { import { CordovaProject } from '../cordova/project.js'; const cordovaProject = new CordovaProject(projectContext, { settingsFile: options.settings, mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), cordovaServerPort: parsedCordovaServerPort }); + await cordovaProject.init(); + if (buildmessage.jobHasMessages()) return; cordovaRunner = new CordovaRunner(cordovaProject, runTargets); - projectContext.platformList.write(cordovaRunner.platformsForRunTargets); - cordovaRunner.checkPlatformsForRunTargets(); + await projectContext.platformList.write(cordovaRunner.platformsForRunTargets); + await cordovaRunner.checkPlatformsForRunTargets(); }); } - ensureDevBundleDependencies(); - prepareCordovaProject(); + await ensureDevBundleDependencies(); + await prepareCordovaProject(); } options.cordovaRunner = cordovaRunner; - return runTestAppForPackages(projectContext, Object.assign( + return await runTestAppForPackages(projectContext, Object.assign( options, { mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), @@ -2077,27 +2468,27 @@ function doTestCommand(options) { // Returns the "local-test:*" package names for the given package names (or for // all local packages if packageNames is empty/unspecified). -var getTestPackageNames = function (projectContext, packageNames) { +var getTestPackageNames = async function (projectContext, packageNames) { var packageNamesSpecifiedExplicitly = ! _.isEmpty(packageNames); if (_.isEmpty(packageNames)) { // If none specified, test all local packages. (We don't have tests for // non-local packages.) - packageNames = projectContext.localCatalog.getAllPackageNames(); + packageNames = await projectContext.localCatalog.getAllPackageNames(); } var testPackages = []; - main.captureAndExit("=> Errors while collecting tests:", function () { - _.each(packageNames, function (p) { - buildmessage.enterJob("trying to test package `" + p + "`", function () { + await main.captureAndExit("=> Errors while collecting tests:", async function () { + for (const p of packageNames) { + await buildmessage.enterJob("trying to test package `" + p + "`", async function () { // If it's a package name, look it up the normal way. if (p.indexOf('/') === -1) { if (p.indexOf('@') !== -1) { buildmessage.error( - "You may not specify versions for local packages: " + p ); + "You may not specify versions for local packages: " + p ); return; // recover by ignoring } // Check to see if this is a real local package, and if it is a real // local package, if it has tests. - var version = projectContext.localCatalog.getLatestVersion(p); + var version = await projectContext.localCatalog.getLatestVersion(p); if (! version) { buildmessage.error("Not a known local package, cannot test"); } else if (version.testName) { @@ -2111,7 +2502,7 @@ var getTestPackageNames = function (projectContext, packageNames) { } else { // Otherwise, it's a directory; find it by source root. version = projectContext.localCatalog.getVersionBySourceRoot( - files.pathResolve(p)); + files.pathResolve(p)); if (! version) { buildmessage.error("Package not found in local catalog"); return; @@ -2125,13 +2516,13 @@ var getTestPackageNames = function (projectContext, packageNames) { // packages that don't have tests. } }); - }); + } }); return testPackages; }; -var runTestAppForPackages = function (projectContext, options) { +var runTestAppForPackages = async function (projectContext, options) { var buildOptions = { minifyMode: options.production ? 'production' : 'development' }; @@ -2140,12 +2531,14 @@ var runTestAppForPackages = function (projectContext, options) { if (options.cordovaRunner) { webArchs.push("web.cordova"); } - buildOptions.webArchs = filterWebArchs(webArchs, options['exclude-archs']); + buildOptions.webArchs = filterWebArchs(webArchs, options['exclude-archs'], projectContext.appDirectory, options); + // Set the webArchs to include for compilation later + global.includedWebArchs = buildOptions.webArchs; if (options.deploy) { // Run the constraint solver and build local packages. - main.captureAndExit("=> Errors while initializing project:", function () { - projectContext.prepareProjectForBuild(); + await main.captureAndExit("=> Errors while initializing project:", function () { + return projectContext.prepareProjectForBuild(); }); // No need to display the PackageMapDelta here, since it would include all // of the packages! @@ -2183,7 +2576,18 @@ var runTestAppForPackages = function (projectContext, options) { // On the first run, we shouldn't display the delta between "no packages // in the temp app" and "all the packages we're testing". If we make // changes and reload, though, it's fine to display them. - omitPackageMapDeltaDisplayOnFirstRun: true + omitPackageMapDeltaDisplayOnFirstRun: true, + onBuilt: function () { + // Opens a browser window when it finishes building + if (options.open) { + console.log("=> Opening your app in a browser..."); + if (process.env.ROOT_URL) { + open(process.env.ROOT_URL) + } else { + open(`http://localhost:${options.port}`) + } + } + } }); } }; @@ -2227,7 +2631,7 @@ main.registerCommand({ email: { type: Boolean } }, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, function (options) { return auth.loginCommand(Object.assign({ overwriteExistingToken: true }, options)); @@ -2262,23 +2666,23 @@ main.registerCommand({ // organizations /////////////////////////////////////////////////////////////////////////////// -var loggedInAccountsConnectionOrPrompt = function (action) { +var loggedInAccountsConnectionOrPrompt = async function (action) { var token = auth.getSessionToken(config.getAccountsDomain()); if (! token) { Console.error("You must be logged in to " + action + "."); - auth.doUsernamePasswordLogin({ retry: true }); + await auth.doUsernamePasswordLogin({ retry: true }); Console.info(); } token = auth.getSessionToken(config.getAccountsDomain()); - var conn = auth.loggedInAccountsConnection(token); + var conn = await auth.loggedInAccountsConnection(token); if (conn === null) { // Server rejected our token. Console.error("You must be logged in to " + action + "."); - auth.doUsernamePasswordLogin({ retry: true }); + await auth.doUsernamePasswordLogin({ retry: true }); Console.info(); token = auth.getSessionToken(config.getAccountsDomain()); - conn = auth.loggedInAccountsConnection(token); + conn = await auth.loggedInAccountsConnection(token); } return conn; @@ -2291,18 +2695,18 @@ main.registerCommand({ maxArgs: 0, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { var token = auth.getSessionToken(config.getAccountsDomain()); if (! token) { Console.error("You must be logged in to list your organizations."); - auth.doUsernamePasswordLogin({ retry: true }); + await auth.doUsernamePasswordLogin({ retry: true }); Console.info(); } var url = config.getAccountsApiUrl() + "/organizations"; try { - var result = httpHelpers.request({ + var result = await httpHelpers.request({ url: url, method: "GET", useSessionHeader: true, @@ -2351,7 +2755,7 @@ main.registerCommand({ return options.add || options.remove; }, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (options.add && options.remove) { Console.error( @@ -2361,13 +2765,13 @@ main.registerCommand({ var username = options.add || options.remove; - var conn = loggedInAccountsConnectionOrPrompt( + var conn = await loggedInAccountsConnectionOrPrompt( username ? "edit organizations" : "show an organization's members"); if (username ) { // Adding or removing members try { - conn.call( + await conn.callAsync( options.add ? "addOrganizationMember": "removeOrganizationMember", options.args[0], username); } catch (err) { @@ -2383,7 +2787,7 @@ main.registerCommand({ } else { // Showing the members of an org try { - var result = conn.call("showOrganization", options.args[0]); + var result = await conn.callAsync("showOrganization", options.args[0]); } catch (err) { Console.error("Error showing organization: " + err.reason); return 1; @@ -2438,7 +2842,7 @@ main.registerCommand({ }, hidden: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { +}, async function (options) { if (! files.inCheckout()) { Console.error("self-test is only supported running from a checkout"); return 1; @@ -2450,7 +2854,7 @@ main.registerCommand({ var offline = false; if (!options['force-online']) { try { - require('../utils/http-helpers.js').getUrl("http://www.google.com/"); + await require('../utils/http-helpers.js').getUrl("http://www.google.com/"); } catch (e) { if (e instanceof files.OfflineError) { offline = true; @@ -2495,7 +2899,7 @@ main.registerCommand({ } if (options.list) { - selftest.listTests({ + await selftest.listTests({ onlyChanged: options.changed, offline: offline, includeSlowTests: options.slow, @@ -2554,8 +2958,8 @@ main.registerCommand({ maxArgs: 0, pretty: false, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - auth.pollForRegistrationCompletion(); +}, async function (options) { + await auth.pollForRegistrationCompletion(); if (! auth.isLoggedIn()) { Console.error( "You must be logged in for that. Try " + @@ -2807,7 +3211,7 @@ main.registerCommand({ throw new main.ExitWithCode(2); } - files.cp_r(assetsPath(), files.pathResolve(scaffoldPath), { + await files.cp_r(assetsPath(), files.pathResolve(scaffoldPath), { transformFilename: function (f) { if (options.replaceFn) return userTransformFilenameFn(f); return transformName(f); @@ -2909,8 +3313,9 @@ main.registerCommand({ }, hidden: true, catalogRefresh: new catalog.Refresh.Never() -}, function (options) { - buildmessage.enterJob({ title: "A test progressbar" }, function () { +}, async function (options) { + await buildmessage.enterJob({ title: "A test progressbar" }, async function () { + var progress = buildmessage.getCurrentProgressTracker(); var totalProgress = { current: 0, end: options.secs, done: false }; var i = 0; @@ -2920,7 +3325,7 @@ main.registerCommand({ totalProgress.end = undefined; } - new Promise(function (resolve) { + await new Promise(function (resolve) { function updateProgress() { i++; if (! options.spinner) { @@ -2938,7 +3343,7 @@ main.registerCommand({ } setTimeout(updateProgress); - }).await(); + }) }); }); @@ -2995,3 +3400,129 @@ main.registerCommand({ }, function () { throw new Error("testing stack traces!"); // #StackTraceTest this line is found in tests/source-maps.js }); + +const setupBenchmarkSuite = async (profilingPath) => { + if (await files.exists(profilingPath)) { + return; + } + + // Check git availability and version + const [okGitVersion, errGitVersion] = await bash`git --version`; + if (errGitVersion) throw new Error("git is not installed"); + + const parsedGitVersion = semver.coerce(okGitVersion.match(/\d+\.\d+\.\d+/)?.[0] || '')?.version; + if (!parsedGitVersion || semver.lt(parsedGitVersion, '2.25.0')) { + throw new Error("git version is too old. Please upgrade to at least 2.25"); + } + + // Check tar availability + const [okTar, errTar] = await bash`tar --version`; + const hasTar = !errTar; + + // Disable interactive git prompts + process.env.GIT_TERMINAL_PROMPT = 0; + + const repoUrl = "https://github.com/meteor/performance"; + const branch = "v3.3.0"; + + let tarFailed = false; + + // If tar is available, prefer tar-based extraction + if (hasTar) { + const tempDir = "/tmp/meteor-performance-benchmark-suite"; + const tarCommand = [ + `rm -rf ${tempDir}`, + `git clone --no-checkout --depth 1 --filter=tree:0 --sparse --progress --branch ${branch} --single-branch ${repoUrl} ${tempDir}`, + `cd ${tempDir}`, + `git sparse-checkout init --cone`, + `git sparse-checkout set scripts`, + `git checkout ${branch}`, + `mkdir -p ${profilingPath}/scripts`, + `tar -czf /tmp/scripts.tar.gz -C ./scripts .`, + `tar -xzf /tmp/scripts.tar.gz -C ${profilingPath}/scripts`, + `rm -rf ${tempDir}`, + `rm -f /tmp/scripts.tar.gz` + ].join(" && "); + + const [okTarClone, errTarClone] = await bash`${tarCommand}`; + if (!errTarClone) { + Console.info("Meteor profiling suite cloned to: " + Console.path(profilingPath)); + return; + } else { + Console.warn("Tar-based cloning failed. Will attempt standard git clone..."); + tarFailed = errTarClone; + } + } else { + Console.warn("Tar not available. Will use standard git clone..."); + } + + // Fallback to plain git clone + const gitCommand = [ + `mkdir -p ${profilingPath}`, + `git clone --no-checkout --depth 1 --filter=tree:0 --sparse --progress --branch ${branch} --single-branch ${repoUrl} ${profilingPath}`, + `cd ${profilingPath}`, + `git sparse-checkout init --cone`, + `git sparse-checkout set scripts`, + `git checkout ${branch}`, + `find ${profilingPath} -maxdepth 1 -type f -delete` + ].join(" && "); + + const [okClone, errClone] = await bash`${gitCommand}`; + if (errClone) { + let combinedMessage = "Git clone failed."; + if (tarFailed) { + combinedMessage = `Tar-based cloning also failed:\n${tarFailed}\n\nGit fallback failed:\n${errClone}`; + } + throw new Error(combinedMessage); + } + + // Remove .git folder if present + await files.rm_recursive_async(files.pathJoin(profilingPath, ".git")); + + Console.info("Meteor profiling suite cloned to: " + Console.path(profilingPath)); +}; + +async function doBenchmarkCommand(options) { + const isWindows = process.platform === "win32"; + if (isWindows) { + throw new Error('Profiling is not supported on Windows'); + } + + const args = process.argv.slice(3); + var projectContext = new projectContextModule.ProjectContext({ + projectDir: options.appDir, + allowIncompatibleUpdate: options['allow-incompatible-update'], + lintAppAndLocalPackages: !options['no-lint'], + }); + const profilingPath = `${projectContext.projectDir}/node_modules/.cache/meteor/performance`; + await setupBenchmarkSuite(profilingPath); + + const meteorSizeEnvs = [ + !!options['size-only'] && 'METEOR_BUNDLE_SIZE_ONLY=true', + !!options['size'] && 'METEOR_BUNDLE_SIZE=true', + !!options['build'] && 'METEOR_BUNDLE_BUILD=true', + ].filter(Boolean); + const meteorOptions = args.filter(arg => !['--size-only', '--size', '--build'].includes(arg)); + + const profilingCommand = [ + `${meteorSizeEnvs.join(' ')} ${profilingPath}/scripts/monitor-bundler.sh ${projectContext.projectDir} ${new Date().getTime()} ${meteorOptions.join(' ')}`.trim(), + ].join(" && "); + const [, errBenchmark] = await bashLive`${profilingCommand}`; + if (errBenchmark) { + throw new Error(errBenchmark); + } +} + +main.registerCommand( +{ + name: 'profile', + maxArgs: Infinity, + options: { + ...buildCommands.options || {}, + ...runCommandOptions.options || {}, + 'size': { type: Boolean }, + 'size-only': { type: Boolean }, + 'build': { type: Boolean }, + }, + catalogRefresh: new catalog.Refresh.Never(), +}, doBenchmarkCommand); diff --git a/tools/cli/default-npm-deps.js b/tools/cli/default-npm-deps.js index 28dfe2e0f3..ea92f40695 100644 --- a/tools/cli/default-npm-deps.js +++ b/tools/cli/default-npm-deps.js @@ -8,7 +8,7 @@ import { const INSTALL_JOB_MESSAGE = "installing npm dependencies"; -export function install(appDir, options) { +export async function install(appDir, options) { const packageJsonPath = pathJoin(appDir, "package.json"); const needTempPackageJson = ! statOrNull(packageJsonPath); @@ -25,14 +25,14 @@ export function install(appDir, options) { ); } - const ok = buildmessage.enterJob(INSTALL_JOB_MESSAGE, function () { + const ok = await buildmessage.enterJob(INSTALL_JOB_MESSAGE, async function () { const npmCommand = ["install"]; if (options && options.includeDevDependencies) { npmCommand.push("--production=false"); } const { runNpmCommand } = require("../isobuild/meteor-npm.js"); - const installResult = runNpmCommand(npmCommand, appDir); + const installResult = await runNpmCommand(npmCommand, appDir); if (! installResult.success) { buildmessage.error( "Could not install npm dependencies for test-packages: " + diff --git a/tools/cli/dev-bundle-bin-commands.js b/tools/cli/dev-bundle-bin-commands.js index ddf0419a44..d7f0722ce8 100644 --- a/tools/cli/dev-bundle-bin-commands.js +++ b/tools/cli/dev-bundle-bin-commands.js @@ -4,44 +4,48 @@ // The dev_bundle/bin command has to come immediately after the meteor // command, as in `meteor npm` or `meteor node`, because we don't want to // require("./main.js") for these commands. -var devBundleBinCommand = process.argv[2]; -var args = process.argv.slice(3); +const { getDevBundleDir, DEFAULT_DEV_BUNDLE_DIR } = require('./dev-bundle'); +const { getEnv } = require('./dev-bundle-bin-helpers'); +const devBundleBinCommand = process.argv[2]; +const args = process.argv.slice(3); -function getChildProcess() { +async function getChildProcess({ isFirstTry }) { if (typeof devBundleBinCommand !== "string") { return Promise.resolve(null); } - var helpers = require("./dev-bundle-bin-helpers.js"); + const helpers = require("./dev-bundle-bin-helpers"); - return Promise.all([ - helpers.getDevBundle(), - helpers.getEnv() - ]).then(function (devBundleAndEnv) { - var devBundleDir = devBundleAndEnv[0]; - var cmd = helpers.getCommand(devBundleBinCommand, devBundleDir); - if (! cmd) { - return null; - } + const [devBundleDir, env] = await Promise.all([ + getDevBundleDir(), + getEnv() + ]); - var env = devBundleAndEnv[1]; - var child = require("child_process").spawn(cmd, args, { - stdio: "inherit", - env: env - }); + if (isFirstTry && devBundleDir === DEFAULT_DEV_BUNDLE_DIR) { + return null + } - require("./flush-buffers-on-exit-in-windows.js"); + const cmd = helpers.getCommand(devBundleBinCommand, devBundleDir); - child.on("error", function (error) { - console.log(error.stack || error); - }); + if (!cmd) { + return null; + } - child.on("exit", function (exitCode) { - process.exit(exitCode); - }); - - return child; + const child = require('child_process').spawn(cmd, args, { + stdio: 'inherit', + env: env, + shell: process.platform === 'win32' && ['.cmd', '.bat'].some(_extension => cmd.endsWith(_extension)), }); + require("./flush-buffers-on-exit-in-windows"); + child.on("error", function (error) { + console.log(error.stack || error); + }); + child.on("exit", function (exitCode) { + process.exit(exitCode); + }); + return child; } -module.exports = getChildProcess(); +module.exports = { + getChildProcess +} diff --git a/tools/cli/dev-bundle-bin-helpers.js b/tools/cli/dev-bundle-bin-helpers.js index 1854cb3e04..cdbcf11f6e 100644 --- a/tools/cli/dev-bundle-bin-helpers.js +++ b/tools/cli/dev-bundle-bin-helpers.js @@ -1,18 +1,19 @@ const fs = require("fs"); const path = require("path"); const { convertToOSPath } = require("./convert-to-os-path.js"); +const { getDevBundleDir } = require('./dev-bundle'); -var isWindows = process.platform === "win32"; -var extensions = isWindows ? [".cmd", ".exe"] : [""]; -var hasOwn = Object.prototype.hasOwnProperty; +const isWindows = process.platform === "win32"; +const extensions = isWindows ? [".cmd", ".exe"] : [""]; +const hasOwn = Object.prototype.hasOwnProperty; -function getDevBundle() { - return require("./dev-bundle.js"); +module.exports = { + getCommand, + getEnv, } -exports.getDevBundle = getDevBundle; -exports.getCommand = function (name, devBundleDir) { - var result = null; +function getCommand (name, devBundleDir) { + let result = null; // Strip leading and/or trailing whitespace. name = name.replace(/^\s+|\s+$/g, ""); @@ -22,7 +23,7 @@ exports.getCommand = function (name, devBundleDir) { } extensions.some(function (ext) { - var cmd = path.join(devBundleDir, "bin", name + ext); + const cmd = path.join(devBundleDir, "bin", name + ext); try { if (fs.statSync(cmd).isFile()) { result = cmd; @@ -48,7 +49,7 @@ function isValidCommand(name, devBundleDir) { return false; } - var meteorCommandsJsonPath = + const meteorCommandsJsonPath = path.join(devBundleDir, "bin", ".meteor-commands.json"); try { @@ -62,64 +63,61 @@ function isValidCommand(name, devBundleDir) { return ! hasOwn.call(meteorCommands, name); } -exports.getEnv = function (options) { - var devBundle = options && options.devBundle; - var devBundlePromise = typeof devBundle === "string" - ? Promise.resolve(convertToOSPath(devBundle)) - : getDevBundle(); +async function getEnv(options) { + const devBundle = options && options.devBundle; - return devBundlePromise.then(function (devBundleDir) { - var paths = [ - // When npm looks for node, it must find dev_bundle/bin/node. - path.join(devBundleDir, "bin"), + /** + * @type string + */ + const devBundleDir = typeof devBundle === "string" + ? await convertToOSPath(devBundle) + : await getDevBundleDir(); - // When npm looks for meteor, it should find dev_bundle/../meteor. - path.dirname(devBundleDir), + const paths = [ + // When npm looks for node, it must find dev_bundle/bin/node. + path.join(devBundleDir, "bin"), - // Also make available any scripts installed by packages in - // dev_bundle/lib/node_modules, such as node-gyp. - path.join(devBundleDir, "lib", "node_modules", ".bin") - ]; + // When npm looks for meteor, it should find dev_bundle/../meteor. + path.dirname(devBundleDir), - var env = Object.create(process.env); + // Also make available any scripts installed by packages in + // dev_bundle/lib/node_modules, such as node-gyp. + path.join(devBundleDir, "lib", "node_modules", ".bin") + ]; - // Make sure notifications to update npm aren't presented to the user. - env.NO_UPDATE_NOTIFIER = true; + const env = Object.create(process.env); + env.NO_UPDATE_NOTIFIER = true; - // Make sure `meteor npm install --global ...` installs into - // dev_bundle/lib/node_modules by default. - if (! env.NPM_CONFIG_PREFIX) { - env.NPM_CONFIG_PREFIX = devBundleDir; - } + if (!env.NPM_CONFIG_PREFIX) { + env.NPM_CONFIG_PREFIX = devBundleDir; + } - if (env.METEOR_ALLOW_SUPERUSER) { - // Note that env.METEOR_ALLOW_SUPERUSER could be "0" or "false", which - // should propagate falsy semantics to NPM_CONFIG_UNSAFE_PERM. - env.NPM_CONFIG_UNSAFE_PERM = env.METEOR_ALLOW_SUPERUSER; - } + if (env.METEOR_ALLOW_SUPERUSER) { + // Note that env.METEOR_ALLOW_SUPERUSER could be "0" or "false", which + // should propagate falsy semantics to NPM_CONFIG_UNSAFE_PERM. + env.NPM_CONFIG_UNSAFE_PERM = env.METEOR_ALLOW_SUPERUSER; + } - // This allows node-gyp to find Node headers and libraries in - // dev_bundle/include/node. - env.NPM_CONFIG_NODEDIR = devBundleDir; + env.NPM_CONFIG_NODEDIR = devBundleDir; - var PATH = env.PATH || env.Path; - if (PATH) { - paths.push(PATH); - } + const PATH = env.PATH || env.Path; - env.PATH = paths.join(path.delimiter); + if (PATH) { + paths.push(PATH); + } - if (process.platform === "win32") { - return addWindowsVariables(devBundleDir, env); - } + env.PATH = paths.join(path.delimiter); - return env; - }); -}; + if (process.platform === "win32") { + return addWindowsVariables(devBundleDir, env); + } + + return env; +} // Caching env.GYP_MSVS_VERSION allows us to avoid invoking Python every // time Meteor runs an npm command. TODO Store this on disk? -var cachedMSVSVersion; +let cachedMSVSVersion; function addWindowsVariables(devBundleDir, env) { // On Windows we provide a reliable version of python.exe for use by @@ -143,11 +141,11 @@ function addWindowsVariables(devBundleDir, env) { // If $GYP_MSVS_VERSION was not provided, use the gyp Python library to // infer it, or default to 2015 if that doesn't work. return new Promise(function (resolve) { - var nodeGypPylibDir = path.join( + const nodeGypPylibDir = path.join( devBundleDir, "lib", "node_modules", "node-gyp", "gyp", "pylib" ); - var child = require("child_process").spawn(env.PYTHON, ["-c", [ + const child = require("child_process").spawn(env.PYTHON, ["-c", [ "from gyp.MSVSVersion import SelectVisualStudioVersion", "try:", " print SelectVisualStudioVersion(allow_fallback=False).short_name", @@ -158,7 +156,7 @@ function addWindowsVariables(devBundleDir, env) { stdio: "pipe" }); - var chunks = []; + const chunks = []; child.stdout.on("data", function (chunk) { chunks.push(chunk); }); diff --git a/tools/cli/dev-bundle-helpers.js b/tools/cli/dev-bundle-helpers.js index eafcffe932..1d4249480e 100644 --- a/tools/cli/dev-bundle-helpers.js +++ b/tools/cli/dev-bundle-helpers.js @@ -1,7 +1,7 @@ import { pathJoin, getDevBundle, statOrNull } from '../fs/files'; import { installNpmModule } from '../isobuild/meteor-npm.js'; -export function ensureDependencies(deps) { +export async function ensureDependencies(deps) { const devBundleLib = pathJoin(getDevBundle(), 'lib'); const devBundleNodeModules = pathJoin(devBundleLib, 'node_modules'); @@ -19,7 +19,7 @@ export function ensureDependencies(deps) { }); // Install each of the requested modules. - Object.keys(needToInstall).forEach(dep => { - installNpmModule(dep, needToInstall[dep], devBundleLib); - }); + for (const dep of Object.keys(needToInstall)) { + await installNpmModule(dep, needToInstall[dep], devBundleLib); + } } diff --git a/tools/cli/dev-bundle.js b/tools/cli/dev-bundle.js index a89946e73e..5a60eff3a8 100644 --- a/tools/cli/dev-bundle.js +++ b/tools/cli/dev-bundle.js @@ -5,75 +5,73 @@ // but that's unavoidable if we don't want to install Babel and load all // the rest of the code every time we run `meteor npm` or `meteor node`. -var fs = require("fs"); -var path = require("path"); -var links = require("./dev-bundle-links.js"); -var rootDir = path.resolve(__dirname, "..", ".."); -var defaultDevBundlePromise = - Promise.resolve(path.join(rootDir, "dev_bundle")); +const fs = require("fs"); +const path = require("path"); +const links = require("./dev-bundle-links.js"); +const rootDir = path.resolve(__dirname, "..", ".."); -function getDevBundleDir() { +const DEFAULT_DEV_BUNDLE_DIR = path.join(rootDir, "dev_bundle"); + +async function getDevBundleDir() { // Note that this code does not care if we are running meteor from a // checkout, because it's always better to respect the .meteor/release // file of the current app, if possible. - var releaseFile = find( + const releaseFile = find( process.cwd(), makeStatTest("isFile"), ".meteor", "release" ); if (! releaseFile) { - return defaultDevBundlePromise; + return DEFAULT_DEV_BUNDLE_DIR; } - var localDir = path.join(path.dirname(releaseFile), "local"); + const localDir = path.join(path.dirname(releaseFile), "local"); if (! statOrNull(localDir, "isDirectory")) { try { fs.mkdirSync(localDir); } catch (e) { - return defaultDevBundlePromise; + return DEFAULT_DEV_BUNDLE_DIR; } } - var devBundleLink = path.join(localDir, "dev_bundle"); - var devBundleStat = statOrNull(devBundleLink); + const devBundleLink = path.join(localDir, "dev_bundle"); + const devBundleStat = statOrNull(devBundleLink); if (devBundleStat) { return new Promise(function (resolve) { resolve(links.readLink(devBundleLink)); }); } - var release = fs.readFileSync( + const release = fs.readFileSync( releaseFile, "utf8" ).replace(/^\s+|\s+$/g, ""); if (! /^METEOR@\d+/.test(release)) { - return defaultDevBundlePromise; + return DEFAULT_DEV_BUNDLE_DIR; } - return Promise.resolve( - getDevBundleForRelease(release) - ).then(function (devBundleDir) { - if (devBundleDir) { - links.makeLink(devBundleDir, devBundleLink); - return devBundleDir; - } + const devBundleDir = await getDevBundleForRelease(release); - return defaultDevBundlePromise; - }); + if (devBundleDir) { + links.makeLink(devBundleDir, devBundleLink); + return devBundleDir; + } + + return DEFAULT_DEV_BUNDLE_DIR; } function getDevBundleForRelease(release) { - var parts = release.split("@"); + const parts = release.split("@"); if (parts.length < 2) { return null; } - var track = parts[0]; - var version = parts.slice(1).join("@"); + const track = parts[0]; + const version = parts.slice(1).join("@"); - var packageMetadataDir = find( + const packageMetadataDir = find( rootDir, makeStatTest("isDirectory"), ".meteor", "package-metadata" @@ -83,29 +81,29 @@ function getDevBundleForRelease(release) { return null; } - var meteorToolDir = path.resolve( + const meteorToolDir = path.resolve( packageMetadataDir, "..", "packages", "meteor-tool" ); - var meteorToolStat = statOrNull(meteorToolDir, "isDirectory"); + const meteorToolStat = statOrNull(meteorToolDir, "isDirectory"); if (! meteorToolStat) { return null; } - var dbPath = path.join( + const dbPath = path.join( packageMetadataDir, "v2.0.1", "packages.data.db" ); - var dbStat = statOrNull(dbPath, "isFile"); + const dbStat = statOrNull(dbPath, "isFile"); if (! dbStat) { return null; } - var sqlite3 = require("sqlite3"); - var db = new sqlite3.Database(dbPath); + const sqlite3 = require("sqlite3"); + const db = new sqlite3.Database(dbPath); return new Promise(function (resolve, reject) { db.get( @@ -118,15 +116,15 @@ function getDevBundleForRelease(release) { }).then(function (data) { if (data) { - var tool = JSON.parse(data.content).tool; - var devBundleDir = path.join( + const tool = JSON.parse(data.content).tool; + const devBundleDir = path.join( meteorToolDir, tool.split("@").slice(1).join("@"), "mt-" + getHostArch(), "dev_bundle" ); - var devBundleStat = statOrNull(devBundleDir, "isDirectory"); + const devBundleStat = statOrNull(devBundleDir, "isDirectory"); if (devBundleStat) { return devBundleDir; } @@ -163,17 +161,17 @@ function statOrNull(path, statMethod) { } function find(dir, predicate) { - var joinArgs = Array.prototype.slice.call(arguments, 2); + const joinArgs = Array.prototype.slice.call(arguments, 2); joinArgs.unshift(null); while (true) { joinArgs[0] = dir; - var joined = path.join.apply(path, joinArgs); + const joined = path.join.apply(path, joinArgs); if (predicate(joined)) { return joined; } - var parentDir = path.dirname(dir); + const parentDir = path.dirname(dir); if (parentDir === dir) break; dir = parentDir; } @@ -201,6 +199,7 @@ function getHostArch() { } } -module.exports = getDevBundleDir().catch(function (error) { - return defaultDevBundlePromise; -}); +module.exports = { + getDevBundleDir, + DEFAULT_DEV_BUNDLE_DIR +} \ No newline at end of file diff --git a/tools/cli/example-repositories.js b/tools/cli/example-repositories.js index 4324daf293..f1d67151ef 100644 --- a/tools/cli/example-repositories.js +++ b/tools/cli/example-repositories.js @@ -1,26 +1,14 @@ export const EXAMPLE_REPOSITORIES = { - clock: { repo: 'https://github.com/meteor/clock' }, - leaderboard: { repo: 'https://github.com/meteor/leaderboard' }, - localmarket: { repo: 'https://github.com/meteor/localmarket' }, - 'simple-todos': { repo: 'https://github.com/meteor/simple-todos' }, - 'simple-todos-react': { - repo: 'https://github.com/meteor/simple-todos-react' - }, - 'simple-todos-angular': { - repo: 'https://github.com/meteor/simple-todos-angular' - }, - todos: { repo: 'https://github.com/meteor/todos' }, - 'todos-react': { - 'repo': 'https://github.com/meteor/todos', - 'branch': 'react', - }, - 'angular-boilerplate': { - repo: 'https://github.com/Urigo/angular-meteor-base.git' - }, - simpletasks: { repo: 'https://github.com/fredmaiaarantes/simpletasks' }, - chakraui: { repo: 'https://github.com/meteor/examples/blob/main/chakra-ui' }, - tailwindcss: { repo: 'https://github.com/meteor/examples/blob/main/tailwindcss' }, - wantch: { repo: 'https://github.com/filipenevola/wantch' }, - doubleapp: { repo: 'https://github.com/denihs/double-app/' }, - + "vue": { "repo": "https://github.com/meteor/skel-vue" }, + "react": { "repo": "https://github.com/meteor/skel-react" }, + "full": { "repo": "https://github.com/meteor/skel-full" }, + "bare": { "repo": "https://github.com/meteor/skel-bare" }, + "blaze": { "repo": "https://github.com/meteor/skel-blaze" }, + "chakra-ui": { "repo": "https://github.com/meteor/skel-chakra-ui" }, + "apollo": { "repo": "https://github.com/meteor/skel-apollo" }, + "minimal": { "repo": "https://github.com/meteor/skel-minimal" }, + "solid": { "repo": "https://github.com/meteor/skel-solid" }, + "svelte": { "repo": "https://github.com/meteor/skel-svelte" }, + "tailwind": { "repo": "https://github.com/meteor/skel-tailwind" }, + "typescript": { "repo": "https://github.com/meteor/skel-typescript" }, }; diff --git a/tools/cli/help.txt b/tools/cli/help.txt index c5cc820414..96e611feca 100644 --- a/tools/cli/help.txt +++ b/tools/cli/help.txt @@ -73,6 +73,7 @@ Options: uses port N+1 and a port specified by --app-port. Specify as --port=host:port to bind to a specific interface. + --open, -o Opens a browser window when the app starts. --inspect[-brk][=] Enable server-side debugging via debugging clients like the Node.js command-line debugger, Chrome DevTools, or @@ -89,7 +90,8 @@ Options: Meteor app source code as by default the port is generated using the id inside .meteor/.id file. --production Simulate production mode. Minify and bundle CSS and JS files. - --raw-logs Run without parsing logs from stdout and stderr. + --raw-logs Run without parsing logs from stdout and stderr (default: true). + --timestamps Run with timestamps in logs, the same as passing `--raw-logs=false`. --settings, -s Set optional data for Meteor.settings on the server. --release Specify the release of Meteor to use. --verbose Print all output from builds logs. @@ -106,6 +108,7 @@ Options: --exclude-archs Don't create bundles for certain web architectures (comma separated, for example: --exclude-archs "web.browser.legacy, web.cordova") + --open Opens a browser window when it finishes building >>> debug Run the project with server-side debugging enabled. @@ -150,8 +153,9 @@ Options: >>> create Create a new project. -Usage: meteor create [--release ] [--bare|--minimal|--full|--react|--vue|--vue-2|--apollo|--svelte|--blaze|--tailwind|--chakra-ui|--solid] +Usage: meteor create [--release ] [--bare|--minimal|--full|--react|--vue|--apollo|--svelte|--blaze|--tailwind|--chakra-ui|--solid] meteor create [--release ] --example [] + meteor create [--release ] --from [] meteor create --list meteor create --package [] @@ -178,13 +182,13 @@ currently no package examples. Options: --package Create a new meteor package instead of an app. --example Example template to use. + --from Clones a meteor project from a url. --list Show list of available examples. --bare Create an empty app. --minimal Create an app with as few Meteor packages as possible. --full Create a fully scaffolded app. --react Create a basic react-based app, same as default. --vue Create a basic vue3-based app. - --vue-2 Create a basic vue2-based app. --apollo Create a basic apollo-based app. --svelte Create a basic svelte-based app. --typescript Create a basic Typescript React-based app. @@ -192,7 +196,7 @@ Options: --tailwind Create a basic react-based app, with tailwind configured. --chakra-ui Create a basic react-based app, with chakra-ui configured. --solid Create a basic solid-based app. - --prototype Create a prototype app with the insecure & autopublish packages. Can be used along with other app commands + --prototype Create a prototype app with the insecure & autopublish packages. Can be used along with other app commands >>> update @@ -489,7 +493,7 @@ Note that you must have mongosh installed to use this option. Options: --url, -U return a Mongo database URL --verbose, -v to show the errors that have occurred while connecting to the - database + database Currently, this feature can only be used when developing locally. The opened Mongo shell connects to the current project's local @@ -497,11 +501,12 @@ development database. The current working directory must be a Meteor project directory, and the Meteor application must already be running. >>> reset -Reset the project state. Erases the local database. -Usage: meteor reset +Reset the project state. +Usage: meteor reset [--db] -Reset the current project to a fresh state. Removes all local data. +Reset the current project to a fresh state and clear the local cache. +The --db flag also removes the local database. >>> deploy Deploy this project to Galaxy, Meteor's hosting service. @@ -635,6 +640,7 @@ with --port. Options: --port, -p Port to listen on (instead of the default 3000). Also uses port N+1 and N+2. + --open, -o Opens a browser window when the app starts. --inspect[-brk][=] Enable server-side debugging via debugging clients like the Node.js command-line debugger, Chrome DevTools, or @@ -724,6 +730,7 @@ Meteor Guide - https://guide.meteor.com/testing.html Options: --port, -p Port to listen on (instead of the default 3000). Also uses port N+1 and N+2. + --open, -o Opens a browser window when the app starts. --inspect[-brk][=] Enable server-side debugging via debugging clients like the Node.js command-line debugger, Chrome DevTools, or @@ -741,7 +748,9 @@ Options: important when multiple Cordova apps are build from the same Meteor app source code as by default the port is generated using the id inside .meteor/.id file. - --raw-logs Run without parsing logs from stdout and stderr. + --raw-logs Run without parsing logs from stdout and stderr (default: true). + --timestamps Run with timestamps in logs, the same as passing `--raw-logs=false`. + --settings, -s Set optional data for Meteor.settings on the server --ios, Run tests in an emulator or on a mobile device. All of @@ -760,6 +769,7 @@ Options: --exclude-archs Don't create test bundles for certain web architectures (comma separated, for example: --exclude-archs "web.browser.legacy, web.cordova") + --open Opens a browser window when it finishes building >>> self-test Run tests of the 'meteor' tool. @@ -809,7 +819,16 @@ Usage: meteor admin [args] Rarely used commands for administering official Meteor services. Commands: -{{commands}} + + make-bootstrap-tarballs + recommend-release + change-homepage + set-unmigrated + set-banners + list-organizations + members + set-latest-readme + get-machine See 'meteor help admin ' for details on an admin command. @@ -868,12 +887,12 @@ for replacing the names, we offer $$PascalName$$, $$camelName$$, $$name$$. This is a MeteorJS project command. Options: - --help Show help. - --path The path to the folder where the files will be generated. Default is the current folder. - --templatePath Path to the template file check https://docs.meteor.com/commandline.html#meteorgenerate-templating for more info. - --replaceFn Replace function to replace the names in the template. Check https://docs.meteor.com/commandline.html#meteorgenerate-templating for more info. - --methods Generate methods. - --publications Generate publications. + --help Show help. + --path The path to the folder where the files will be generated. Default is the current folder. + --templatePath Path to the template file check https://docs.meteor.com/commandline.html#meteorgenerate-templating for more info. + --replaceFn Replace function to replace the names in the template. Check https://docs.meteor.com/commandline.html#meteorgenerate-templating for more info. + --methods Generate methods. + --publications Generate publications. >>> publish-release @@ -1144,3 +1163,30 @@ To see the requirements for this compilation step, consult the platform requirements for 'node-gyp': https://github.com/nodejs/node-gyp + +>>> profile +Run performance profiling for the Meteor application. +Usage: meteor profile [...] + +This command runs a performance profile for the Meteor application, monitoring the +bundler process and tracking key performance metrics to help analyze the build and +bundling performance. + +Use METEOR_IDLE_TIMEOUT= to set a timeout for profiling. The default time (90s) +is usually enough for each build step to complete. If you encounter errors due to +early exits, adjust the environment variable accordingly. + +Use METEOR_CLIENT_ENTRYPOINT= to set a custom client entrypoint, and +METEOR_SERVER_ENTRYPOINT= to set a custom server entrypoint. By default, +it uses the server and client entrypoints specified in your package.json. + +Use METEOR_LOG_DIR= to set a custom log directory. + +Options: + --size monitor both bundle runtime and size + --size-only monitor only the bundle size + --build monitor build time + +The rest of options for this command are the same as those for the meteor run command. +You can pass typical runtime options (such as --settings, --exclude-archs, etc.) +to customize the profiling process. diff --git a/tools/cli/main.js b/tools/cli/main.js index 09a4873b3d..b73e2b7868 100644 --- a/tools/cli/main.js +++ b/tools/cli/main.js @@ -5,7 +5,6 @@ if (showRequireProfile) { var assert = require("assert"); var _ = require('underscore'); -var Fiber = require('fibers'); var Console = require('../console/console.js').Console; var files = require('../fs/files'); var warehouse = require('../packaging/warehouse.js'); @@ -15,17 +14,12 @@ var projectContextModule = require('../project-context.js'); var catalog = require('../packaging/catalog/catalog.js'); var buildmessage = require('../utils/buildmessage.js'); var httpHelpers = require('../utils/http-helpers.js'); +const { makeGlobalAsyncLocalStorage } = require("../utils/fiber-helpers"); const archinfo = require('../utils/archinfo'); import { isEmacs } from "../utils/utils.js"; var main = exports; -if (process.platform === 'darwin' && process.arch === 'arm64') { - // pool size needs to be bigger on m1 because arm64 builds are using - // fibers with CORO_PTHREAD set. - default on fibers is 120 - Fiber.poolSize = 250; -} - require('./flush-buffers-on-exit-in-windows.js'); // node (v8) defaults to only recording 10 lines of stack trace. This @@ -273,12 +267,12 @@ main.registerCommand = function (options, func) { target[nameParts[0]] = new Command(options); }; -main.captureAndExit = function (header, title, f) { +main.captureAndExit = async function (header, title, f) { var messages; if (f) { - messages = buildmessage.capture({ title: title }, f); + messages = await buildmessage.capture({ title: title }, f); } else { - messages = buildmessage.capture(title); // title is really f + messages = await buildmessage.capture(title); // title is really f } if (messages.hasMessages()) { Console.error(header); @@ -293,12 +287,16 @@ main.captureAndExit = function (header, title, f) { // NB: files required up to this point may not define commands +const { initMeteorConfig } = require('../tool-env/meteor-config'); require('./commands.js'); require('./commands-packages.js'); require('./commands-packages-query.js'); require('./commands-cordova.js'); require('./commands-aliases.js'); +// Initialize meteorConfig globally +initMeteorConfig(); + /////////////////////////////////////////////////////////////////////////////// // Record all the top-level commands as JSON /////////////////////////////////////////////////////////////////////////////// @@ -427,7 +425,7 @@ var longHelp = exports.longHelp = function (commandName) { // and will cause release.forced to be true). // - fromApp: this release was suggested because it is the app's // release. affects error messages. -var springboard = function (rel, options) { +var springboard = async function (rel, options) { options = options || {}; if (process.env.METEOR_DEBUG_SPRINGBOARD) { console.log("WILL SPRINGBOARD TO", rel.getToolsPackageAtVersion()); @@ -435,14 +433,14 @@ var springboard = function (rel, options) { const toolsPkg = rel.getToolsPackage(); const toolsVersion = rel.getToolsVersion(); - const serverArchitectures = catalog.official.filterArchesWithBuilds( + const serverArchitectures = await catalog.official.filterArchesWithBuilds( toolsPkg, toolsVersion, archinfo.acceptableMeteorToolArches(), ); if (serverArchitectures.length === 0) { - var release = catalog.official.getDefaultReleaseVersion(); + var release = await catalog.official.getDefaultReleaseVersion(); var releaseName = release.track + "@" + release.version; Console.error( @@ -461,12 +459,12 @@ var springboard = function (rel, options) { }); // XXX split better - Console.withProgressDisplayVisible(function () { - var messages = buildmessage.capture({ + await Console.withProgressDisplayVisible(async function () { + var messages = await buildmessage.capture({ title: "downloading the command-line tool" - }, function () { - catalog.runAndRetryWithRefreshIfHelpful(function () { - tropohouse.default.downloadPackagesMissingFromMap(packageMap, { + }, async function () { + await catalog.runAndRetryWithRefreshIfHelpful(async function () { + await tropohouse.default.downloadPackagesMissingFromMap(packageMap, { serverArchitectures, }); }); @@ -493,7 +491,7 @@ var springboard = function (rel, options) { const isopack = require('../isobuild/isopack.js'); const packagePath = tropohouse.default.packagePath(toolsPkg, toolsVersion); const toolIsopack = new isopack.Isopack; - toolIsopack.initFromPath(toolsPkg, packagePath); + await toolIsopack.initFromPath(toolsPkg, packagePath); let toolRecord = null; serverArchitectures.some(arch => { @@ -545,7 +543,7 @@ var springboard = function (rel, options) { // Release our connection to the sqlite catalog database for the current // process, so that the springboarded process can reestablish it. - catalog.official.closePermanently(); + await catalog.official.closePermanently(); const isWindows = process.platform === "win32"; const executable = files.pathJoin( @@ -554,13 +552,14 @@ var springboard = function (rel, options) { ); if (isWindows) { - process.exit(new Promise(function (resolve) { + process.exit(await new Promise(function (resolve) { var execPath = files.convertToOSPath(executable); var child = require("child_process").spawn(execPath, newArgv, { env: process.env, - stdio: 'inherit' + stdio: 'inherit', + shell: true, }).on('exit', resolve); - }).await()); + })); } // Now exec; we're not coming back. @@ -569,7 +568,7 @@ var springboard = function (rel, options) { }; // Springboard to a pre-0.9.0 release. -var oldSpringboard = function (toolsVersion) { +var oldSpringboard = async function (toolsVersion) { // Strip off the "node" and "meteor.js" from argv and replace it with the // appropriate tools's meteor shell script. var newArgv = process.argv.slice(2); @@ -578,7 +577,7 @@ var oldSpringboard = function (toolsVersion) { // Release our connection to the sqlite catalog database for the current // process, so that the springboarded process can reestablish it. - catalog.official.closePermanently(); + await catalog.official.closePermanently(); // Now exec; we're not coming back. require('kexec')(cmd, newArgv); @@ -596,8 +595,7 @@ var oldSpringboard = function (toolsVersion) { // finding the requested command in the commands table, and making // sure that you're using the version of the Meteor tools that match // your project. - -Fiber(function () { +makeGlobalAsyncLocalStorage().run({}, async function () { // If running inside the Emacs shell, set stdin to be blocking, // reversing node's normal setting of O_NONBLOCK on the evaluation // of process.stdin (because Node unblocks stdio when forking). This @@ -610,7 +608,7 @@ Fiber(function () { // Check required Node version. // This code is duplicated in tools/server/boot.js. - var MIN_NODE_VERSION = 'v14.0.0'; + var MIN_NODE_VERSION = 'v18.16.0'; if (require('semver').lt(process.version, MIN_NODE_VERSION)) { Console.error( 'Meteor requires Node ' + MIN_NODE_VERSION + ' or later.'); @@ -871,14 +869,17 @@ Fiber(function () { var appDir = files.findAppDir(); if (appDir) { appDir = files.pathResolve(appDir); + + // Renitialize meteorConfig globally when having appDir context + initMeteorConfig(appDir); } - require('../tool-env/isopackets.js').ensureIsopacketsLoadable(); + await require('../tool-env/isopackets.js').ensureIsopacketsLoadable(); // Initialize the server catalog. Among other things, this is where we get // release information (used by springboarding). We do not at this point talk // to the server and refresh it. - catalog.official.initialize({ + await catalog.official.initialize({ offline: !!process.env.METEOR_OFFLINE_CATALOG }); @@ -931,10 +932,12 @@ Fiber(function () { } var releaseName, appReleaseFile; + if (appDir) { appReleaseFile = new projectContextModule.ReleaseFile({ projectDir: appDir }); + await appReleaseFile.init(); // This is what happens if the file exists and is empty. This really // shouldn't happen unless the user did it manually. if (appReleaseFile.noReleaseSpecified()) { @@ -983,15 +986,15 @@ Fiber(function () { } else { // Run outside an app dir with no --release flag. Use the latest // release we know about (in the default track). - releaseName = release.latestKnown(); + releaseName = await release.latestKnown(); if (!releaseName) { // Somehow we have a catalog that doesn't have any releases on the // default track. Try syncing, at least. (This is a pretty unlikely // error case, since you should always start with a non-empty catalog.) - Console.withProgressDisplayVisible(function () { - catalog.refreshOrWarn(); + await Console.withProgressDisplayVisible(async function () { + await catalog.refreshOrWarn(); }); - releaseName = release.latestKnown(); + releaseName = await release.latestKnown(); } if (!releaseName) { if (catalog.refreshFailed) { @@ -1028,7 +1031,7 @@ Fiber(function () { // mean we've downloaded the tool or any packages yet.) release.load just // does a single sqlite query; it doesn't refresh the catalog. try { - rel = release.load(releaseName); + rel = await release.load(releaseName); } catch (e) { if (!(e instanceof release.NoSuchReleaseError)) { throw e; @@ -1043,20 +1046,20 @@ Fiber(function () { // ATTEMPT 2: legacy release, on disk. (And it's a "real" release, not a // "red pill" release which has the same name as a modern release!) if (warehouse.realReleaseExistsInWarehouse(releaseName)) { - var manifest = warehouse.ensureReleaseExistsAndReturnManifest( + var manifest = await warehouse.ensureReleaseExistsAndReturnManifest( releaseName); - oldSpringboard(manifest.tools); // doesn't return + await oldSpringboard(manifest.tools); // doesn't return } // ATTEMPT 3: modern release, troposphere sync needed. - Console.withProgressDisplayVisible(function () { - catalog.refreshOrWarn(); + await Console.withProgressDisplayVisible(async function () { + await catalog.refreshOrWarn(); }); // Try to load the release even if the refresh failed, since it might // have failed on a later page than the one we needed. try { - rel = release.load(releaseName); + rel = await release.load(releaseName); } catch (e) { if (!(e instanceof release.NoSuchReleaseError)) { throw e; @@ -1068,7 +1071,7 @@ Fiber(function () { // ATTEMPT 4: legacy release, loading from warehouse server. manifest = null; try { - manifest = warehouse.ensureReleaseExistsAndReturnManifest( + manifest = await warehouse.ensureReleaseExistsAndReturnManifest( releaseName); } catch (e) { // Note: this is WAREHOUSE's NoSuchReleaseError, not RELEASE's @@ -1093,7 +1096,7 @@ Fiber(function () { } if (manifest) { // OK, it was an legacy release. We should old-springboard to it. - oldSpringboard(manifest.tools); // doesn't return + await oldSpringboard(manifest.tools); // doesn't return } } } @@ -1113,7 +1116,7 @@ Fiber(function () { if (process.platform === "win32") { // Give a good warning if this release exists, but only in the super old // warehouse. - var result = httpHelpers.request( + var result = await httpHelpers.request( "http://warehouse.meteor.com/releases/" + releaseName + ".release.json"); if(result.response.statusCode === 200) { Console.error("Meteor on Windows does not support running any releases", @@ -1162,13 +1165,13 @@ Fiber(function () { release.current.isProperRelease()) { if (files.getToolsVersion() !== release.current.getToolsPackageAtVersion()) { - springboard(release.current, { + await springboard(release.current, { fromApp: releaseFromApp, mayReturn: false, - }) + }); // Does not return! } else if (archinfo.canSwitchTo64Bit()) { - springboard(release.current, { + await springboard(release.current, { fromApp: releaseFromApp, // Switching to a 64-bit meteor-tool build may fail, in which case // we should continue on as usual. @@ -1177,6 +1180,23 @@ Fiber(function () { } } + try { + const { getChildProcess } = require("./dev-bundle-bin-commands") + + const child = await getChildProcess({ isFirstTry: false }) + + // If we spawned a process to handle a dev_bundle/bin command like + // `meteor npm` or `meteor node`, then don't run any other tool code. + + if (child) { + return; + } + } catch (error) { + process.nextTick(function () { + throw error; + }); + } + // Check for the '--help' option. var showHelp = false; if (_.has(rawOptions, '--help')) { @@ -1525,14 +1545,15 @@ Fiber(function () { var catalogRefreshStrategy = command.catalogRefresh; if (! catalog.triedToRefreshRecently && catalogRefreshStrategy.beforeCommand) { - buildmessage.enterJob({title: 'updating package catalog'}, function () { - catalogRefreshStrategy.beforeCommand(); + await buildmessage.enterJob({title: 'updating package catalog'}, async function () { + await catalogRefreshStrategy.beforeCommand(); }); } - var ret = Promise.resolve( - command.func(options, { rawOptions }) - ).await(); + // Set the currentCommand in the global object to spread context + global.currentCommand = { name: command.name, options }; + + var ret = await command.func(options, { rawOptions }); } catch (e) { Console.enableProgressDisplay(false); @@ -1550,22 +1571,23 @@ Fiber(function () { // Load the metadata for the latest release (or at least, the latest // release we know about locally). We should only do this if we know there // is some latest release on this track. - var latestRelease = release.load(release.latestKnown(e.track)); - springboard(latestRelease, { releaseOverride: latestRelease.name }); + var latestRelease = await release.load(await release.latestKnown(e.track)); + await springboard(latestRelease, { releaseOverride: latestRelease.name }); // (does not return) } else if (e instanceof main.SpringboardToSpecificRelease) { // Springboard to a specific release. This is only throw by // publish-for-arch, which is catalog.Refresh.OnceAtStart, so we ought to // have decent knowledge of the latest release. - var nextRelease = release.load(e.fullReleaseName); - springboard(nextRelease, { releaseOverride: e.fullReleaseName }); + var nextRelease = await release.load(e.fullReleaseName); + await springboard(nextRelease, { releaseOverride: e.fullReleaseName }); // (does not return) } else if (e instanceof main.WaitForExit) { return; } else if (e instanceof main.ExitWithCode) { process.exit(e.code); } else { - throw e; + console.error(e); + process.exit(1); } } @@ -1580,4 +1602,4 @@ Fiber(function () { throw new Error("command returned non-number?"); } process.exit(ret); -}).run(); +}); diff --git a/tools/console/console.js b/tools/console/console.js index 762a0f4957..a897346483 100644 --- a/tools/console/console.js +++ b/tools/console/console.js @@ -49,7 +49,7 @@ /// (They will change your output in ways that you probably do not want). These /// don't auto-linewrap, end in a newline, or take in Console.options. /// -/// Here is are some examples: +/// Here are some examples: /// Console.rawInfo(JSON.stringify(myData, null, 2)); /// Console.rawError(err.stack + "\n"); /// @@ -442,16 +442,16 @@ class StatusPoller { this._stop = false; } - _startPoller() { + async _startPoller() { if (this._pollPromise) { throw new Error("Already started"); } this._pollPromise = (async() => { - sleepMs(STATUS_INTERVAL_MS); + await sleepMs(STATUS_INTERVAL_MS); while (! this._stop) { this.statusPoll(); - sleepMs(STATUS_INTERVAL_MS); + await sleepMs(STATUS_INTERVAL_MS); } })(); } @@ -623,7 +623,7 @@ class Console extends ConsoleBase { // Runs f with the progress display visible (ie, with progress display enabled // and pretty). Resets both flags to their original values after f runs. - withProgressDisplayVisible(f) { + async withProgressDisplayVisible(f) { var originalPretty = this._pretty; var originalProgressDisplayEnabled = this._progressDisplayEnabled; @@ -636,7 +636,7 @@ class Console extends ConsoleBase { } try { - return f(); + return await f(); } finally { // Reset the flags. this._pretty = originalPretty; @@ -683,19 +683,19 @@ class Console extends ConsoleBase { // consuming lots of CPU without yielding is especially bad. // Other IO/network tasks will stall, and you can't even kill the process! // - // Within any code that may burn CPU for too long, call `Console.nudge()`. - // If it's been a while since your last yield, your Fiber will sleep momentarily. + // Within any code that may burn CPU for too long, call `Console.yield()`. // It will also update the spinner if there is one and it's been a while. - // The caller should be OK with yielding --- it has to be in a Fiber and it can't be - // anything that depends for correctness on not yielding. You can also call nudge(false) + // The caller should be OK with yielding --- it can't be + // anything that depends for correctness on not yielding. You can also call Console.nudge() // if you just want to update the spinner and not yield, but you should avoid this. - nudge(canYield) { + nudge() { if (this._statusPoller) { this._statusPoller.statusPoll(); } - if (canYield === undefined || canYield === true) { - this._throttledYield.yield(); - } + } + async yield() { + this.nudge(); + await this._throttledYield.yield(); } // Initializes and returns a new ConsoleOptions object. Takes in the following @@ -1316,7 +1316,7 @@ class Console extends ConsoleBase { this._setProgressDisplay(previousProgressDisplay); resolve(line); }); - }).await(); + }); } } diff --git a/tools/console/progress.ts b/tools/console/progress.ts index 7b50bfa876..f68f839482 100644 --- a/tools/console/progress.ts +++ b/tools/console/progress.ts @@ -15,7 +15,7 @@ type ProgressState = { /** * Utility class for computing the progress of complex tasks. - * + * * Watchers are invoked with a ProgressState object. */ export class Progress { @@ -144,7 +144,9 @@ export class Progress { this.updateTotalState(); // Nudge the spinner/progress bar, but don't yield (might not be safe to yield) - require('./console.js').Console.nudge(false); + const { Console } = require("./console.js"); + + Console.nudge(); this.notifyState(); } diff --git a/tools/cordova/assets/launchscreens/android_mdpi_portrait.png b/tools/cordova/assets/launchscreens/android_universal.png similarity index 100% rename from tools/cordova/assets/launchscreens/android_mdpi_portrait.png rename to tools/cordova/assets/launchscreens/android_universal.png diff --git a/tools/cordova/builder.js b/tools/cordova/builder.js index 3c35e42dbb..ab8e8a4b03 100644 --- a/tools/cordova/builder.js +++ b/tools/cordova/builder.js @@ -64,16 +64,7 @@ const splashIosKeys = { }; const splashAndroidKeys = { - 'android_mdpi_portrait': 'port-mdpi', - 'android_mdpi_landscape': 'land-mdpi', - 'android_hdpi_portrait': 'port-hdpi', - 'android_hdpi_landscape': 'land-hdpi', - 'android_xhdpi_portrait': 'port-xhdpi', - 'android_xhdpi_landscape': 'land-xhdpi', - 'android_xxhdpi_portrait': 'port-xxhdpi', - 'android_xxhdpi_landscape': 'land-xxhdpi', - 'android_xxxhdpi_portrait': 'port-xxxhdpi', - 'android_xxxhdpi_landscape': 'land-xxxhdpi' + 'android_universal': 'AndroidWindowSplashScreenAnimatedIcon', }; export class CordovaBuilder { @@ -150,14 +141,6 @@ export class CordovaBuilder { const packageMap = this.projectContext.packageMap; - if (packageMap && packageMap.getInfo('launch-screen')) { - this.additionalConfiguration.global.AutoHideSplashScreen = false; - this.additionalConfiguration.global.SplashScreen = 'screen'; - this.additionalConfiguration.global.SplashScreenDelay = 5000; - this.additionalConfiguration.global.FadeSplashScreenDuration = 250; - this.additionalConfiguration.global.ShowSplashScreenSpinner = false; - } - if (packageMap && packageMap.getInfo('mobile-status-bar')) { this.additionalConfiguration.global.StatusBarOverlaysWebView = false; this.additionalConfiguration.global.StatusBarStyle = 'default'; @@ -232,12 +215,12 @@ export class CordovaBuilder { _.each(iconsAndroidSizes, setDefaultIcon); setDefaultLaunchScreen('ios_universal'); - setDefaultLaunchScreen('android_mdpi_portrait'); + setDefaultLaunchScreen('android_universal'); this.pluginsConfiguration = {}; } - processControlFile() { + async processControlFile() { const controlFilePath = files.pathJoin(this.projectContext.projectDir, 'mobile-config.js'); @@ -245,11 +228,11 @@ export class CordovaBuilder { if (files.exists(controlFilePath)) { Console.debug('Processing mobile-config.js'); - buildmessage.enterJob({ title: `processing mobile-config.js` }, () => { + await buildmessage.enterJob({ title: `processing mobile-config.js` }, async () => { const code = files.readFile(controlFilePath, 'utf8'); try { - files.runJavaScript(code, { + await files.runJavaScript(code, { filename: 'mobile-config.js', symbols: { App: createAppConfiguration(this) } }); @@ -260,7 +243,7 @@ export class CordovaBuilder { } } - writeConfigXmlAndCopyResources(shouldCopyResources = true) { + async writeConfigXmlAndCopyResources(shouldCopyResources = true) { let config = XmlBuilder.create({ version: '1.0' }).ele('widget'); // Set the root attributes @@ -341,7 +324,7 @@ export class CordovaBuilder { } if (shouldCopyResources) { // Prepare the resources folder - files.rm_recursive(this.resourcesPath); + await files.rm_recursive(this.resourcesPath); files.mkdir_p(this.resourcesPath); Console.debug('Copying resources for mobile apps'); @@ -373,7 +356,7 @@ export class CordovaBuilder { files.pathJoin(this.resourcesPath, newFilename)); // Set it to the xml tree - xmlElement.ele(tag, { src, ...attributes }); + xmlElement.ele(tag, { ...(tag === "preference" ? { value: src } : { src }), ...attributes }); } _resolveFilenameForImages = (suppliedPath, key, tag) => { @@ -426,8 +409,12 @@ export class CordovaBuilder { let suppliedPath = suppliedValue; let suppliedPathDarkMode = null; if (typeof suppliedValue === 'object') { - suppliedPath = suppliedValue.src; - suppliedPathDarkMode = suppliedValue.srcDarkMode; + if (isIos) { + suppliedPath = suppliedValue.src; + suppliedPathDarkMode = suppliedValue.srcDarkMode; + } else { + throw new Error("Dark mode through Meteor's launch screen helper is only allowed for iOS. For android, please follow the instructions: https://developer.android.com/develop/ui/views/theming/darktheme."); + } } if (isIos) { @@ -445,19 +432,12 @@ export class CordovaBuilder { } const filename = this._resolveFilenameForImages(suppliedPath, key, 'splash'); - if (suppliedPathDarkMode) { - this._copyImageToBuildFolderAndAppendToXmlNode(suppliedPathDarkMode, - appendDarkMode(filename, { withChar: '_' }), - xmlElement, 'splash', - { density: appendDarkMode(value, { separator: '-', withChar: '-' })} - ); - } this._copyImageToBuildFolderAndAppendToXmlNode(suppliedPath, filename, xmlElement, - 'splash', - { density: value }); - }) + 'preference', + { name: value }); + }); } configureAndCopyResourceFiles(resourceFiles, iosElement, androidElement) { @@ -485,11 +465,11 @@ export class CordovaBuilder { }); } - copyWWW(bundlePath) { + async copyWWW(bundlePath) { const wwwPath = files.pathJoin(this.projectRoot, 'www'); // Remove existing www - files.rm_recursive(wwwPath); + await files.rm_recursive(wwwPath); // Create www and www/application directories const applicationPath = files.pathJoin(wwwPath, 'application'); @@ -497,7 +477,7 @@ export class CordovaBuilder { // Copy Cordova arch program from bundle to www/application const programPath = files.pathJoin(bundlePath, 'programs', CORDOVA_ARCH); - files.cp_r(programPath, applicationPath); + await files.cp_r(programPath, applicationPath); // Load program.json const programJsonPath = files.convertToOSPath( @@ -511,20 +491,20 @@ export class CordovaBuilder { const publicSettings = settings['public']; // Calculate client hash and append to program - this.appendVersion(program, publicSettings); + await this.appendVersion(program, publicSettings); // Write program.json files.writeFile(programJsonPath, JSON.stringify(program), 'utf8'); - const bootstrapPage = this.generateBootstrapPage( + const bootstrapPage = await this.generateBootstrapPage( applicationPath, program, publicSettings - ).await(); + ); files.writeFile(files.pathJoin(applicationPath, 'index.html'), bootstrapPage, 'utf8'); } - appendVersion(program, publicSettings) { + async appendVersion(program, publicSettings) { // Note: these version calculations must be kept in agreement with // generateClientProgram in packages/webapp/webapp_server.js, or hot // code push will reload the app unnecessarily. @@ -532,7 +512,7 @@ export class CordovaBuilder { let configDummy = {}; configDummy.PUBLIC_SETTINGS = publicSettings || {}; - const { WebAppHashing } = loadIsopackage('webapp-hashing'); + const { WebAppHashing } = await loadIsopackage('webapp-hashing'); const { AUTOUPDATE_VERSION } = process.env; program.version = AUTOUPDATE_VERSION || @@ -558,7 +538,7 @@ export class CordovaBuilder { ); } - generateBootstrapPage(applicationPath, program, publicSettings) { + async generateBootstrapPage(applicationPath, program, publicSettings) { const meteorRelease = release.current.isCheckout() ? "none" : release.current.name; const hmrVersion = @@ -599,7 +579,7 @@ export class CordovaBuilder { runtimeConfig.PUBLIC_SETTINGS = publicSettings; } - const { Boilerplate } = loadIsopackage('boilerplate-generator'); + const { Boilerplate } = await loadIsopackage('boilerplate-generator'); const boilerplate = new Boilerplate(CORDOVA_ARCH, manifest, { urlMapper: _.identity, @@ -614,14 +594,14 @@ export class CordovaBuilder { return boilerplate.toHTMLAsync(); } - copyBuildOverride() { + async copyBuildOverride() { const buildOverridePath = files.pathJoin(this.projectContext.projectDir, 'cordova-build-override'); if (files.exists(buildOverridePath) && files.stat(buildOverridePath).isDirectory()) { Console.debug('Copying over the cordova-build-override directory'); - files.cp_r(buildOverridePath, this.projectRoot); + await files.cp_r(buildOverridePath, this.projectRoot); } } } @@ -754,11 +734,11 @@ configuration. The key may be deprecated.`); * @summary Set the launch screen images for your mobile app. * @param {Object} launchScreens A dictionary where keys are different * devices, screen sizes, and orientations, and the values are image paths - * relative to the project root directory or an object containing a dark mode image path too ({src, srcDarkMode}). + * relative to the project root directory or an object containing a dark mode image path too `{ src, srcDarkMode }` (iOS only). + * Note: If you want to have a dark theme splash screen on Android, please follow the instructions described [here](https://developer.android.com/develop/ui/views/theming/darktheme). * - * For Android, launch screen images should - * be special "Nine-patch" image files that specify how they should be - * stretched. See the [Android docs](https://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch). + * For Android specific information, check the [Cordova docs](https://cordova.apache.org/docs/en/latest/core/features/splashscreen/index.html#android-specific-information) and [Android docs](https://developer.android.com/develop/ui/views/launch/splash-screen#splash_screen_dimensions). + * Also note that for android the asset can either be an XML Vector Drawable or PNG. * * For best practices when developing a splash image, see the [Apple Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/launch-screen/). * To learn more about size classes for iOS, check out the [documentation](https://cordova.apache.org/docs/en/10.x/reference/cordova-plugin-splashscreen/#size-classes) from Cordova. @@ -766,32 +746,23 @@ configuration. The key may be deprecated.`); * Valid key values: * * iOS: - * - `ios_universal` (Default@2xuniversalanyany.png - 2732x2732) - All @2x devices, if device/mode specific is not declared - * - `ios_universal_3x` (Default@3xuniversalanyany.png - 2208x2208) - All @3x devices, if device/mode specific is not declared - * - `Default@2x~universal~comany` (1278x2732) - All @2x devices in portrait mode - * - `Default@2x~universal~comcom` (1334x750) - All @2x devices in landscape (narrow) mode - * - `Default@3x~universal~anycom` (2208x1242) - All @3x devices in landscape (wide) mode - * - `Default@3x~universal~comany` (1242x2208) - All @3x devices in portrait mode - * - `Default@2x~iphone~anyany` (1334x1334) - iPhone SE/6s/7/8/XR - * - `Default@2x~iphone~comany` (750x1334) - iPhone SE/6s/7/8/XR - portrait mode - * - `Default@2x~iphone~comcom` (1334x750) - iPhone SE/6s/7/8/XR - landscape (narrow) mode - * - `Default@3x~iphone~anyany` (2208x2208) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - * - `Default@3x~iphone~anycom` (2208x1242) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - landscape (wide) mode - * - `Default@3x~iphone~comany` (1242x2208) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - portrait mode - * - `Default@2x~ipad~anyany` (2732x2732) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9" - * - `Default@2x~ipad~comany` (1278x2732) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9" - portrait mode + * - `ios_universal` (Default@2xuniversalanyany.png - 2732x2732 px) - All @2x devices, if device/mode specific is not declared + * - `ios_universal_3x` (Default@3xuniversalanyany.png - 2208x2208 px) - All @3x devices, if device/mode specific is not declared + * - `Default@2x~universal~comany` (1278x2732 px) - All @2x devices in portrait mode + * - `Default@2x~universal~comcom` (1334x750 px) - All @2x devices in landscape (narrow) mode + * - `Default@3x~universal~anycom` (2208x1242 px) - All @3x devices in landscape (wide) mode + * - `Default@3x~universal~comany` (1242x2208 px) - All @3x devices in portrait mode + * - `Default@2x~iphone~anyany` (1334x1334 px) - iPhone SE/6s/7/8/XR + * - `Default@2x~iphone~comany` (750x1334 px) - iPhone SE/6s/7/8/XR - portrait mode + * - `Default@2x~iphone~comcom` (1334x750 px) - iPhone SE/6s/7/8/XR - landscape (narrow) mode + * - `Default@3x~iphone~anyany` (2208x2208 px) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max + * - `Default@3x~iphone~anycom` (2208x1242 px) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - landscape (wide) mode + * - `Default@3x~iphone~comany` (1242x2208 px) - iPhone 6s Plus/7 Plus/8 Plus/X/XS/XS Max - portrait mode + * - `Default@2x~ipad~anyany` (2732x2732 px) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9" + * - `Default@2x~ipad~comany` (1278x2732 px) - iPad Pro 12.9"/11"/10.5"/9.7"/7.9" - portrait mode * * Android: - * - `android_mdpi_portrait` (320x480) - * - `android_mdpi_landscape` (480x320) - * - `android_hdpi_portrait` (480x800) - * - `android_hdpi_landscape` (800x480) - * - `android_xhdpi_portrait` (720x1280) - * - `android_xhdpi_landscape` (1280x720) - * - `android_xxhdpi_portrait` (960x1600) - * - `android_xxhdpi_landscape` (1600x960) - * - `android_xxxhdpi_portrait` (1280x1920) - * - `android_xxxhdpi_landscape` (1920x1280) + * - `android_universal` (288x288 dp) * * @memberOf App */ @@ -800,11 +771,16 @@ configuration. The key may be deprecated.`); Object.keys(splashIosKeys).concat(Object.keys(splashAndroidKeys)); Object.keys(launchScreens).forEach((key) => { - if (!key in validDevices) { + if (!validDevices.includes(key)) { Console.labelWarn(`${key}: unknown key in App.launchScreens \ configuration. The key may be deprecated.`); } - }) + + const value = launchScreens[key]; + if (typeof value !== "string" && key.includes("android")) { + throw new Error("Android splash screen path must be a string. To enable dark splash screens for your app, check out the android developer guide: https://developer.android.com/develop/ui/views/theming/darktheme."); + } + }); Object.assign(builder.imagePaths.splash, launchScreens); }, diff --git a/tools/cordova/index.js b/tools/cordova/index.js index a35f48d41b..e1acabacb6 100644 --- a/tools/cordova/index.js +++ b/tools/cordova/index.js @@ -13,11 +13,11 @@ export const CORDOVA_ARCH = "web.cordova"; export const CORDOVA_PLATFORMS = ['ios', 'android']; -const CORDOVA_ANDROID_VERSION = "10.1.2"; +const CORDOVA_ANDROID_VERSION = "14.0.1"; export const CORDOVA_DEV_BUNDLE_VERSIONS = { - 'cordova-lib': '10.0.0', - 'cordova-common': '4.0.2', + 'cordova-lib': '12.0.2', + 'cordova-common': '5.0.1', 'cordova-create': '2.0.0', 'cordova-registry-mapper': '1.1.15', 'cordova-android': CORDOVA_ANDROID_VERSION, @@ -25,7 +25,7 @@ export const CORDOVA_DEV_BUNDLE_VERSIONS = { export const CORDOVA_PLATFORM_VERSIONS = { 'android': CORDOVA_ANDROID_VERSION, - 'ios': '6.2.0', + 'ios': '7.1.1', }; export const SWIFT_VERSION = 5; @@ -36,13 +36,13 @@ const PLATFORM_TO_DISPLAY_NAME_MAP = { }; export function ensureDevBundleDependencies() { - buildmessage.enterJob( + return buildmessage.enterJob( { title: 'Installing Cordova in Meteor tool', }, - () => { - require("../cli/dev-bundle-helpers.js") - .ensureDependencies(CORDOVA_DEV_BUNDLE_VERSIONS); + async () => { + await (require("../cli/dev-bundle-helpers.js") + .ensureDependencies(CORDOVA_DEV_BUNDLE_VERSIONS)); const cordovaNodeModulesDir = pathJoin( getDevBundle(), @@ -52,18 +52,18 @@ export function ensureDevBundleDependencies() { "node_modules", ); - [ + for (const pkg of [ // Remove these bundled packages in preference to // dev_bundle/lib/node_modules/: "graceful-fs", pathJoin("npm", "node_modules", "graceful-fs"), - ].forEach(pkg => { + ]) { const path = pathJoin(cordovaNodeModulesDir, pkg); const stat = statOrNull(path); if (stat && stat.isDirectory()) { - rm_recursive(path); + await rm_recursive(path); } - }); + } } ); } diff --git a/tools/cordova/project.js b/tools/cordova/project.js index b5bb0b0fe3..27a6891bfd 100644 --- a/tools/cordova/project.js +++ b/tools/cordova/project.js @@ -10,7 +10,8 @@ import { Console } from '../console/console.js'; import { Profile } from '../tool-env/profile'; import buildmessage from '../utils/buildmessage.js'; import main from '../cli/main.js'; -import { execFileSync } from '../utils/processes'; +import { execFileAsync } from '../utils/processes'; +var meteorNpm = require('../isobuild/meteor-npm'); import { cordova as cordova_lib, events as cordova_events, CordovaError } from 'cordova-lib'; @@ -22,6 +23,8 @@ import { CORDOVA_PLATFORMS, CORDOVA_PLATFORM_VERSIONS, displayNameForPlatform, d newPluginId, convertPluginVersions, convertToGitUrl } from './index.js'; import { CordovaBuilder } from './builder.js'; +const cordovaPackagesFile = 'cordova-packages.json'; + cordova_events.on('verbose', logIfVerbose); cordova_events.on('log', logIfVerbose); cordova_events.on('info', logIfVerbose); @@ -67,7 +70,6 @@ const pinnedPluginVersions = { "cordova-plugin-media": "3.0.1", "cordova-plugin-media-capture": "1.4.3", "cordova-plugin-network-information": "1.3.3", - "cordova-plugin-splashscreen": "4.1.0", "cordova-plugin-statusbar": "2.3.0", "cordova-plugin-test-framework": "1.1.5", "cordova-plugin-vibration": "2.1.5", @@ -114,45 +116,51 @@ export class CordovaProject { this.buildJsonPath = files.convertToOSPath( files.pathJoin(this.projectRoot, 'build.json')); - - this.createIfNeeded(); } - - createIfNeeded() { + init() { + const self = this; + return self.createIfNeeded(); + } + async createIfNeeded() { buildmessage.assertInJob(); // Check if we have an existing Cordova project directory with outdated // platforms. In that case, we remove the whole directory to avoid issues. + let outdated; if (files.exists(this.projectRoot)) { const installedPlatforms = this.listInstalledPlatforms(); - const outdated = _.some(pinnedPlatformVersions, (pinnedVersion, platform) => { + for (const [platform, pinnedVersion] of Object.entries(pinnedPlatformVersions)) { // If the platform is not installed, it cannot be outdated if (!installedPlatforms.includes(platform)) { - return false; + continue; } - const installedVersion = this.installedVersionForPlatform(platform); + const installedVersion = await this.installedVersionForPlatform(platform); // If we cannot establish the installed version, we consider it outdated if (!installedVersion) { - return true; + outdated = true; + break; } if (! semver.valid(pinnedVersion)) { // If pinnedVersion is not a semantic version but instead // something like a GitHub tarball URL, assume not outdated. - return false; + continue; } - return semver.lt(installedVersion, pinnedVersion); - }); + if (semver.lt(installedVersion, pinnedVersion)) { + outdated = true; + break; + } + } if (outdated) { Console.debug(`Removing Cordova project directory to avoid issues with outdated platforms`); // Remove Cordova project directory to start afresh // and avoid a broken project - files.rm_recursive(this.projectRoot); + await files.rm_recursive(this.projectRoot); } } @@ -182,14 +190,14 @@ outdated platforms`); buildMode: this.options.buildMode } ); - builder.processControlFile(); + await builder.processControlFile(); if (buildmessage.jobHasMessages()) { return; } // Don't copy resources (they will be copied as part of the prepare) - builder.writeConfigXmlAndCopyResources(false); + await builder.writeConfigXmlAndCopyResources(false); // Create the Cordova project root directory files.mkdir_p(files.pathDirname(this.projectRoot)); @@ -205,7 +213,7 @@ outdated platforms`); // Don't set cwd to project root in runCommands because it doesn't // exist yet - this.runCommands('creating Cordova project', async () => { + await this.runCommands('creating Cordova project', async () => { // No need to pass in appName and appId because these are set from // the generated config.xml await create(files.convertToOSPath(this.projectRoot), @@ -242,7 +250,7 @@ outdated platforms`); // Preparing - prepareFromAppBundle(bundlePath, pluginVersions) { + async prepareFromAppBundle(bundlePath, pluginVersions) { assert(bundlePath); assert(pluginVersions); @@ -259,18 +267,18 @@ outdated platforms`); buildMode: this.options.buildMode } ); - builder.processControlFile(); + await builder.processControlFile(); if (buildmessage.jobHasMessages()) { return; } - builder.writeConfigXmlAndCopyResources(); - builder.copyWWW(bundlePath); + await builder.writeConfigXmlAndCopyResources(); + await builder.copyWWW(bundlePath); - this.ensurePluginsAreSynchronized(pluginVersions, + await this.ensurePluginsAreSynchronized(pluginVersions, builder.pluginsConfiguration); - this.ensurePlatformsAreSynchronized(); + await this.ensurePlatformsAreSynchronized(); // Temporary workaround for Cordova iOS bug until // https://issues.apache.org/jira/browse/CB-10885 is fixed @@ -285,10 +293,10 @@ outdated platforms`); 'LD_RUNPATH_SEARCH_PATHS = @executable_path/Frameworks;'); } - builder.copyBuildOverride(); + await builder.copyBuildOverride(); } - prepareForPlatform(platform, options) { + async prepareForPlatform(platform, options) { assert(platform); // Temporary workaround for Cordova iOS bug until @@ -303,7 +311,7 @@ outdated platforms`); platforms: [platform], }; - this.runCommands(`preparing Cordova project for platform \ + await this.runCommands(`preparing Cordova project for platform \ ${displayNameForPlatform(platform)}`, async () => { await cordova_lib.prepare(commandOptions); }); @@ -311,7 +319,7 @@ ${displayNameForPlatform(platform)}`, async () => { // Building (includes prepare) - buildForPlatform(platform, options = {}) { + async buildForPlatform(platform, options = {}) { assert(platform); const commandOptions = { @@ -320,7 +328,7 @@ ${displayNameForPlatform(platform)}`, async () => { options, }; - this.runCommands(`building Cordova app for platform \ + await this.runCommands(`building Cordova app for platform \ ${displayNameForPlatform(platform)}`, async () => { await cordova_lib.build(commandOptions); }); @@ -339,11 +347,10 @@ ${displayNameForPlatform(platform)}`, async () => { device: isDevice, }; - this.runCommands(`running Cordova app for platform \ -${displayNameForPlatform(platform)} with options ${options}`, async () => { - await cordova_lib.run(commandOptions); - }); - + await this.runCommands( + `running Cordova app for platform \ +${displayNameForPlatform(platform)} with options ${options}`, + () => cordova_lib.run(commandOptions)); } // Platforms @@ -351,7 +358,7 @@ ${displayNameForPlatform(platform)} with options ${options}`, async () => { // Checks to see if the requirements for building and running on the // specified Cordova platform are satisfied, printing // installation instructions when needed. - checkPlatformRequirements(platform) { + async checkPlatformRequirements(platform) { if (platform === 'ios' && process.platform !== 'darwin') { Console.warn("Currently, it is only possible to build iOS apps \ on an OS X system."); @@ -368,7 +375,7 @@ platform to your project first.`); return false; } - const allRequirements = this.runCommands(`checking Cordova \ + const allRequirements = await this.runCommands(`checking Cordova \ requirements for platform ${displayNameForPlatform(platform)}`, async () => { return await cordova_lib.requirements([platform], @@ -424,14 +431,16 @@ to build apps for ${displayNameForPlatform(platform)}.`); return cordova_util.listPlatforms(files.convertToOSPath(this.projectRoot)); } - installedVersionForPlatform(platform) { - const command = files.convertToOSPath(files.pathJoin( + async installedVersionForPlatform(platform) { + const file = files.convertToOSPath(files.pathJoin( this.projectRoot, 'platforms', platform, 'cordova', 'version')); + const command = process.platform === "win32" ? process.execPath : file; + const args = process.platform === "win32" ? [file] : []; // Make sure the command exists before trying to execute it if (files.exists(command)) { return this.runCommands( `getting installed version for platform ${platform} in Cordova project`, - execFileSync(command, { + execFileAsync(command, args, { env: this.defaultEnvWithPathsAdded(), cwd: this.projectRoot}), null, null); } else { @@ -439,24 +448,61 @@ to build apps for ${displayNameForPlatform(platform)}.`); } } - updatePlatforms(platforms = this.listInstalledPlatforms()) { - this.runCommands(`updating Cordova project for platforms \ + async updatePlatforms(platforms = this.listInstalledPlatforms()) { + return this.runCommands(`updating Cordova project for platforms \ ${displayNamesForPlatforms(platforms)}`, async () => { await cordova_lib.platform('update', platforms, this.defaultOptions); }); } - addPlatform(platform) { - this.runCommands(`adding platform ${displayNameForPlatform(platform)} \ + async addPlatform(platform) { + const self = this; + return self.runCommands(`adding platform ${displayNameForPlatform(platform)} \ to Cordova project`, async () => { let version = pinnedPlatformVersions[platform]; let platformSpec = version ? `${platform}@${version}` : platform; await cordova_lib.platform('add', platformSpec, this.defaultOptions); + + const installedPlugins = this.listInstalledPluginVersions(); + + // As per Npm 8, we need now do inject a package.json file + // with the dependencies so that when running any npm command + // it keeps the dependencies installed. + const packageLock = files.exists('node_modules/.package-lock.json') ? JSON.parse(files.readFile( + files.pathJoin(self.projectRoot, 'node_modules/.package-lock.json') + )) : { packages: { [`cordova-${platform}`]: { version } } }; + // Accumulated dependencies from plugins + const cordovaPackagesPath = files.pathJoin(self.projectRoot, cordovaPackagesFile); + const cordovaPackageLock = files.exists(cordovaPackagesPath) ? JSON.parse(files.readFile(cordovaPackagesPath)) : {}; + + // Ensure all packages are kept installed + const packages = { ...(cordovaPackageLock?.packages || {}), ...(packageLock?.packages || {}) }; + const getPackageName = (pkgPath) => { + const split = pkgPath.split("node_modules/"); + return split[split.length - 1]; + }; + + const packageJsonObj = Object.entries(packages).reduce((acc, [key, value]) => { + const name = getPackageName(key); + const originalPluginVersion = installedPlugins[name]; + return ({ + dependencies: { + ...acc.dependencies, + [name]: originalPluginVersion || value.version, + } + }); + }, { dependencies: { [`cordova-${platform}`]: version } }); + files.writeFile( + files.pathJoin(self.projectRoot, "package.json"), + JSON.stringify(packageJsonObj, null, 2) + "\n" + ); + + await meteorNpm.runNpmCommand(["install"], self.projectRoot); }); } - removePlatform(platform) { - this.runCommands(`removing platform ${displayNameForPlatform(platform)} \ + async removePlatform(platform) { + return this.runCommands(`removing platform ${displayNameForPlatform(platform)} \ from Cordova project`, async () => { await cordova_lib.platform('rm', platform, this.defaultOptions); }); @@ -468,7 +514,7 @@ from Cordova project`, async () => { // Ensures that the Cordova platforms are synchronized with the app-level // platforms. - ensurePlatformsAreSynchronized(platforms = this.cordovaPlatformsInApp) { + async ensurePlatformsAreSynchronized(platforms = this.cordovaPlatformsInApp) { buildmessage.assertInCapture(); const installedPlatforms = this.listInstalledPlatforms(); @@ -478,13 +524,13 @@ from Cordova project`, async () => { continue; } - this.addPlatform(platform); + await this.addPlatform(platform); } for (let platform of installedPlatforms) { if (!platforms.includes(platform) && CORDOVA_PLATFORMS.includes(platform)) { - this.removePlatform(platform); + await this.removePlatform(platform); } } } @@ -584,7 +630,7 @@ from Cordova project`, async () => { } } - addPlugin(id, version, config = {}, options = {}) { + async addPlugin(id, version, config = {}, options = {}) { const { retry = true } = options; const target = this.targetForPlugin(id, version, options); if (target) { @@ -592,16 +638,36 @@ from Cordova project`, async () => { { cli_variables: config, link: utils.isUrlWithFileScheme(version) }); try { - this.runCommands(`adding plugin ${target} \ + await this.runCommands(`adding plugin ${target} \ to Cordova project`, cordova_lib.plugin.bind(undefined, 'add', [target], commandOptions)); + + // Accumulate dependencies from plugins to later installation + const cordovaPackagesPath = files.pathJoin(this.projectRoot, cordovaPackagesFile); + const packageLock = JSON.parse(files.readFile( + files.pathJoin(this.projectRoot, 'node_modules/.package-lock.json') + )); + const existingPackageLock = files.exists(cordovaPackagesPath) ? + JSON.parse(files.readFile(cordovaPackagesPath)) + : {}; + const accumulatedCordovaPackages = { + packages: { + ...existingPackageLock.packages, + ...packageLock.packages, + } + }; + files.writeFile( + cordovaPackagesPath, + JSON.stringify(accumulatedCordovaPackages, null, 2) + "\n" + ); + } catch (error) { if (retry && utils.isUrlWithSha(version)) { Console.warn(`Cordova plugin add for ${id} failed with plugin id in the URL with hash, retrying now with plugin name. If this works you can ignore the error above or you can update your plugin declaration to use the id from config.xml instead of the name from package.json`); - this.addPlugin(id, version, config, { ...options, + await this.addPlugin(id, version, config, { ...options, usePluginName: true, retry: false }); return; } @@ -611,7 +677,7 @@ to Cordova project`, cordova_lib.plugin.bind(undefined, 'add', [target], } // plugins is an array of plugin IDs. - removePlugins(plugins, config = {}) { + async removePlugins(plugins, config = {}) { if (_.isEmpty(plugins)) { return; } @@ -619,24 +685,24 @@ to Cordova project`, cordova_lib.plugin.bind(undefined, 'add', [target], const commandOptions = Object.assign(this.defaultOptions, { cli_variables: config }); - plugins.forEach(plugin => { + for (const plugin of plugins) { const commandOptionsPlugin = getCommandOptionsForPlugin(plugin, commandOptions); - this.runCommands(`removing plugin ${plugin} \ + await this.runCommands(`removing plugin ${plugin} \ from Cordova project`, cordova_lib.plugin.bind(undefined, 'rm --force', [plugin], commandOptionsPlugin)); - }); + } } // Ensures that the Cordova plugins are synchronized with the app-level // plugins. - ensurePluginsAreSynchronized(pluginVersions, pluginsConfiguration = {}) { + async ensurePluginsAreSynchronized(pluginVersions, pluginsConfiguration = {}) { assert(pluginVersions); buildmessage.assertInCapture(); - buildmessage.enterJob({ title: "installing Cordova plugins"}, () => { + await buildmessage.enterJob({ title: "installing Cordova plugins"}, async () => { // Cordova plugin IDs have changed as part of moving to npm. // We convert old plugin IDs to new IDs in the 1.2.0-cordova-changes // upgrader and when adding plugins, but packages may still depend on @@ -754,7 +820,7 @@ perform cordova plugins reinstall`); Object.keys(installedPluginVersions)); } - this.removePlugins(pluginsToRemove, pluginsConfiguration); + await this.removePlugins(pluginsToRemove, pluginsConfiguration); let pluginVersionsToInstall; @@ -769,22 +835,22 @@ perform cordova plugins reinstall`); let installedPluginsCount = 0; buildmessage.reportProgress({ current: 0, end: pluginsToInstallCount }); - _.each(pluginVersionsToInstall, (version, id) => { - this.addPlugin(id, version, pluginsConfiguration[id]); + for (const [id, version] of Object.entries(pluginVersionsToInstall)) { + await this.addPlugin(id, version, pluginsConfiguration[id]); buildmessage.reportProgress({ current: ++installedPluginsCount, end: pluginsToInstallCount }); - }); + } - this.ensurePluginsWereInstalled(pluginVersionsToInstall, pluginsConfiguration, true); + await this.ensurePluginsWereInstalled(pluginVersionsToInstall, pluginsConfiguration, true); } }); } // Ensures that the Cordova plugins are installed - ensurePluginsWereInstalled(requiredPlugins, pluginsConfiguration, retryInstall) { + async ensurePluginsWereInstalled(requiredPlugins, pluginsConfiguration, retryInstall) { // List of all installed plugins. This should work for global / local / scoped cordova plugins. // Examples: // cordova-plugin-whitelist@1.3.2 => { 'cordova-plugin-whitelist': '1.3.2' } @@ -794,12 +860,12 @@ perform cordova plugins reinstall`); const installedPluginsNames = Object.keys(installed); const missingPlugins = {}; - Object.keys(requiredPlugins).filter(plugin => { + for (const plugin of Object.keys(requiredPlugins)) { if (!installedPluginsNames.includes(plugin)) { Console.debug(`Plugin ${plugin} was not installed.`); if (retryInstall) { Console.debug(`Retrying to install ${plugin}.`); - this.addPlugin( + await this.addPlugin( plugin, requiredPlugins[plugin], pluginsConfiguration[plugin] @@ -807,7 +873,7 @@ perform cordova plugins reinstall`); } missingPlugins[plugin] = requiredPlugins[plugin]; } - }); + } // All plugins were installed if (Object.keys(missingPlugins).length === 0) { @@ -816,7 +882,7 @@ perform cordova plugins reinstall`); // Check one more time after re-installation. if (retryInstall) { - this.ensurePluginsWereInstalled(missingPlugins, pluginsConfiguration, false); + await this.ensurePluginsWereInstalled(missingPlugins, pluginsConfiguration, false); } else { // Fail, to prevent building and publishing faulty mobile app without at this moment we need to stop. throw new Error(`Some Cordova plugins installation failed: (${Object.keys(missingPlugins).join(', ')}).`); @@ -872,7 +938,7 @@ convenience, but you should adjust your dependencies.`); return [nodeBinDir, iosSimBinPath]; } - runCommands(title, promiseOrAsyncFunction, env = this.defaultEnvWithPathsAdded(), + async runCommands(title, promiseOrAsyncFunction, env = this.defaultEnvWithPathsAdded(), cwd = this.projectRoot) { // Capitalize title for debug output Console.debug(title[0].toUpperCase() + title.slice(1)); @@ -891,9 +957,9 @@ convenience, but you should adjust your dependencies.`); } try { - const promise = (typeof promiseOrAsyncFunction === 'function') ? - promiseOrAsyncFunction() : promiseOrAsyncFunction; - return Promise.await(promise); + return await (typeof promiseOrAsyncFunction === "function" + ? promiseOrAsyncFunction() + : promiseOrAsyncFunction); } catch (error) { Console.arrowError('Errors executing Cordova commands:'); Console.error(); diff --git a/tools/cordova/run-targets.js b/tools/cordova/run-targets.js index e503f8eede..4860f6e59c 100644 --- a/tools/cordova/run-targets.js +++ b/tools/cordova/run-targets.js @@ -3,7 +3,7 @@ import chalk from 'chalk'; import { loadIsopackage } from '../tool-env/isopackets.js'; import { Console } from '../console/console.js'; import files from '../fs/files'; -import { execFileSync, execFileAsync } from '../utils/processes'; +import { execFileAsync } from '../utils/processes'; export class CordovaRunTarget { get title() { @@ -26,13 +26,13 @@ export class iOSRunTarget extends CordovaRunTarget { // ios-deploy is super buggy, so we just open Xcode and let the user // start the app themselves. if (this.isDevice) { - openXcodeProject(files.pathJoin(cordovaProject.projectRoot, + await openXcodeProject(files.pathJoin(cordovaProject.projectRoot, 'platforms', 'ios')); } else { await cordovaProject.run(this.platform, this.isDevice, undefined); // Bring iOS Simulator to front (it is called Simulator in Xcode 7) - execFileAsync('osascript', ['-e', + await execFileAsync('osascript', ['-e', `tell application "System Events" set possibleSimulatorNames to {"iOS Simulator", "Simulator"} repeat with possibleSimulatorName in possibleSimulatorNames @@ -45,9 +45,10 @@ end tell`]); } } -function openXcodeProject(projectDir) { - const projectFilename = files.readdir(projectDir).filter((entry) => - { return entry.match(/\.xcodeproj$/i) })[0]; +async function openXcodeProject(projectDir) { + const projectFilename = files.readdir(projectDir).filter((entry) => { + return entry.match(/\.xcodeproj$/i); + })[0]; if (!projectFilename) { printFailure(`Couldn't find your Xcode project in directory \ @@ -55,19 +56,17 @@ function openXcodeProject(projectDir) { return; } - try { - execFileSync('open', ['-a', 'Xcode', projectDir]); + await execFileAsync("open", ["-a", "Xcode", projectDir]); Console.info(); Console.info( chalk.green( "Your project has been opened in Xcode so that you can run your " + - "app on an iOS device. For further instructions, visit this " + - "wiki page: ") + - Console.url( - "https://guide.meteor.com/cordova.html#running-on-ios" - )); + "app on an iOS device. For further instructions, visit this " + + "wiki page: " + ) + Console.url("https://guide.meteor.com/cordova.html#running-on-ios") + ); Console.info(); } catch (error) { printFailure(`Failed to open your project in Xcode: @@ -79,7 +78,7 @@ ${error.message}`); Console.error(message); Console.error( chalk.green("Instructions for running your app on an iOS device: ") + - Console.url("https://guide.meteor.com/cordova.html#running-on-ios") + Console.url("https://guide.meteor.com/cordova.html#running-on-ios") ); Console.error(); } @@ -103,7 +102,7 @@ export class AndroidRunTarget extends CordovaRunTarget { let target = this.isDevice ? "-d" : "-e"; // Clear logs - execFileAsync('adb', [target, 'logcat', '-c']); + await execFileAsync('adb', [target, 'logcat', '-c']); await cordovaProject.run(this.platform, this.isDevice); @@ -130,7 +129,7 @@ export class AndroidRunTarget extends CordovaRunTarget { async tailLogs(cordovaProject, target) { const { transform } = require("../utils/eachline"); - cordovaProject.runCommands(`tailing logs for ${this.displayName}`, async () => { + await cordovaProject.runCommands(`tailing logs for ${this.displayName}`, async () => { await this.checkPlatformRequirementsAndSetEnv(cordovaProject); const logLevel = Console.verbose ? "V" : "I"; @@ -139,7 +138,7 @@ export class AndroidRunTarget extends CordovaRunTarget { `CordovaLog:${logLevel}`, `chromium:${logLevel}`, `SystemWebViewClient:${logLevel}`, '*:F']; - const { Log } = loadIsopackage('logging'); + const { Log } = await loadIsopackage('logging'); const logStream = transform(line => { const logEntry = logFromAndroidLogcatLine(Log, line); diff --git a/tools/cordova/runner.js b/tools/cordova/runner.js index cee0a60c78..e137b6010f 100644 --- a/tools/cordova/runner.js +++ b/tools/cordova/runner.js @@ -20,15 +20,15 @@ export class CordovaRunner { return _.uniq(this.runTargets.map((runTarget) => runTarget.platform)); } - checkPlatformsForRunTargets() { - this.cordovaProject.ensurePlatformsAreSynchronized(); + async checkPlatformsForRunTargets() { + await this.cordovaProject.ensurePlatformsAreSynchronized(); let satisfied = true; - const messages = buildmessage.capture( - { title: `checking platform requirements` }, () => { + const messages = await buildmessage.capture( + { title: `checking platform requirements` }, async () => { for (const platform of this.platformsForRunTargets) { satisfied = - this.cordovaProject.checkPlatformRequirements(platform) && + await this.cordovaProject.checkPlatformRequirements(platform) && satisfied; } }); @@ -69,11 +69,11 @@ export class CordovaRunner { } } - prepareProject(bundlePath, pluginVersions, options) { + async prepareProject(bundlePath, pluginVersions, options) { buildmessage.assertInCapture(); - buildmessage.enterJob({ title: "preparing Cordova project" }, () => { - this.cordovaProject.prepareFromAppBundle(bundlePath, + await buildmessage.enterJob({ title: "preparing Cordova project" }, async () => { + await this.cordovaProject.prepareFromAppBundle(bundlePath, pluginVersions, options); if (buildmessage.jobHasMessages()) { @@ -81,20 +81,23 @@ export class CordovaRunner { } for (let platform of this.platformsForRunTargets) { - this.cordovaProject.prepareForPlatform(platform, options); + await this.cordovaProject.prepareForPlatform(platform, options); } }); this.pluginVersions = pluginVersions; } - startRunTargets() { + async startRunTargets() { this.started = false; - for (let runTarget of this.runTargets) { - const messages = buildmessage.capture({ title: `starting ${runTarget.title}` }, () => { - Promise.await(runTarget.start(this.cordovaProject)); - }); + for (const runTarget of this.runTargets) { + const messages = await buildmessage.capture( + { title: `starting ${runTarget.title}` }, + async () => { + await runTarget.start(this.cordovaProject); + } + ); if (messages.hasMessages()) { Console.printMessages(messages); } else { diff --git a/tools/fs/files.ts b/tools/fs/files.ts index 0229231c23..1babe78416 100644 --- a/tools/fs/files.ts +++ b/tools/fs/files.ts @@ -4,29 +4,12 @@ /// (such as testing whether an directory is a meteor app) /// -import fs, { PathLike, Stats, Dirent } from "fs"; +import fs, { Dirent, PathLike, Stats } from "fs"; import os from "os"; import { execFile } from "child_process"; import { EventEmitter } from "events"; import { Slot } from "@wry/context"; import { dep } from "optimism"; - -const _ = require('underscore'); -const Fiber = require("fibers"); - -const rimraf = require('rimraf'); -const sourcemap = require('source-map'); -const sourceMapRetrieverStack = require('../tool-env/source-map-retriever-stack.js'); - -const utils = require('../utils/utils.js'); -const cleanup = require('../tool-env/cleanup.js'); -const buildmessage = require('../utils/buildmessage.js'); -const fiberHelpers = require('../utils/fiber-helpers.js'); -const colonConverter = require('../utils/colon-converter.js'); - -const Profile = require('../tool-env/profile').Profile; - -export * from '../static-assets/server/mini-files'; import { convertToOSPath, convertToPosixPath, @@ -43,6 +26,23 @@ import { pathResolve, pathSep, } from "../static-assets/server/mini-files"; +import { realpathSync } from './fsFixPath'; + +const _ = require('underscore'); + +const rimraf = require('rimraf'); +const sourcemap = require('source-map'); +const sourceMapRetrieverStack = require('../tool-env/source-map-retriever-stack.js'); + +const utils = require('../utils/utils.js'); +const cleanup = require('../tool-env/cleanup.js'); +const buildmessage = require('../utils/buildmessage.js'); +const fiberHelpers = require('../utils/fiber-helpers.js'); +const colonConverter = require('../utils/colon-converter.js'); + +const Profile = require('../tool-env/profile').Profile; + +export * from '../static-assets/server/mini-files'; const { hasOwnProperty } = Object.prototype; @@ -62,11 +62,11 @@ function useParsedSourceMap(pathForSourceMap: string) { // Try this source map first sourceMapRetrieverStack.push(useParsedSourceMap); -function canYield() { - return Fiber.current && - Fiber.yield && - ! Fiber.yield.disallowed; -} +// function canYield() { +// return Fiber.current && +// Fiber.yield && +// ! Fiber.yield.disallowed; +// } // given a predicate function and a starting path, traverse upwards // from the path until we find a path that satisfies the predicate. @@ -148,7 +148,7 @@ export function findGitCommitHash(path: string) { } else { resolve(); } - }).await(); + }); } // create a .gitignore file in dirPath if one doesn't exist. add @@ -203,22 +203,19 @@ export function usesWarehouse() { export function getToolsVersion() { if (! inCheckout()) { const isopackJsonPath = pathJoin(getCurrentToolsDir(), - '..', // get out of tool, back to package - 'isopack.json'); - + '..', // get out of tool, back to package + 'isopack.json'); let parsed; - if (exists(isopackJsonPath)) { // XXX "isopack-1" is duplicate of isopack.currentFormat parsed = JSON.parse(readFile(isopackJsonPath))["isopack-1"]; return parsed.name + '@' + parsed.version; } - // XXX COMPAT WITH 0.9.3 const unipackageJsonPath = pathJoin( - getCurrentToolsDir(), - '..', // get out of tool, back to package - 'unipackage.json' + getCurrentToolsDir(), + '..', // get out of tool, back to package + 'unipackage.json' ); parsed = JSON.parse(readFile(unipackageJsonPath)); return parsed.name + '@' + parsed.version; @@ -239,6 +236,10 @@ export function getCurrentNodeBinDir() { // Return the top-level directory for this meteor install or checkout export function getCurrentToolsDir() { + if (!process.env.SANDBOX && process.env.METEOR_WAREHOUSE_DIR) { + return pathDirname(realpathSync(pathJoin(process.env.METEOR_WAREHOUSE_DIR, 'meteor'))); + } + return pathDirname(pathDirname(convertToStandardPath(__dirname))); } @@ -344,35 +345,41 @@ export function rm_recursive_async(path: string) { } // Like rm -r. -export const rm_recursive = Profile("files.rm_recursive", (path: string) => { +export const rm_recursive = Profile("files.rm_recursive", async (path: string) => { try { rimraf.sync(convertToOSPath(path)); } catch (e: any) { if ((e.code === "ENOTEMPTY" || - e.code === "EPERM") && - canYield()) { - rm_recursive_async(path).await(); + e.code === "EPERM")) { + await rm_recursive_async(path); return; } throw e; } }); +export const rm_recursive_deferred = Profile("files.rm_recursive_deferred", async (path: string) => { + // Generate a temp path name for the old build directory + const oldBuildPath = path + '.old-' + Math.floor(Math.random() * 999999); + // If the original buildPath exists, rename it first + if (exists(path)) { + await rename(path, oldBuildPath); + // Start deletion of old directory asynchronously without awaiting + rm_recursive(oldBuildPath).catch(e => { + // Log error but don't fail the build + console.error(`Error removing old build directory ${oldBuildPath}:`, e); + }); + } +}); + // Returns the base64 SHA256 of the given file. export function fileHash(filename: string) { const crypto = require('crypto'); const hash = crypto.createHash('sha256'); - hash.setEncoding('base64'); - const rs = createReadStream(filename); - return new Promise(function (resolve) { - rs.on('end', function () { - rs.close(); - resolve(hash.digest('base64')); - }); - rs.pipe(hash, { end: false }); - }).await(); + const fileBuff = readFile(filename); + hash.update(fileBuff); + return hash.digest('base64'); } - // This is the result of running fileHash on a blank file. export const blankHash = "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="; @@ -387,9 +394,9 @@ export function treeHash(root: string, optionsParams: { ...optionsParams, }; - const hash = require('crypto').createHash('sha256'); + function traverse(relativePath: string) { + const hash = require('crypto').createHash('sha256'); - function traverse(relativePath: string) { if (options.ignore(relativePath)) { return; } @@ -408,8 +415,9 @@ export function treeHash(root: string, optionsParams: { if (!relativePath) { throw Error("must call files.treeHash on a directory"); } + const fileHashed = fileHash(absPath); hash.update('file ' + JSON.stringify(relativePath) + ' ' + - stat?.size + ' ' + fileHash(absPath) + '\n'); + stat?.size + ' ' + fileHashed + '\n'); // @ts-ignore if (stat.mode & 0o100) { @@ -423,9 +431,11 @@ export function treeHash(root: string, optionsParams: { JSON.stringify(readlink(absPath)) + '\n'); } // ignore anything weirder + + return hash } - traverse(''); + const hash = traverse(''); return hash.digest('base64'); } @@ -489,7 +499,7 @@ function pathIsDirectory(path: string) { // If options.ignore is present, it should be a list of regexps. Any // file whose basename matches one of the regexps, before // transformation, will be skipped. -export function cp_r(from: string, to: string, options: { +export async function cp_r(from: string, to: string, options: { preserveSymlinks?: boolean; ignore?: RegExp[]; transformFilename?: (f: string) => string; @@ -508,7 +518,7 @@ export function cp_r(from: string, to: string, options: { if (stat.isDirectory()) { mkdir_p(to, 0o755); - readdir(from).forEach(f => { + for (let f of readdir(from)) { if (options.ignore && options.ignore.some(pattern => f.match(pattern))) { return; @@ -517,15 +527,15 @@ export function cp_r(from: string, to: string, options: { const fullFrom = pathJoin(from, f); if (options.transformFilename) { - f = options.transformFilename(f); + f = await options.transformFilename(f); } - cp_r( - fullFrom, - pathJoin(to, f), - options + await cp_r( + fullFrom, + pathJoin(to, f), + options ); - }) + } return; } @@ -533,10 +543,9 @@ export function cp_r(from: string, to: string, options: { mkdir_p(pathDirname(to)); if (stat.isSymbolicLink()) { - symlinkWithOverwrite(readlink(from), to); - + await symlinkWithOverwrite(readlink(from), to); } else if (options.transformContents) { - writeFile(to, options.transformContents( + writeFile(to, await options.transformContents( readFile(from), pathBasename(from) ), { @@ -559,7 +568,7 @@ export function cp_r(from: string, to: string, options: { // create a symlink, overwriting the target link, file, or directory // if it exists export const symlinkWithOverwrite = -Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite( +Profile("files.symlinkWithOverwrite", async function symlinkWithOverwrite( source: string, target: string, ) { @@ -588,7 +597,7 @@ Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite( return; } // overwrite existing link, file, or directory - rm_recursive(target); + await rm_recursive(target); symlink(...args); } else { throw e; @@ -607,6 +616,7 @@ Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite( export function getPathsInDir(dir: string, options: { cwd?: string; output?: string[]; + maxDepth?: number; }) { // Don't let this function yield so that the file system doesn't get changed // underneath us @@ -626,6 +636,7 @@ export function getPathsInDir(dir: string, options: { } const output = options.output || []; + const maxDepth = options.maxDepth; function pathIsDirectory(path: string) { var stat = lstat(path); @@ -638,10 +649,12 @@ export function getPathsInDir(dir: string, options: { output.push(newPath); - if (pathIsDirectory(newAbsPath)) { + const nextMaxDepth = maxDepth != null ? maxDepth - 1 : maxDepth; + if (pathIsDirectory(newAbsPath) && (nextMaxDepth == null || nextMaxDepth > 0)) { getPathsInDir(newPath, { cwd: cwd, - output: output + output: output, + ...nextMaxDepth != null && { maxDepth: nextMaxDepth }, }); } }); @@ -704,6 +717,7 @@ export function mkdtemp(prefix: string): string { mkdir(dirPath, 0o700); return dirPath; } catch (err) { + console.error(err); tries--; } } @@ -748,10 +762,10 @@ export function changeTempDirStatus(dir: string, status: boolean) { if (! process.env.METEOR_SAVE_TMPDIRS) { cleanup.onExit(function () { - Object.entries(tempDirs).filter(([_, isTmp]) => !!isTmp).map(([dir]) => dir).forEach(dir => { + return Object.entries(tempDirs).filter(([_, isTmp]) => !!isTmp).map(([dir]) => dir).map(async dir => { delete tempDirs[dir]; try { - rm_recursive(dir); + await rm_recursive(dir); } catch (err) { // Don't crash and print a stack trace because we failed to delete // a temp directory. This happens sometimes on Windows and seems @@ -770,7 +784,7 @@ type TarOptions = { // into a destination directory. destPath should not exist yet, and // the archive should contain a single top-level directory, which will // be renamed atomically to destPath. -export function extractTarGz( +export async function extractTarGz( buffer: Buffer, destPath: string, options: TarOptions = {}, @@ -786,9 +800,7 @@ export function extractTarGz( const startTime = +new Date; // standardize only one way of extracting, as native ones can be tricky - const promise = tryExtractWithNpmTar(buffer, tempDir, options) - - promise.await(); + await tryExtractWithNpmTar(buffer, tempDir, options); // succeed! const topLevelOfArchive = readdir(tempDir) @@ -802,8 +814,8 @@ export function extractTarGz( } const extractDir = pathJoin(tempDir, topLevelOfArchive[0]); - rename(extractDir, destPath); - rm_recursive(tempDir); + await rename(extractDir, destPath); + await rm_recursive(tempDir); if (options.verbose) { console.log("Finished extracting in", Date.now() - startTime, "ms"); @@ -905,11 +917,11 @@ export const createTarball = Profile(function (_: string, tarball: string) { return "files.createTarball " + pathBasename(tarball); }, function (dirPath: string, tarball: string) { const out = createWriteStream(tarball); - new Promise(function (resolve, reject) { + return new Promise(function (resolve, reject) { out.on('error', reject); out.on('close', resolve); createTarGzStream(dirPath).pipe(out); - }).await(); + }); }); // Use this if you'd like to replace a directory with another @@ -920,7 +932,7 @@ export const createTarball = Profile(function (_: string, tarball: string) { // sitting around", but not "there's any time where toDir exists but // is in a state other than initial or final".) export const renameDirAlmostAtomically = -Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => { +Profile("files.renameDirAlmostAtomically", async (fromDir: string, toDir: string) => { const garbageDir = pathJoin( pathDirname(toDir), // Begin the base filename with a '.' character so that it can be @@ -932,7 +944,7 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => { let cleanupGarbage = false; let forceCopy = false; try { - rename(toDir, garbageDir); + await rename(toDir, garbageDir); cleanupGarbage = true; } catch (e: any) { if (e.code === 'EXDEV') { @@ -951,7 +963,7 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => { if (! forceCopy) { try { - rename(fromDir, toDir); + await rename(fromDir, toDir); } catch (e: any) { // It's possible that there may not have been a `toDir` to have // advanced warning about this, so we're prepared to handle it again. @@ -966,8 +978,8 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => { // If we've been forced to jeopardize our atomicity due to file-system // limitations, we'll resort to copying. if (forceCopy) { - rm_recursive(toDir); - cp_r(fromDir, toDir, { + await rm_recursive(toDir); + await cp_r(fromDir, toDir, { preserveSymlinks: true, }); } @@ -975,12 +987,12 @@ Profile("files.renameDirAlmostAtomically", (fromDir: string, toDir: string) => { // ... and take out the trash. if (cleanupGarbage) { // We don't care about how long this takes, so we'll let it go async. - rm_recursive_async(garbageDir); + await rm_recursive_async(garbageDir); } }); export const writeFileAtomically = -Profile("files.writeFileAtomically", function (filename: string, contents: string | Buffer) { +Profile("files.writeFileAtomically", async function (filename: string, contents: string | Buffer) { const parentDir = pathDirname(filename); mkdir_p(parentDir); @@ -990,19 +1002,19 @@ Profile("files.writeFileAtomically", function (filename: string, contents: strin ); writeFile(tmpFile, contents); - rename(tmpFile, filename); + await rename(tmpFile, filename); }); // Like fs.symlinkSync, but creates a temporary link and renames it over the // file; this means it works even if the file already exists. // Do not use this function on Windows, it won't work. -export function symlinkOverSync(linkText: string, file: string) { +export async function symlinkOverSync(linkText: string, file: string) { file = pathResolve(file); const tmpSymlink = pathJoin( pathDirname(file), "." + pathBasename(file) + ".tmp" + utils.randomToken()); symlink(linkText, tmpSymlink); - rename(tmpSymlink, file); + await rename(tmpSymlink, file); } // Return the result of evaluating `code` using @@ -1034,7 +1046,7 @@ export function runJavaScript(code: string, { sourceMap?: object; sourceMapRoot?: string; }) { - return Profile.time('runJavaScript ' + filename, () => { + return Profile.time('runJavaScript ' + filename, async () => { const keys: string[] = [], values: any[] = []; // don't assume that _.keys and _.values are guaranteed to // enumerate in the same order @@ -1054,7 +1066,7 @@ export function runJavaScript(code: string, { const header = "(function(" + keys.join(',') + "){"; chunks.push(header); if (sourceMap) { - const sourcemapConsumer = Promise.await(new sourcemap.SourceMapConsumer(sourceMap)); + const sourcemapConsumer = await new sourcemap.SourceMapConsumer(sourceMap); chunks.push(sourcemap.SourceNode.fromStringWithSourceMap( code, sourcemapConsumer)); sourcemapConsumer.destroy(); @@ -1126,7 +1138,7 @@ export function runJavaScript(code: string, { if (parsedSourceMap) { // XXX this duplicates code in computeGlobalReferences - var consumer2 = Promise.await(new sourcemap.SourceMapConsumer(parsedSourceMap)); + var consumer2 = await new sourcemap.SourceMapConsumer(parsedSourceMap); var original = consumer2.originalPositionFor(parseError.loc); consumer2.destroy(); if (original.source) { @@ -1156,7 +1168,7 @@ export function runJavaScript(code: string, { } return buildmessage.markBoundary( - script.runInThisContext() + await script.runInThisContext() ).apply(null, values); }); } @@ -1377,7 +1389,7 @@ export function _getLocationFromScriptLinkToMeteorScript(script: string | Buffer return convertToPosixPath(scriptLocation, ! isAbsolute); } -export function linkToMeteorScript( +export async function linkToMeteorScript( scriptLocation: string, linkLocation: string, platform: string, @@ -1392,7 +1404,7 @@ export function linkToMeteorScript( writeFile(linkLocation, script, { encoding: "ascii" }); } else { // Symlink meteor tool - symlinkOverSync(scriptLocation, linkLocation); + await symlinkOverSync(scriptLocation, linkLocation); } } @@ -1617,15 +1629,15 @@ export const rename = isWindowsLikeFilesystem() ? function (from: string, to: st } } attempt(); - }).catch((error: any) => { + }).catch(async (error: any) => { if (error.code === 'EPERM' || - error.code === 'EACCESS') { - cp_r(from, to, { preserveSymlinks: true }); - rm_recursive(from); + error.code === 'EACCES') { + await cp_r(from, to, { preserveSymlinks: true }); + await rm_recursive(from); } else { throw error; } - }).await(); + }); } : wrappedRename; // Warning: doesn't convert slashes in the second 'cache' arg diff --git a/tools/fs/optimistic.ts b/tools/fs/optimistic.ts index 61da929a65..8f59486eb3 100644 --- a/tools/fs/optimistic.ts +++ b/tools/fs/optimistic.ts @@ -342,14 +342,21 @@ export const optimisticReadMeteorIgnore = wrap((dir: string) => { const meteorIgnorePath = pathJoin(dir, ".meteorignore"); const meteorIgnoreStat = optimisticStatOrNull(meteorIgnorePath); + let ignoreConfig = null; if (meteorIgnoreStat && meteorIgnoreStat.isFile()) { - return ignore().add( - optimisticReadFile(meteorIgnorePath).toString("utf8") + ignoreConfig = ignore().add( + optimisticReadFile(meteorIgnorePath).toString("utf8") ); } - return null; + const customMeteorIgnore = process.env.METEOR_IGNORE; + if (customMeteorIgnore != null) { + ignoreConfig = ignoreConfig || ignore(); + ignoreConfig = ignoreConfig.add(customMeteorIgnore); + } + + return ignoreConfig; }); type LookupPkgJsonType = OptimisticWrapperFunction< diff --git a/tools/fs/safe-watcher-legacy.ts b/tools/fs/safe-watcher-legacy.ts new file mode 100644 index 0000000000..f9f108afc8 --- /dev/null +++ b/tools/fs/safe-watcher-legacy.ts @@ -0,0 +1,476 @@ +import { FSWatcher, Stats, BigIntStats } from "fs"; +import { Profile } from "../tool-env/profile"; +import { + statOrNull, + convertToOSPath, + watchFile, + unwatchFile, + toPosixPath, + pathRelative +} from "./files"; +import { + join as nativeJoin +} from 'path'; +import nsfw from 'vscode-nsfw'; + +const pathwatcher = require('pathwatcher'); + +// Default to prioritizing changed files, but disable that behavior (and +// thus prioritize all files equally) if METEOR_WATCH_PRIORITIZE_CHANGED +// is explicitly set to a string that parses to a falsy value. +var PRIORITIZE_CHANGED = true; +if (process.env.METEOR_WATCH_PRIORITIZE_CHANGED && + ! JSON.parse(process.env.METEOR_WATCH_PRIORITIZE_CHANGED)) { + PRIORITIZE_CHANGED = false; +} + +var DEFAULT_POLLING_INTERVAL = + +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 5000); + +var NO_WATCHER_POLLING_INTERVAL = + +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 500); + +// This may seems like a long time to wait before actually closing the +// file watchers, but it's to our advantage if they survive restarts. +const WATCHER_CLEANUP_DELAY_MS = 30000; + +// Since linux doesn't have recursive file watching, nsfw has to walk the +// watched folder and create a separate watcher for each subfolder. Until it has a +// way for us to filter which folders it walks we will continue to use +// pathwatcher to avoid having too many watchers. +let watcherLibrary = process.env.METEOR_WATCHER_LIBRARY || + (process.platform === 'linux' ? 'pathwatcher' : 'nsfw'); + +// Pathwatcher complains (using console.error, ugh) if you try to watch +// two files with the same stat.ino number but different paths on linux, so we have +// to deduplicate files by ino. +const DEDUPLICATE_BY_INO = watcherLibrary === 'pathwatcher'; +// Set METEOR_WATCH_FORCE_POLLING environment variable to a truthy value to +// force the use of files.watchFile instead of watchLibrary.watch. +let watcherEnabled = ! JSON.parse( + process.env.METEOR_WATCH_FORCE_POLLING || "false" +); + +const entriesByIno = new Map; + +export type SafeWatcher = { + close: () => void; +} + +type EntryCallback = (event: string) => void; + +interface Entry extends SafeWatcher { + callbacks: Set; + rewatch: () => void; + release: (callback: EntryCallback) => void; + _fire: (event: string) => void; +} + +const entries: Record = Object.create(null); + +// Folders that are watched recursively +let watchRoots = new Set(); + +// Set of paths for which a change event has been fired, watched with +// watchLibrary.watch if available. This could be an LRU cache, but in +// practice it should never grow large enough for that to matter. +const changedPaths = new Set; + +function hasPriority(absPath: string) { + // If we're not prioritizing changed files, then all files have + // priority, which means they should be watched with native file + // watchers if the platform supports them. If we are prioritizing + // changed files, then only changed files get priority. + return PRIORITIZE_CHANGED + ? changedPaths.has(absPath) + : true; +} + +function acquireWatcher(absPath: string, callback: EntryCallback) { + const entry = entries[absPath] || ( + entries[absPath] = startNewWatcher(absPath)); + + // Watches successfully established in the past may have become invalid + // because the watched file was deleted or renamed, so we need to make + // sure we're still watching every time we call safeWatcher.watch. + entry.rewatch(); + + // The size of the entry.callbacks Set also serves as a reference count + // for this watcher. + entry.callbacks.add(callback); + + return entry; +} + +function startNewWatcher(absPath: string): Entry { + let stat: Stats | BigIntStats | null | undefined = null; + + if (DEDUPLICATE_BY_INO) { + stat = statOrNull(absPath); + if (stat && stat.ino > 0 && entriesByIno.has(stat.ino)) { + const entry = entriesByIno.get(stat.ino); + if (entries[absPath] === entry) { + return entry; + } + } + } else { + let entry = entries[absPath]; + if (entry) { + return entry; + } + } + + function safeUnwatch() { + if (watcher) { + watcher.close(); + watcher = null; + if (stat && stat.ino > 0) { + entriesByIno.delete(stat.ino); + } + } + } + + let lastWatcherEventTime = Date.now(); + const callbacks = new Set(); + let watcherCleanupTimer: ReturnType | null = null; + let watcher: FSWatcher | null = null; + + // Determines the polling interval to be used for the fs.watchFile-based + // safety net that works on all platforms and file systems. + function getPollingInterval() { + if (hasPriority(absPath)) { + // Regardless of whether we have a native file watcher and it works + // correctly on this file system, poll prioritized files (that is, + // files that have been changed at least once) at a higher frequency + // (every 500ms by default). + return NO_WATCHER_POLLING_INTERVAL; + } + + if (watcherEnabled || PRIORITIZE_CHANGED) { + // As long as native file watching is enabled (even if it doesn't + // work correctly) and the developer hasn't explicitly opted out of + // the file watching priority system, poll unchanged files at a + // lower frequency (every 5000ms by default). + return DEFAULT_POLLING_INTERVAL; + } + + // If native file watching is disabled and the developer has + // explicitly opted out of the priority system, poll everything at the + // higher frequency (every 500ms by default). Note that this leads to + // higher idle CPU usage, so the developer may want to adjust the + // METEOR_WATCH_POLLING_INTERVAL_MS environment variable. + return NO_WATCHER_POLLING_INTERVAL; + } + + function fire(event: string) { + if (event !== "change") { + // When we receive a "delete" or "rename" event, the watcher is + // probably not going to generate any more notifications for this + // file, so we close and nullify the watcher to ensure that + // entry.rewatch() will attempt to reestablish the watcher the next + // time we call safeWatcher.watch. + safeUnwatch(); + + // Make sure we don't throttle the watchFile callback after a + // "delete" or "rename" event, since it is now our only reliable + // source of file change notifications. + lastWatcherEventTime = 0; + + } else { + changedPaths.add(absPath); + rewatch(); + } + + callbacks.forEach(cb => cb(event)); + } + + function watchWrapper(event: string) { + lastWatcherEventTime = Date.now(); + fire(event); + + // It's tempting to call unwatchFile(absPath, watchFileWrapper) here, + // but previous watcher success is no guarantee of future watcher + // reliability. For example, watchLibrary.watch works just fine when file + // changes originate from within a Vagrant VM, but changes to shared + // files made outside the VM are invisible to watcher, so our only + // hope of catching them is to continue polling. + } + + function rewatch() { + if (hasPriority(absPath)) { + if (watcher) { + // Already watching; nothing to do. + return; + } + watcher = watchLibraryWatch(absPath, watchWrapper); + } else if (watcher) { + safeUnwatch(); + } + + // Since we're about to restart the stat-based file watcher, we don't + // want to miss any of its events because of the lastWatcherEventTime + // throttling that it attempts to do. + lastWatcherEventTime = 0; + + // We use files.watchFile in addition to watcher.watch as a fail-safe + // to detect file changes even on network file systems. However + // (unless the user disabled watcher or this watcher call failed), we + // use a relatively long default polling interval of 5000ms to save + // CPU cycles. + statWatch(absPath, getPollingInterval(), watchFileWrapper); + } + + function watchFileWrapper(newStat: Stats, oldStat: Stats) { + if (newStat.ino === 0 && + oldStat.ino === 0 && + +newStat.mtime === +oldStat.mtime) { + // Node calls the watchFile listener once with bogus identical stat + // objects, which should not trigger a file change event. + return; + } + + // If a watcher event fired in the last polling interval, ignore + // this event. + if (Date.now() - lastWatcherEventTime > getPollingInterval()) { + fire("change"); + } + } + + const entry = { + callbacks, + rewatch, + + release(callback: EntryCallback) { + if (! entries[absPath]) { + return; + } + + callbacks.delete(callback); + if (callbacks.size > 0) { + return; + } + + // Once there are no more callbacks in the Set, close both watchers + // and nullify the shared data. + if (watcherCleanupTimer) { + clearTimeout(watcherCleanupTimer); + } + + watcherCleanupTimer = setTimeout(() => { + if (callbacks.size > 0) { + // If another callback was added while the timer was pending, we + // can avoid tearing anything down. + return; + } + entry.close(); + }, WATCHER_CLEANUP_DELAY_MS); + }, + + close() { + if (entries[absPath] !== entry) return; + entries[absPath] = null; + + if (watcherCleanupTimer) { + clearTimeout(watcherCleanupTimer); + watcherCleanupTimer = null; + } + + safeUnwatch(); + + unwatchFile(absPath, watchFileWrapper); + }, + _fire: fire + }; + + if (stat && stat.ino > 0) { + entriesByIno.set(stat.ino, entry); + } + + return entry; +} + +export function closeAllWatchers() { + Object.keys(entries).forEach(absPath => { + const entry = entries[absPath]; + if (entry) { + entry.close(); + } + }); +} + +const statWatchers = Object.create(null); + +function statWatch( + absPath: string, + interval: number, + callback: (current: Stats, previous: Stats) => void, +) { + let statWatcher = statWatchers[absPath]; + + if (!statWatcher) { + statWatcher = { + interval, + changeListeners: [], + stat: null + }; + statWatchers[absPath] = statWatcher; + } + + // If the interval needs to be changed, replace the watcher. + // Node will only recreate the watcher with the new interval if all old + // watchers are stopped (which unwatchFile does when not passed a + // specific listener) + if (statWatcher.interval !== interval && statWatcher.stat) { + // This stops all stat watchers for the file, not just those created by + // statWatch + unwatchFile(absPath); + statWatcher.stat = null; + statWatcher.interval = interval; + } + + if (!statWatcher.changeListeners.includes(callback)) { + statWatcher.changeListeners.push(callback); + } + + if (!statWatcher.stat) { + const newStat = watchFile(absPath, { + persistent: false, // never persistent + interval, + }, (newStat, oldStat) => { + statWatcher.changeListeners.forEach(( + listener: (newStat: Stats, oldStat: Stats) => void + ) => { + listener(newStat, oldStat); + }); + }); + + newStat.on("stop", () => { + if (statWatchers[absPath] === statWatch) { + delete statWatchers[absPath]; + } + }); + + statWatcher.stat = newStat; + } + + return statWatcher; +} + +function watchLibraryWatch(absPath: string, callback: EntryCallback) { + if (watcherEnabled && watcherLibrary === 'pathwatcher') { + try { + return pathwatcher.watch(convertToOSPath(absPath), callback); + } catch (e: any) { + maybeSuggestRaisingWatchLimit(e); + // ... ignore the error. We'll still have watchFile, which is good + // enough. + } + } + + return null; +} + +let suggestedRaisingWatchLimit = false; + +function maybeSuggestRaisingWatchLimit(error: Error & { errno: number }) { + var constants = require('constants'); + var archinfo = require('../utils/archinfo'); + if (! suggestedRaisingWatchLimit && + // Note: the not-super-documented require('constants') maps from + // strings to SYSTEM errno values. System errno values aren't the same + // as the numbers used internally by libuv! Once we're upgraded + // to Node 0.12, we'll have the system errno as a string (on 'code'), + // but the support for that wasn't in Node 0.10's uv. + // See our PR https://github.com/atom/node-pathwatcher/pull/53 + // (and make sure to read the final commit message, not the original + // proposed PR, which had a slightly different interface). + error.errno === constants.ENOSPC && + // The only suggestion we currently have is for Linux. + archinfo.matches(archinfo.host(), 'os.linux')) { + + // Check suggestedRaisingWatchLimit again because archinfo.host() may + // have yielded. + if (suggestedRaisingWatchLimit) return; + suggestedRaisingWatchLimit = true; + + var Console = require('../console/console.js').Console; + if (! Console.isHeadless()) { + Console.arrowWarn( + "It looks like a simple tweak to your system's configuration will " + + "make many tools (including this Meteor command) more efficient. " + + "To learn more, see " + + Console.url("https://github.com/meteor/docs/blob/master/long-form/file-change-watcher-efficiency.md")); + } + } +} + +export const watch = Profile( + "safeWatcher.watchLegacy", + (absPath: string, callback: EntryCallback) => { + const entry = acquireWatcher(absPath, callback); + return { + close() { + entry.release(callback); + } + } as SafeWatcher; + } +); + +const fireNames = { + [nsfw.actions.CREATED]: 'change', + [nsfw.actions.MODIFIED]: 'change', + [nsfw.actions.DELETED]: 'delete' +} + +export function addWatchRoot(absPath: string) { + if (watchRoots.has(absPath) || watcherLibrary !== 'nsfw' || !watcherEnabled) { + return; + } + + watchRoots.add(absPath); + + // If there already is a watcher for a parent directory, there is no need + // to create this watcher. + for (const path of watchRoots) { + let relativePath = pathRelative(path, absPath); + if ( + path !== absPath && + !relativePath.startsWith('..') && + !relativePath.startsWith('/') + ) { + return; + } + } + + // TODO: check if there are any existing watchers that are children of this + // watcher and stop them + + nsfw( + convertToOSPath(absPath), + (events) => { + events.forEach(event => { + if(event.action === nsfw.actions.RENAMED) { + let oldPath = nativeJoin(event.directory, event.oldFile); + let oldEntry = entries[toPosixPath(oldPath)]; + if (oldEntry) { + oldEntry._fire('rename'); + } + + let path = nativeJoin(event.newDirectory, event.newFile); + let newEntry = entries[toPosixPath(path)]; + if (newEntry) { + newEntry._fire('change'); + } + } else { + let path = nativeJoin(event.directory, event.file); + let entry = entries[toPosixPath(path)]; + if (entry) { + entry._fire(fireNames[event.action]); + } + } + }) + } + ).then(watcher => { + watcher.start() + }); +} diff --git a/tools/fs/safe-watcher.ts b/tools/fs/safe-watcher.ts index 6b4f9edb0e..07fe605fb7 100644 --- a/tools/fs/safe-watcher.ts +++ b/tools/fs/safe-watcher.ts @@ -1,478 +1,624 @@ -import { FSWatcher, Stats, BigIntStats } from "fs"; +import { Stats } from 'fs'; +import ParcelWatcher from "@parcel/watcher"; +import { watch as watchLegacy, addWatchRoot as addWatchRootLegacy, closeAllWatchers as closeAllWatchersLegacy } from './safe-watcher-legacy'; + import { Profile } from "../tool-env/profile"; -import { - statOrNull, - convertToOSPath, - watchFile, - unwatchFile, - toPosixPath, - pathRelative -} from "./files"; -import { - join as nativeJoin -} from 'path'; -import nsfw from 'vscode-nsfw'; +import { statOrNull, lstat, toPosixPath, convertToOSPath, pathRelative, watchFile, unwatchFile, pathResolve, pathDirname } from "./files"; +import { getMeteorConfig } from "../tool-env/meteor-config"; -const pathwatcher = require('pathwatcher'); +// Register process exit handlers to ensure subscriptions are properly cleaned up +const registerExitHandlers = () => { + + // For SIGINT and SIGTERM, we need to handle the async cleanup before the process exits + const cleanupAndExit = (signal: string) => { + // Clear the timeout if cleanup completes successfully + closeAllWatchers().then(() => { + process.exit(0); + }).catch(err => { + console.error(`Error closing watchers on ${signal}:`, err); + process.exit(1); + }); + }; + + // Handle SIGINT (Ctrl+C) + process.on('SIGINT', () => cleanupAndExit('SIGINT')); + + // Handle SIGTERM + process.on('SIGTERM', () => cleanupAndExit('SIGTERM')); + + // Handle 'exit' event + process.on('exit', () => { + try { + for (const root of Array.from(watchRoots)) { + const sub = dirSubscriptions.get(root); + if (sub) { + sub.unsubscribe(); + dirSubscriptions.delete(root); + watchRoots.delete(root); + } + } + } catch (err) { + console.error('Error during synchronous cleanup on exit:', err); + } + }); +}; + +export type SafeWatcher = { close: () => void; }; + +type ChangeCallback = (event: string) => void; + +interface Entry extends SafeWatcher { + callbacks: Set; + _fire(event: string): void; +} + +// Registry mapping normalized absolute paths to their watcher entry. +const entries = new Map(); + +// Registry mapping normalized absolute paths to their polling watchers. +// Each path can have multiple callbacks, but only one active watcher. +interface PollingWatcherInfo { + callbacks: Set; + pollCallback: (curr: Stats, prev: Stats) => void; +} +const pollingWatchers = new Map(); + +function getEntry(path: string): Entry | null | undefined { + return entries.get(path); +} + +function setEntry(path: string, entry: Entry | null): void { + entries.set(path, entry); +} + +function deleteEntry(path: string): void { + entries.delete(path); +} + +function findNearestEntry(startPath: string): Entry | null { + let currentPath = pathResolve(startPath); + + while (true) { + const entry = getEntry(currentPath); + if (entry) { + return entry; // Found it! + } + + const parentPath = pathDirname(currentPath); + if (parentPath === currentPath) { + // Reached root + break; + } + + currentPath = parentPath; + } + + return null; +} + +// Watch roots are directories for which we have an active ParcelWatcher subscription. +const watchRoots = new Set(); +// For each watch root, store its active subscription. +const dirSubscriptions = new Map(); +// A set of roots that are known to be unwatchable. +const ignoredWatchRoots = new Set(); + +// A set of roots that are known to be symbolic links. +const symlinkRoots = new Set(); + +// Set METEOR_WATCH_FORCE_POLLING environment variable to a truthy value to +// force the use of files.watchFile instead of ParcelWatcher. +let watcherEnabled = !JSON.parse(process.env.METEOR_WATCH_FORCE_POLLING || "false"); + +/** + * Polling fallback globals. + * The legacy Meteor strategy used polling for cases where native watchers failed. + * We keep track of files that changed, so that we can poll them faster. + */ +var DEFAULT_POLLING_INTERVAL = + +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 5000); + +var NO_WATCHER_POLLING_INTERVAL = + +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 500); -// Default to prioritizing changed files, but disable that behavior (and -// thus prioritize all files equally) if METEOR_WATCH_PRIORITIZE_CHANGED -// is explicitly set to a string that parses to a falsy value. var PRIORITIZE_CHANGED = true; if (process.env.METEOR_WATCH_PRIORITIZE_CHANGED && ! JSON.parse(process.env.METEOR_WATCH_PRIORITIZE_CHANGED)) { PRIORITIZE_CHANGED = false; } -var DEFAULT_POLLING_INTERVAL = - +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 5000); - -var NO_WATCHER_POLLING_INTERVAL = - +(process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 500); - -// This may seems like a long time to wait before actually closing the -// file watchers, but it's to our advantage if they survive restarts. -const WATCHER_CLEANUP_DELAY_MS = 30000; - -// Since linux doesn't have recursive file watching, nsfw has to walk the -// watched folder and create a separate watcher for each subfolder. Until it has a -// way for us to filter which folders it walks we will continue to use -// pathwatcher to avoid having too many watchers. -let watcherLibrary = process.env.METEOR_WATCHER_LIBRARY || - (process.platform === 'linux' ? 'pathwatcher' : 'nsfw'); - -// Pathwatcher complains (using console.error, ugh) if you try to watch -// two files with the same stat.ino number but different paths on linux, so we have -// to deduplicate files by ino. -const DEDUPLICATE_BY_INO = watcherLibrary === 'pathwatcher'; -// Set METEOR_WATCH_FORCE_POLLING environment variable to a truthy value to -// force the use of files.watchFile instead of watchLibrary.watch. -let watcherEnabled = ! JSON.parse( - process.env.METEOR_WATCH_FORCE_POLLING || "false" -); - -const entriesByIno = new Map; - -export type SafeWatcher = { - close: () => void; -} - -type EntryCallback = (event: string) => void; - -interface Entry extends SafeWatcher { - callbacks: Set; - rewatch: () => void; - release: (callback: EntryCallback) => void; - _fire: (event: string) => void; -} - -const entries: Record = Object.create(null); - -// Folders that are watched recursively -let watchRoots = new Set(); - // Set of paths for which a change event has been fired, watched with -// watchLibrary.watch if available. This could be an LRU cache, but in -// practice it should never grow large enough for that to matter. +// watchLibrary.watch if available. const changedPaths = new Set; +function shouldIgnorePath(absPath: string): boolean { + const posixPath = toPosixPath(absPath); + const parts = posixPath.split('/'); + + const cwd = toPosixPath(process.cwd()); + const isWithinCwd = absPath.startsWith(cwd); + + if (isWithinCwd && absPath.includes(`${cwd}/.meteor/local`)) { + return true; + } + + // Check for .meteor: allow the .meteor directory itself, + // but ignore its "local" subdirectory (or any immediate child folder that indicates cache). + const meteorIndex = parts.indexOf(".meteor"); + if (meteorIndex !== -1) { + const nextPart = parts[meteorIndex + 1]; + if (nextPart && nextPart === "local") { + // Ignore anything inside .meteor/local + return true; + } + // Otherwise, do not automatically ignore .meteor (which includes .meteor/packages, etc). + } + + // For project node_modules: check if it's a direct node_modules/ + if (isWithinCwd) { + // Check if it's the project node_modules + if (absPath.includes(`${cwd}/node_modules`)) { + // Check if it's a direct node_modules/ path + const relPath = absPath.substring(cwd.length + 1); // +1 for the slash + const relParts = relPath.split('/'); + if (relParts.length >= 2 && relParts[0] === 'node_modules') { + // If it's a direct node_modules/, check if it's a symlink + // We'll return false here (don't ignore) so that the code can later decide to use polling + // based on isSymbolicLink check in the watch function + if (relParts.length === 2 && isSymbolicLink(absPath)) { + return false; + } + // Check if it's within a symlink root to not ignore + if (isWithinSymlinkRoot(absPath)) { + return false; + } + } + return true; + } else { + // Otherwise, don't ignore non-npm node_modules + return false; + } + } + + // For external node_modules: check if it's a direct node_modules/ + const nmIndex = parts.indexOf("node_modules"); + if (nmIndex !== -1) { + // Don't ignore node_modules within .npm/package/ paths + const npmPackageIndex = parts.indexOf(".npm"); + if (npmPackageIndex !== -1 && parts[npmPackageIndex + 1] === "package" && + nmIndex > npmPackageIndex && parts[nmIndex - 1] === "package") { + return false; + } + return true; + } + + return false; +} + +/** + * Check if a path is a symbolic link. + * + * Symbolic links are not supported natively in some operating systems, + * so we need to use polling for them to ensure they are properly watched. + * This function is used to determine if a path is a symbolic link, + * so we can use polling instead of native watching for it. + * + * If a path is a symbolic link, its root is added to the symlinkRoots set. + */ +function isSymbolicLink(absPath: string, addToRoots = true): boolean { + try { + const osPath = convertToOSPath(absPath); + const stat = lstat(osPath); + if (stat?.isSymbolicLink()) { + if (addToRoots) { + // Add the directory containing the symlink to the symlinkRoots set + const symlinkRoot = toPosixPath(absPath); + symlinkRoots.add(symlinkRoot); + // Rewatch using polling any existing watchers under this symlink root + rewatchPolling(symlinkRoot); + } + return true; + } + return false; + } catch (e) { + // If we can't stat the file, assume it's not a symlink + return false; + } +} + +/** + * Check if a path is within any symlink root. + * + * This is used to determine if a path should use polling instead of native watching, + * even if it's not a symlink itself. + */ +function isWithinSymlinkRoot(absPath: string): boolean { + for (const root of symlinkRoots) { + // Check if absPath starts with root + '/' + if (absPath === root || (absPath.startsWith(root) && absPath.charAt(root.length) === '/')) { + return true; + } + } + return false; +} + +/** + * Ensure that the given directory is being watched by @parcel/watcher. + * If it is not a directory or is unwatchable, it is immediately added to an ignore set. + */ +async function ensureWatchRoot(dirPath: string): Promise { + if (!watcherEnabled || watchRoots.has(dirPath) || ignoredWatchRoots.has(dirPath)) { + return; + } + + // If an ancestor is already watched, skip this one. + for (const root of watchRoots) { + const rel = pathRelative(root, dirPath); + if (root !== dirPath && !rel.startsWith("..") && !rel.startsWith("/")) { + return; + } + } + + // Remove any existing roots that are now encompassed by the new one. + for (const root of Array.from(watchRoots)) { + const rel = pathRelative(dirPath, root); + if (root !== dirPath && !rel.startsWith("..") && !rel.startsWith("/")) { + const sub = dirSubscriptions.get(root); + if (sub) { + try { + await sub.unsubscribe(); + } catch (_) { + /* ignore errors */ + } + } + dirSubscriptions.delete(root); + watchRoots.delete(root); + } + } + + const osDirPath = convertToOSPath(dirPath); + // Check that osDirPath is indeed a directory. + try { + const stats = statOrNull(osDirPath); + if (!stats?.isDirectory()) { + console.warn(`Skipping watcher for ${osDirPath}: not a directory`); + ignoredWatchRoots.add(dirPath); + return; + } + } catch (e) { + console.error(`Failed to stat ${osDirPath}:`, e); + ignoredWatchRoots.add(dirPath); + return; + } + + // Set up ignore patterns to skip node_modules and .meteor/local cache + const cwd = toPosixPath(process.cwd()); + const isWithinCwd = dirPath.startsWith(cwd); + const ignPrefix = isWithinCwd ? "" : "**/"; + const ignorePatterns = [`${ignPrefix}node_modules/**`, `${ignPrefix}.meteor/local/**`]; + try { + watchRoots.add(dirPath); + const subscription = await ParcelWatcher.subscribe( + osDirPath, + (err, events) => { + if (err) { + if (/Events were dropped/.test(err.message)) { + return; + } + console.error(`Parcel watcher error on ${osDirPath}:`, err); + // Only disable native watching for critical errors (like ENOSPC). + // @ts-ignore + if (err.code === "ENOSPC" || err.errno === require("constants").ENOSPC) { + fallbackToPolling(); + } + watchRoots.delete(dirPath); + return; + } + // Dispatch each event to any registered entries. + for (const event of events) { + const changedPath = toPosixPath(event.path); + const entry = findNearestEntry(changedPath); + if (!entry) continue; + // In Meteor's safe-watcher API, both create/update trigger "change" events. + const evtType = event.type === "delete" ? "delete" : "change"; + entry._fire(evtType); + } + }, + { ignore: ignorePatterns } + ); + dirSubscriptions.set(dirPath, subscription); + } catch (e: any) { + if ( + e && + (e.code === "ENOTDIR" || + /Not a directory/.test(e.message) || + e.code === "EBADF" || + /Bad file descriptor/.test(e.message)) + ) { + console.warn(`Skipping watcher for ${osDirPath}: not a directory`); + ignoredWatchRoots.add(dirPath); + } else { + console.error(`Failed to start watcher for ${osDirPath}:`, e); + if (e.code === "ENOSPC" || e.errno === require("constants").ENOSPC) { + fallbackToPolling(); + } + } + watchRoots.delete(dirPath); + } +} + +/** + * Creates a new watch entry for a specific file (or directory) and + * holds its registered callbacks. + */ +function startNewEntry(absPath: string): Entry { + const callbacks = new Set(); + let closed = false; + const entry: Entry = { + callbacks, + close() { + if (closed) return; + closed = true; + deleteEntry(absPath); + }, + _fire(event: string) { + callbacks.forEach(cb => { + try { + cb(event); + } catch (e) { + // Ignore callback errors. + } + }); + } + }; + return entry; +} + +/** + * The primary API function to watch a file or directory. + * This registers the callback on the internally managed entry and + * ensures that a Parcel watcher is subscribed to a covering directory. + */ +export function watch (absPath: string, callback: ChangeCallback): SafeWatcher { + // @ts-ignore + if (!getMeteorConfig()?.modern?.watcher) { + // @ts-ignore + return watchLegacy(absPath, callback); + } + // @ts-ignore + return watchModern(absPath, callback); +}; + +const watchModern = + Profile( + "safeWatcher.watchModern", + ( + absPath: string, + callback: ChangeCallback + ): SafeWatcher => { + absPath = toPosixPath(absPath); + + // If the path should be ignored, immediately return a noop SafeWatcher. + if (shouldIgnorePath(absPath)) { + return { close() {} }; + } + // If native watching is disabled, the path is a symbolic link, or the path is within a symlink root, + // use the polling strategy. Symbolic links are not supported natively in some operating systems, + // and paths within symlink roots should also use polling for consistency. + if (!watcherEnabled || isWithinSymlinkRoot(absPath) || isSymbolicLink(absPath)) { + return startPolling(absPath, callback); + } + // Try to reuse an existing entry if one was created before. + let entry = getEntry(absPath); + if (!entry) { + entry = startNewEntry(absPath); + setEntry(absPath, entry); + // Determine the directory that should be watched. + let watchTarget: string; + try { + const st = statOrNull(convertToOSPath(absPath)); + watchTarget = st?.isDirectory() ? absPath : toPosixPath(pathDirname(convertToOSPath(absPath))); + } catch (e) { + watchTarget = toPosixPath(pathDirname(convertToOSPath(absPath))); + } + // Set up a watcher on the parent directory (or the directory itself) if not already active. + ensureWatchRoot(watchTarget); + } + // Register the callback for this file. + entry.callbacks.add(callback); + return { + close() { + const entry = getEntry(absPath); + if (entry) { + entry.callbacks.delete(callback); + if (entry.callbacks.size === 0) { + entry.close(); + } + } + } + }; +}); + +/** + * Externally force a directory to be watched. + * If the provided path is a file, its parent directory is used. + */ +export function addWatchRoot(absPath: string) { + // @ts-ignore + if (!getMeteorConfig()?.modern?.watcher) { + // @ts-ignore + return addWatchRootLegacy(absPath); + } + + absPath = toPosixPath(absPath); + let watchTarget = absPath; + try { + const st = statOrNull(convertToOSPath(absPath)); + if (!st?.isDirectory()) { + watchTarget = toPosixPath(pathDirname(convertToOSPath(absPath))); + } + } catch (e) { + watchTarget = toPosixPath(pathDirname(convertToOSPath(absPath))); + } + ensureWatchRoot(watchTarget); +} + +async function safeUnsubscribeSub(root: string) { + const sub = dirSubscriptions.get(root); + if (!sub) return; // Already unsubscribed. + // Remove from our maps immediately to prevent further unsubscribe calls. + dirSubscriptions.delete(root); + watchRoots.delete(root); + try { + await sub.unsubscribe(); + } catch (e) { + console.error(`Error during unsubscribe for ${root}:`, e); + } +} + +export async function closeAllWatchers() { + // @ts-ignore + if (!getMeteorConfig()?.modern?.watcher) { + // @ts-ignore + return closeAllWatchersLegacy(); + } + for (const root of Array.from(watchRoots)) { + await safeUnsubscribeSub(root); + } +} + function hasPriority(absPath: string) { // If we're not prioritizing changed files, then all files have // priority, which means they should be watched with native file // watchers if the platform supports them. If we are prioritizing // changed files, then only changed files get priority. return PRIORITIZE_CHANGED - ? changedPaths.has(absPath) - : true; + ? changedPaths.has(absPath) + : true; } -function acquireWatcher(absPath: string, callback: EntryCallback) { - const entry = entries[absPath] || ( - entries[absPath] = startNewWatcher(absPath)); - - // Watches successfully established in the past may have become invalid - // because the watched file was deleted or renamed, so we need to make - // sure we're still watching every time we call safeWatcher.watch. - entry.rewatch(); - - // The size of the entry.callbacks Set also serves as a reference count - // for this watcher. - entry.callbacks.add(callback); - - return entry; -} - -function startNewWatcher(absPath: string): Entry { - let stat: Stats | BigIntStats | null | undefined = null; - - if (DEDUPLICATE_BY_INO) { - stat = statOrNull(absPath); - if (stat && stat.ino > 0 && entriesByIno.has(stat.ino)) { - const entry = entriesByIno.get(stat.ino); - if (entries[absPath] === entry) { - return entry; - } - } - } else { - let entry = entries[absPath]; - if (entry) { - return entry; - } - } - - function safeUnwatch() { - if (watcher) { - watcher.close(); - watcher = null; - if (stat && stat.ino > 0) { - entriesByIno.delete(stat.ino); - } - } - } - - let lastWatcherEventTime = Date.now(); - const callbacks = new Set(); - let watcherCleanupTimer: ReturnType | null = null; - let watcher: FSWatcher | null = null; - - // Determines the polling interval to be used for the fs.watchFile-based - // safety net that works on all platforms and file systems. - function getPollingInterval() { - if (hasPriority(absPath)) { - // Regardless of whether we have a native file watcher and it works - // correctly on this file system, poll prioritized files (that is, - // files that have been changed at least once) at a higher frequency - // (every 500ms by default). - return NO_WATCHER_POLLING_INTERVAL; - } - - if (watcherEnabled || PRIORITIZE_CHANGED) { - // As long as native file watching is enabled (even if it doesn't - // work correctly) and the developer hasn't explicitly opted out of - // the file watching priority system, poll unchanged files at a - // lower frequency (every 5000ms by default). - return DEFAULT_POLLING_INTERVAL; - } - - // If native file watching is disabled and the developer has - // explicitly opted out of the priority system, poll everything at the - // higher frequency (every 500ms by default). Note that this leads to - // higher idle CPU usage, so the developer may want to adjust the - // METEOR_WATCH_POLLING_INTERVAL_MS environment variable. +// Determines the polling interval to be used for the fs.watchFile-based +// safety net that works on all platforms and file systems. +function getPollingInterval(absPath: string): number { + if (hasPriority(absPath)) { + // Regardless of whether we have a native file watcher and it works + // correctly on this file system, poll prioritized files (that is, + // files that have been changed at least once) at a higher frequency + // (every 500ms by default). return NO_WATCHER_POLLING_INTERVAL; } - function fire(event: string) { - if (event !== "change") { - // When we receive a "delete" or "rename" event, the watcher is - // probably not going to generate any more notifications for this - // file, so we close and nullify the watcher to ensure that - // entry.rewatch() will attempt to reestablish the watcher the next - // time we call safeWatcher.watch. - safeUnwatch(); - - // Make sure we don't throttle the watchFile callback after a - // "delete" or "rename" event, since it is now our only reliable - // source of file change notifications. - lastWatcherEventTime = 0; - - } else { - changedPaths.add(absPath); - rewatch(); - } - - callbacks.forEach(cb => cb(event)); + if (watcherEnabled || PRIORITIZE_CHANGED) { + // As long as native file watching is enabled (even if it doesn't + // work correctly) and the developer hasn't explicitly opted out of + // the file watching priority system, poll unchanged files at a + // lower frequency (every 5000ms by default). + return DEFAULT_POLLING_INTERVAL; } - function watchWrapper(event: string) { - lastWatcherEventTime = Date.now(); - fire(event); + // If native file watching is disabled and the developer has + // explicitly opted out of the priority system, poll everything at the + // higher frequency (every 500ms by default). Note that this leads to + // higher idle CPU usage, so the developer may want to adjust the + // METEOR_WATCH_POLLING_INTERVAL_MS environment variable. + return NO_WATCHER_POLLING_INTERVAL; +} - // It's tempting to call unwatchFile(absPath, watchFileWrapper) here, - // but previous watcher success is no guarantee of future watcher - // reliability. For example, watchLibrary.watch works just fine when file - // changes originate from within a Vagrant VM, but changes to shared - // files made outside the VM are invisible to watcher, so our only - // hope of catching them is to continue polling. - } +function startPolling(absPath: string, callback: ChangeCallback): SafeWatcher { + const osPath = convertToOSPath(absPath); + // Initial polling interval. + let interval = getPollingInterval(absPath); - function rewatch() { - if (hasPriority(absPath)) { - if (watcher) { - // Already watching; nothing to do. - return; - } - watcher = watchLibraryWatch(absPath, watchWrapper); - } else if (watcher) { - safeUnwatch(); - } + // Check if we already have a polling watcher for this path + let watcherInfo = pollingWatchers.get(absPath); - // Since we're about to restart the stat-based file watcher, we don't - // want to miss any of its events because of the lastWatcherEventTime - // throttling that it attempts to do. - lastWatcherEventTime = 0; - - // We use files.watchFile in addition to watcher.watch as a fail-safe - // to detect file changes even on network file systems. However - // (unless the user disabled watcher or this watcher call failed), we - // use a relatively long default polling interval of 5000ms to save - // CPU cycles. - statWatch(absPath, getPollingInterval(), watchFileWrapper); - } - - function watchFileWrapper(newStat: Stats, oldStat: Stats) { - if (newStat.ino === 0 && - oldStat.ino === 0 && - +newStat.mtime === +oldStat.mtime) { - // Node calls the watchFile listener once with bogus identical stat - // objects, which should not trigger a file change event. - return; - } - - // If a watcher event fired in the last polling interval, ignore - // this event. - if (Date.now() - lastWatcherEventTime > getPollingInterval()) { - fire("change"); - } - } - - const entry = { - callbacks, - rewatch, - - release(callback: EntryCallback) { - if (! entries[absPath]) { - return; - } - - callbacks.delete(callback); - if (callbacks.size > 0) { - return; - } - - // Once there are no more callbacks in the Set, close both watchers - // and nullify the shared data. - if (watcherCleanupTimer) { - clearTimeout(watcherCleanupTimer); - } - - watcherCleanupTimer = setTimeout(() => { - if (callbacks.size > 0) { - // If another callback was added while the timer was pending, we - // can avoid tearing anything down. - return; + if (watcherInfo) { + // Add this callback to the existing watcher + watcherInfo.callbacks.add(callback); + } else { + // Create a new polling watcher + const pollCallback = (curr: Stats, prev: Stats) => { + // Compare modification times to detect a change. + if (+curr.mtime !== +prev.mtime) { + changedPaths.add(absPath); + // Notify all callbacks registered for this path + const info = pollingWatchers.get(absPath); + if (info) { + for (const cb of info.callbacks) { + cb("change"); + } } - entry.close(); - }, WATCHER_CLEANUP_DELAY_MS); - }, - - close() { - if (entries[absPath] !== entry) return; - entries[absPath] = null; - - if (watcherCleanupTimer) { - clearTimeout(watcherCleanupTimer); - watcherCleanupTimer = null; } - - safeUnwatch(); - - unwatchFile(absPath, watchFileWrapper); - }, - _fire: fire - }; - - if (stat && stat.ino > 0) { - entriesByIno.set(stat.ino, entry); - } - - return entry; -} - -export function closeAllWatchers() { - Object.keys(entries).forEach(absPath => { - const entry = entries[absPath]; - if (entry) { - entry.close(); - } - }); -} - -const statWatchers = Object.create(null); - -function statWatch( - absPath: string, - interval: number, - callback: (current: Stats, previous: Stats) => void, -) { - let statWatcher = statWatchers[absPath]; - - if (!statWatcher) { - statWatcher = { - interval, - changeListeners: [], - stat: null }; - statWatchers[absPath] = statWatcher; + + watchFile(osPath, { interval }, pollCallback); + + // Store the new watcher info + watcherInfo = { + callbacks: new Set([callback]), + pollCallback + }; + pollingWatchers.set(absPath, watcherInfo); } - // If the interval needs to be changed, replace the watcher. - // Node will only recreate the watcher with the new interval if all old - // watchers are stopped (which unwatchFile does when not passed a - // specific listener) - if (statWatcher.interval !== interval && statWatcher.stat) { - // This stops all stat watchers for the file, not just those created by - // statWatch - unwatchFile(absPath); - statWatcher.stat = null; - statWatcher.interval = interval; - } + return { + close() { + const info = pollingWatchers.get(absPath); + if (info) { + // Remove this callback + info.callbacks.delete(callback); - if (!statWatcher.changeListeners.includes(callback)) { - statWatcher.changeListeners.push(callback); - } - - if (!statWatcher.stat) { - const newStat = watchFile(absPath, { - persistent: false, // never persistent - interval, - }, (newStat, oldStat) => { - statWatcher.changeListeners.forEach(( - listener: (newStat: Stats, oldStat: Stats) => void - ) => { - listener(newStat, oldStat); - }); - }); - - newStat.on("stop", () => { - if (statWatchers[absPath] === statWatch) { - delete statWatchers[absPath]; - } - }); - - statWatcher.stat = newStat; - } - - return statWatcher; -} - -function watchLibraryWatch(absPath: string, callback: EntryCallback) { - if (watcherEnabled && watcherLibrary === 'pathwatcher') { - try { - return pathwatcher.watch(convertToOSPath(absPath), callback); - } catch (e: any) { - maybeSuggestRaisingWatchLimit(e); - // ... ignore the error. We'll still have watchFile, which is good - // enough. - } - } - - return null; -} - -let suggestedRaisingWatchLimit = false; - -// This function is async so that archinfo.host() (which may call -// utils.execFileSync) will run in a Fiber. -async function maybeSuggestRaisingWatchLimit(error: Error & { errno: number }) { - var constants = require('constants'); - var archinfo = require('../utils/archinfo'); - if (! suggestedRaisingWatchLimit && - // Note: the not-super-documented require('constants') maps from - // strings to SYSTEM errno values. System errno values aren't the same - // as the numbers used internally by libuv! Once we're upgraded - // to Node 0.12, we'll have the system errno as a string (on 'code'), - // but the support for that wasn't in Node 0.10's uv. - // See our PR https://github.com/atom/node-pathwatcher/pull/53 - // (and make sure to read the final commit message, not the original - // proposed PR, which had a slightly different interface). - error.errno === constants.ENOSPC && - // The only suggestion we currently have is for Linux. - archinfo.matches(archinfo.host(), 'os.linux')) { - - // Check suggestedRaisingWatchLimit again because archinfo.host() may - // have yielded. - if (suggestedRaisingWatchLimit) return; - suggestedRaisingWatchLimit = true; - - var Console = require('../console/console.js').Console; - if (! Console.isHeadless()) { - Console.arrowWarn( - "It looks like a simple tweak to your system's configuration will " + - "make many tools (including this Meteor command) more efficient. " + - "To learn more, see " + - Console.url("https://github.com/meteor/docs/blob/master/long-form/file-change-watcher-efficiency.md")); - } - } -} - -export const watch = Profile( - "safeWatcher.watch", - (absPath: string, callback: EntryCallback) => { - const entry = acquireWatcher(absPath, callback); - return { - close() { - entry.release(callback); - } - } as SafeWatcher; - } -); - -const fireNames = { - [nsfw.actions.CREATED]: 'change', - [nsfw.actions.MODIFIED]: 'change', - [nsfw.actions.DELETED]: 'delete' -} - -export function addWatchRoot(absPath: string) { - if (watchRoots.has(absPath) || watcherLibrary !== 'nsfw' || !watcherEnabled) { - return; - } - - watchRoots.add(absPath); - - // If there already is a watcher for a parent directory, there is no need - // to create this watcher. - for (const path of watchRoots) { - let relativePath = pathRelative(path, absPath); - if ( - path !== absPath && - !relativePath.startsWith('..') && - !relativePath.startsWith('/') - ) { - return; - } - } - - // TODO: check if there are any existing watchers that are children of this - // watcher and stop them - - nsfw( - convertToOSPath(absPath), - (events) => { - events.forEach(event => { - if(event.action === nsfw.actions.RENAMED) { - let oldPath = nativeJoin(event.directory, event.oldFile); - let oldEntry = entries[toPosixPath(oldPath)]; - if (oldEntry) { - oldEntry._fire('rename'); - } - - let path = nativeJoin(event.newDirectory, event.newFile); - let newEntry = entries[toPosixPath(path)]; - if (newEntry) { - newEntry._fire('change'); - } - } else { - let path = nativeJoin(event.directory, event.file); - let entry = entries[toPosixPath(path)]; - if (entry) { - entry._fire(fireNames[event.action]); - } + // If no callbacks remain, remove the watcher + if (info.callbacks.size === 0) { + unwatchFile(osPath, info.pollCallback); + pollingWatchers.delete(absPath); + changedPaths.delete(absPath); } - }) + } } - ).then(watcher => { - watcher.start() - }); + }; } + +/** + * Rewatch entries under a symlink root from native watchers to polling watchers. + * This is called when a new symlink root is discovered. + */ +function rewatchPolling(root: string) { + for (const [watchedPath, entry] of entries) { + // if it lives under the new symlink root... + if (watchedPath === root || + (watchedPath.startsWith(root) && watchedPath.charAt(root.length) === '/')) { + // Skip if entry is null or already closed + if (!entry) continue; + + // Store the callbacks before closing the entry + const callbacks = Array.from(entry.callbacks); + + // Tear down the old native watcher + entry.close(); + + // Remove it from the map + entries.delete(watchedPath); + + // Re-watch via polling for each callback + for (const cb of callbacks) { + startPolling(watchedPath, cb); + } + } + } +} + +/** + * Fall back to polling. If a critical error occurs, + * we disable native watching and close all existing native watchers. + */ +function fallbackToPolling() { + if (watcherEnabled) { + console.error("Critical native watcher error encountered. Falling back to polling for all entries."); + watcherEnabled = false; + closeAllWatchers(); + } +} + +// Register exit handlers to ensure proper cleanup of subscriptions +registerExitHandlers(); diff --git a/tools/index.d.ts b/tools/index.d.ts index ba79b433a4..51beff21d5 100644 --- a/tools/index.d.ts +++ b/tools/index.d.ts @@ -5,20 +5,6 @@ declare global { // The ES5 library fails to allow the input parameter to be a Buffer. parse(input: Buffer | string, reviver?: (this: any, key: string, value: any) => any): any; } - - interface Promise { - // This is an incomplete list of methods added to Promise.prototype by the - // meteor-promise npm package. TODO Eventually these declarations should be - // moved into that package. - await(): T; - } - - // Promise.await(x) is a shorthand provided by meteor-promise for - // Promise.resolve(x).await(). - interface PromiseConstructor { - await(arg: T | PromiseLike): T; - } - interface Function { // func-utils.ts makes usage of this feature displayName?: string; diff --git a/tools/index.js b/tools/index.js index 6522c41c3d..82876cae67 100644 --- a/tools/index.js +++ b/tools/index.js @@ -1,23 +1,25 @@ -require("./tool-env/install-promise.js"); +const { getChildProcess } = require("./cli/dev-bundle-bin-commands"); -require("./cli/dev-bundle-bin-commands.js").then(function (child) { - if (! child) { - // Use process.nextTick here to prevent the Promise from swallowing - // errors from the rest of the setup code. - process.nextTick(continueSetup); +getChildProcess({ isFirstTry: true }).then( + (child) => { + if (!child) { + // Use process.nextTick here to prevent the Promise from swallowing + // errors from the rest of the setup code. + process.nextTick(continueSetup); + } + // If we spawned a process to handle a dev_bundle/bin command like + // `meteor npm` or `meteor node`, then don't run any other tool code. + }, + (error) => { + process.nextTick(function () { + throw error; + }); } - // If we spawned a process to handle a dev_bundle/bin command like - // `meteor npm` or `meteor node`, then don't run any other tool code. -}, function (error) { - process.nextTick(function () { - throw error; - }); -}); +); function continueSetup() { // Set up the Babel transpiler - require('./tool-env/install-babel.js'); - + require("./tool-env/install-babel"); // Run the Meteor command line tool - require('./cli/main.js'); + require("./cli/main"); } diff --git a/tools/isobuild/build-plugin.js b/tools/isobuild/build-plugin.js index e67de09c6b..281bf6e78e 100644 --- a/tools/isobuild/build-plugin.js +++ b/tools/isobuild/build-plugin.js @@ -25,23 +25,23 @@ Object.assign(exports.SourceProcessor.prototype, { // this immediately on evaluating Plugin.registerCompiler; we instead wait // until the whole plugin file has been evaluated (so that it can use things // defined later in the file). - instantiatePlugin: function () { + instantiatePlugin: async function () { var self = this; buildmessage.assertInCapture(); if (self.userPlugin) { throw Error("Called instantiatePlugin twice?"); } - buildmessage.enterJob( + await buildmessage.enterJob( `running ${self.methodName} callback in package ` + self.isopack.displayName(), - () => { + async () => { try { - self.userPlugin = buildmessage.markBoundary(self.factoryFunction) - .call(null); + const markedFactoryFunction = buildmessage.markBoundary(self.factoryFunction); + self.userPlugin = await markedFactoryFunction.call(null); // If we have a disk cache directory and the plugin wants it, use it. if (self.isopack.pluginCacheDir && self.userPlugin.setDiskCacheDirectory) { - buildmessage.markBoundary(function () { + await buildmessage.markBoundary(function () { self.userPlugin.setDiskCacheDirectory( files.convertToOSPath(self.isopack.pluginCacheDir) ); diff --git a/tools/isobuild/builder.js b/tools/isobuild/builder.js index a8cc62f0cd..8472f15f16 100644 --- a/tools/isobuild/builder.js +++ b/tools/isobuild/builder.js @@ -1,7 +1,7 @@ import assert from "assert"; import {WatchSet, readAndWatchFile, sha1} from '../fs/watch'; import files, { - symlinkWithOverwrite, realpath, + symlinkWithOverwrite, realpath, rm_recursive_deferred, } from '../fs/files'; import NpmDiscards from './npm-discards'; import {Profile} from '../tool-env/profile'; @@ -117,18 +117,22 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` } } - // Build the output from scratch - if (resetBuildPath) { - files.rm_recursive(this.buildPath); - files.mkdir_p(this.buildPath, 0o755); - } - - this.watchSet = new WatchSet(); + this.resetBuildPath = resetBuildPath; // XXX cleaner error handling. don't make the humans read an // exception (and, make suitable for use in automated systems) } + async init() { + // Build the output from scratch + if (this.resetBuildPath) { + await files.rm_recursive_deferred(this.buildPath); + // Create the new build directory immediately without waiting for deletion + await files.mkdir_p(this.buildPath, 0o755); + } + this.watchSet = new WatchSet(); + } + // Like mkdir_p, but records in self.usedAsFile that we have created // the directories, and takes a path relative to the bundle // root. Throws an exception on failure. @@ -286,7 +290,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // Returns the final canonicalize relPath that was written to. // // If `file` is used then it will be added to the builder's WatchSet. - write(relPath, {data, file, hash, sanitize, executable, symlink}) { + async write(relPath, {data, file, hash, sanitize, executable, symlink}) { relPath = this._normalizeFilePath(relPath, sanitize); let getData = null; @@ -309,7 +313,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` const absPath = files.pathJoin(this.buildPath, relPath); if (symlink) { - symlinkWithOverwrite(symlink, absPath); + await symlinkWithOverwrite(symlink, absPath); } else { hash = hash || sha1(getData()); @@ -323,7 +327,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` if (this.buildPath === this.outputPath || this.writtenHashes[relPath]) { // atomicallyRewriteFile handles overwriting files that have already been created - atomicallyRewriteFile(absPath, getData(), { + await atomicallyRewriteFile(absPath, getData(), { mode }); } else { @@ -332,7 +336,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // it is not important to write atomically. files.writeFile(absPath, getData(), { mode - }) + }); } } @@ -343,7 +347,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` return relPath; } - copyTranspiledModules(relativePaths, { + async copyTranspiledModules(relativePaths, { sourceRootDir, targetRootDir = this.outputPath, needToTranspile = files.inCheckout(), @@ -352,21 +356,22 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // If these files have already been transpiled, copy the transpiled files // (both .js and .js.map) directly to the builder output directory, without // recompiling them. - relativePaths.forEach(relPath => { + for (const relPath of relativePaths) { const jsPath = jsToTs(relPath); - [jsPath, jsPath + ".map"].forEach(path => { - this.write(path, { + for (const path of [jsPath, jsPath + ".map"]) { + await this.write(path, { file: files.pathJoin(sourceRootDir, path), }); - }); - }); + } + } return; } const babel = require("@meteorjs/babel"); const commonBabelOptions = babel.getDefaultOptions({ nodeMajorVersion: parseInt(process.versions.node), - typescript: true + typescript: true, + useNativeAsyncAwait: true }); commonBabelOptions.sourceMaps = true; @@ -419,7 +424,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // Serialize `data` as JSON and write it to `relPath` (a path to a // file relative to the bundle root), creating parent directories as // necessary. Throw an exception if the file already exists. - writeJson(relPath, data) { + async writeJson(relPath, data) { // Ensure no trailing slash if (relPath.slice(-1) === files.pathSep) { relPath = relPath.slice(0, -1); @@ -428,7 +433,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` this._ensureDirectory(files.pathDirname(relPath)); const absPath = files.pathJoin(this.buildPath, relPath); - atomicallyRewriteFile( + await atomicallyRewriteFile( absPath, Buffer.from(JSON.stringify(data, null, 2), 'utf8'), {mode: 0o444}); @@ -518,9 +523,9 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // is patched through directly rather than rewriting its inputs and // outputs. This is only valid because it does nothing with its inputs // and outputs other than send pass them to other methods.) - writeToGeneratedFilename(relPath, writeOptions) { - const generated = this.generateFilename(relPath); - this.write(generated, writeOptions); + async writeToGeneratedFilename(relPath, writeOptions) { + const generated = await this.generateFilename(relPath); + await this.write(generated, writeOptions); return generated; } @@ -601,7 +606,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` return this._copyDirectory(options); } - _copyDirectory({ + async _copyDirectory({ from, to, ignore, specificFiles, @@ -639,12 +644,12 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` const rootDir = realpath(from); - const walk = (absFrom, relTo) => { + const walk = async (absFrom, relTo) => { if (symlink && ! (relTo in this.usedAsFile)) { this._ensureDirectory(files.pathDirname(relTo)); const absTo = files.pathResolve(this.buildPath, relTo); if (this.previousCreatedSymlinks[absFrom] !== relTo) { - symlinkWithOverwrite(absFrom, absTo); + await symlinkWithOverwrite(absFrom, absTo); } this.usedAsFile[relTo] = false; this.createdSymlinks[absFrom] = relTo; @@ -653,12 +658,12 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` this._ensureDirectory(relTo); - optimisticReaddir(absFrom).forEach(item => { + for (const item of optimisticReaddir(absFrom)) { let thisAbsFrom = files.pathResolve(absFrom, item); const thisRelTo = files.pathJoin(relTo, item); if (specificPaths && !(thisRelTo in specificPaths)) { - return; + continue; } // Returns files.realpath(thisAbsFrom), if it is external to @@ -681,7 +686,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` } const isExternal = - files.pathRelative(rootDir, real).startsWith(".."); + files.pathRelative(rootDir, real).startsWith(".."); // Now cachedExternalPath is either a string or false. return cachedExternalPath = isExternal && real; @@ -706,7 +711,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` if (! fileStatus) { // If the file did not exist, skip it. - return; + continue; } let itemForMatch = item; @@ -717,22 +722,22 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // skip excluded files if (ignore.some(pattern => itemForMatch.match(pattern))) { - return; + continue; } if (typeof filter === "function" && ! filter(thisAbsFrom, isDirectory)) { - return; + continue; } if (npmDiscards instanceof NpmDiscards && npmDiscards.shouldDiscard(thisAbsFrom, isDirectory)) { - return; + continue; } if (isDirectory) { - walk(thisAbsFrom, thisRelTo); - return; + await walk(thisAbsFrom, thisRelTo); + continue; } if (fileStatus.isSymbolicLink()) { @@ -740,16 +745,16 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // portable than absolute links, so getExternalPath() is // preferred if it returns a path. const linkSource = getExternalPath() || - files.readlink(thisAbsFrom); + files.readlink(thisAbsFrom); const linkTarget = - files.pathResolve(this.buildPath, thisRelTo); + files.pathResolve(this.buildPath, thisRelTo); - if (symlinkIfPossible(linkSource, linkTarget)) { + if (await symlinkIfPossible(linkSource, linkTarget)) { // A symlink counts as a file, as far as "can you put // something under it" goes. this.usedAsFile[thisRelTo] = true; - return; + continue; } } @@ -764,28 +769,28 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` const content = optimisticReadFile(thisAbsFrom); files.writeFile( - files.pathResolve(this.buildPath, thisRelTo), - // The reason we call files.writeFile here instead of - // files.copyFile is so that we can read the file using - // optimisticReadFile instead of files.createReadStream. - content, - // Logic borrowed from files.copyFile: "Create the file as - // readable and writable by everyone, and executable by everyone - // if the original file is executably by owner. (This mode will be - // modified by umask.) We don't copy the mode *directly* because - // this function is used by 'meteor create' which is copying from - // the read-only tools tree into a writable app." - { mode: (fileStatus.mode & 0o100) ? 0o777 : 0o666 }, + files.pathResolve(this.buildPath, thisRelTo), + // The reason we call files.writeFile here instead of + // files.copyFile is so that we can read the file using + // optimisticReadFile instead of files.createReadStream. + content, + // Logic borrowed from files.copyFile: "Create the file as + // readable and writable by everyone, and executable by everyone + // if the original file is executably by owner. (This mode will be + // modified by umask.) We don't copy the mode *directly* because + // this function is used by 'meteor create' which is copying from + // the read-only tools tree into a writable app." + { mode: (fileStatus.mode & 0o100) ? 0o777 : 0o666 }, ); } this.writtenHashes[thisRelTo] = hash; this.usedAsFile[thisRelTo] = true; } - }); + } }; - walk(rootDir, to); + await walk(rootDir, to); } // Returns a new Builder-compatible object that works just like a @@ -798,7 +803,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // // TODO(benjamn) This nonsense should be ripped out by any means // necessary... whenever someone has the time. - enter(relPath) { + async enter(relPath) { const subBuilder = {}; const relPathWithSep = relPath + files.pathSep; const methods = [ @@ -811,8 +816,8 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` "enter", ]; - methods.forEach(method => { - subBuilder[method] = (...args) => { + for (const method of methods) { + subBuilder[method] = async (...args) => { if (method === "copyDirectory" || method === "copyNodeModulesDirectory") { // The copy methods take their relative paths via options.to. @@ -822,7 +827,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` args[0] = files.pathJoin(relPath, args[0]); } - let ret = this[method](...args); + let ret = await this[method](...args); if (method === "generateFilename") { // fix up the returned path to be relative to the @@ -832,14 +837,14 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` } if (ret.substr(0, relPathWithSep.length) !== relPathWithSep) { throw new Error("generateFilename returned path outside of " + - "sub-bundle?"); + "sub-bundle?"); } ret = ret.substr(relPathWithSep.length); } return ret; }; - }); + } // Methods that don't have to fix up arguments or return values, because // they are implemented purely in terms of other methods which do. @@ -855,13 +860,13 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` } // Move the completed bundle into its final location (outputPath) - complete() { + async complete() { if (this.previousUsedAsFile) { // delete files and folders left-over from previous runs and not // re-used in this run const removed = {}; const paths = Object.keys(this.previousUsedAsFile); - paths.forEach((path) => { + for (const path of paths) { // if the same path was re-used, leave it if (this.usedAsFile.hasOwnProperty(path)) { return; } @@ -877,7 +882,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` removed[path] = true; } else { // directory - files.rm_recursive(absPath); + await files.rm_recursive_deferred(absPath); // mark all sub-paths as removed, too paths.forEach((anotherPath) => { @@ -886,7 +891,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` } }); } - }); + } } // XXX Alternatively, we could just keep buildPath around, and make @@ -894,13 +899,13 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` // case of renameDirAlmostAtomically since that one is constructing files to // be checked in to version control, but here we could get away with it. if (this.buildPath !== this.outputPath) { - files.renameDirAlmostAtomically(this.buildPath, this.outputPath); + await files.renameDirAlmostAtomically(this.buildPath, this.outputPath); } } // Delete the partially-completed bundle. Do not disturb outputPath. abort() { - files.rm_recursive(this.buildPath); + return files.rm_recursive_deferred(this.buildPath); } // Returns a WatchSet representing all files that were read from disk by the @@ -920,7 +925,7 @@ function jsToTs(path) { return path; } -function atomicallyRewriteFile(path, data, options) { +async function atomicallyRewriteFile(path, data, options) { // create a different file with a random name and then rename over atomically const rname = '.builder-tmp-file.' + Math.floor(Math.random() * 999999); const rpath = files.pathJoin(files.pathDirname(path), rname); @@ -932,7 +937,7 @@ function atomicallyRewriteFile(path, data, options) { // replacing a directory with a file; this is rare (so it can // be a slow path) but can legitimately happen if e.g. a developer // puts a file where there used to be a directory in their app. - files.rm_recursive(path); + await files.rm_recursive_deferred(path); files.rename(rpath, path); } else { throw e; @@ -940,9 +945,9 @@ function atomicallyRewriteFile(path, data, options) { } } -function symlinkIfPossible(source, target) { +async function symlinkIfPossible(source, target) { try { - symlinkWithOverwrite(source, target); + await symlinkWithOverwrite(source, target); return true; } catch (e) { return false; diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index 6fbec630b3..5d42c1b61e 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -149,7 +149,6 @@ // wait until later. var assert = require('assert'); -var Fiber = require('fibers'); var _ = require('underscore'); var compiler = require('./compiler.js'); @@ -170,7 +169,7 @@ var release = require('../packaging/release.js'); import { loadIsopackage } from '../tool-env/isopackets.js'; import { CORDOVA_PLATFORM_VERSIONS } from '../cordova'; import { gzipSync } from "zlib"; -import { PackageRegistry } from "../../packages/meteor/define-package.js"; +import { PackageRegistry } from "../../packages/core-runtime/package-registry.js"; import { optimisticLStatOrNull } from '../fs/optimistic'; const SOURCE_URL_PREFIX = "meteor://\u{1f4bb}app"; @@ -351,7 +350,7 @@ class NodeModulesDirectory { // objects returned by the toJSON method above. Note that this works // even if the node_modules parameter is a string, though that will only // be the case for bundles built before Meteor 1.3. - static readDirsFromJSON(node_modules, { + static async readDirsFromJSON(node_modules, { rebuildBinaries = false, // Options consumed by readDirsFromJSON are listed above. Any other // options will be passed on to NodeModulesDirectory constructor via @@ -422,9 +421,9 @@ class NodeModulesDirectory { } if (rebuildBinaries) { - _.each(nodeModulesDirectories, (info, path) => { - meteorNpm.rebuildIfNonPortable(path); - }); + for (const path of Object.keys(nodeModulesDirectories)) { + await meteorNpm.rebuildIfNonPortable(path); + } } return nodeModulesDirectories; @@ -844,27 +843,27 @@ class Target { // - addCacheBusters: if true, make all files cacheable by adding // unique query strings to their URLs. unlikely to be of much use // on server targets. - make({packages, minifyMode, addCacheBusters, minifiers, onJsOutputFiles = () => {}}) { + async make({packages, minifyMode, addCacheBusters, minifiers, onJsOutputFiles = () => {}}) { buildmessage.assertInCapture(); - buildmessage.enterJob("building for " + this.arch, () => { + await buildmessage.enterJob("building for " + this.arch, async () => { // Populate the list of unibuilds to load - this._determineLoadOrder({ + await this._determineLoadOrder({ packages: packages || [] }); - const sourceBatches = this._runCompilerPlugins({ + const sourceBatches = await this._runCompilerPlugins({ minifiers, minifyMode, }); // Link JavaScript and set up this.js, etc. - this._emitResources(sourceBatches, (outputFiles, sourceBatch, cacheKey) => { + await this._emitResources(sourceBatches, (outputFiles, sourceBatch, cacheKey) => { function getFileOutput(file) { return new LinkerFile(file).getPrelinkedOutput({}); }; - onJsOutputFiles( + return onJsOutputFiles( { arch: this.arch, name: sourceBatch.unibuild.pkg.name || null, @@ -878,7 +877,7 @@ class Target { // Add top-level Cordova dependencies, which override Cordova // dependencies from packages. - this._addDirectCordovaDependencies(); + await this._addDirectCordovaDependencies(); // Minify, with mode requested. // Why do we only minify in client targets? @@ -903,10 +902,10 @@ class Target { }); if (minifiersByExt.js) { - this.minifyJs(minifiersByExt.js, minifyMode); + await this.minifyJs(minifiersByExt.js, minifyMode); } if (minifiersByExt.css) { - this.minifyCss(minifiersByExt.css, minifyMode); + await this.minifyCss(minifiersByExt.css, minifyMode); } } @@ -928,15 +927,15 @@ class Target { // - packages: an array of packages (or, properly speaking, unibuilds) // to include. Each element should either be a Isopack object or a // package name as a string - _determineLoadOrder({packages}) { + async _determineLoadOrder({packages}) { buildmessage.assertInCapture(); const isopackCache = this.isopackCache; - buildmessage.enterJob('linking the program', () => { + await buildmessage.enterJob('linking the program', async () => { // Find the roots const rootUnibuilds = []; - packages.forEach((p) => { + for (let p of packages) { if (typeof p === 'string') { p = isopackCache.getIsopack(p); } @@ -944,17 +943,17 @@ class Target { // `debugOnly` packages work with "debug" and "test" build // modes. if (p.debugOnly && this.buildMode === 'production') { - return; + continue; } if (p.prodOnly && this.buildMode !== 'production') { - return; + continue; } if (p.testOnly && this.buildMode !== 'test') { - return; + continue; } const unibuild = p.getUnibuildAtArch(this.arch); unibuild && rootUnibuilds.push(unibuild); - }); + } if (buildmessage.jobHasMessages()) { return; @@ -971,7 +970,7 @@ class Target { // Phase 2. const usedUnibuilds = {}; // Map from unibuild.id to Unibuild. this.usedPackages = {}; // Map from package name to true; - const addToGetsUsed = function (unibuild) { + const addToGetsUsed = async function (unibuild) { if (_.has(usedUnibuilds, unibuild.id)) { return; } @@ -980,7 +979,7 @@ class Target { // Only track real packages, not plugin pseudo-packages. this.usedPackages[unibuild.pkg.name] = true; } - compiler.eachUsedUnibuild({ + await compiler.eachUsedUnibuild({ dependencies: unibuild.uses, arch: this.arch, isopackCache: isopackCache, @@ -992,7 +991,9 @@ class Target { }, addToGetsUsed); }.bind(this); - rootUnibuilds.forEach(addToGetsUsed); + for (const unibuild of rootUnibuilds) { + await addToGetsUsed(unibuild); + } if (buildmessage.jobHasMessages()) { return; @@ -1019,7 +1020,7 @@ class Target { // This helper recursively adds unibuild's ordered dependencies to // this.unibuilds, then adds unibuild itself. - const add = function (unibuild) { + const add = async function (unibuild) { // If this has already been added, there's nothing to do. if (!_.has(needed, unibuild.id)) { return; @@ -1035,19 +1036,19 @@ class Target { // eachUsedUnibuild does follow weak edges (ie, they affect the // ordering), but only if they point to a package in usedPackages (ie, a // package that SOMETHING uses strongly). - var processUnibuild = function (usedUnibuild) { + var processUnibuild = async function (usedUnibuild) { if (onStack[usedUnibuild.id]) { buildmessage.error( - "circular dependency between packages " + + "circular dependency between packages " + unibuild.pkg.name + " and " + usedUnibuild.pkg.name); // recover by not enforcing one of the dependencies return; } onStack[usedUnibuild.id] = true; - add(usedUnibuild); + await add(usedUnibuild); delete onStack[usedUnibuild.id]; }; - compiler.eachUsedUnibuild({ + await compiler.eachUsedUnibuild({ dependencies: unibuild.uses, arch: this.arch, isopackCache: isopackCache, @@ -1070,18 +1071,18 @@ class Target { for (first in needed) { break; } - if (! first) { + if (!first) { break; } // Now add it, after its ordered dependencies. - add(needed[first]); + await add(needed[first]); } }); } // Run all the compiler plugins on all source files in the project. Returns an // array of PackageSourceBatches which contain the results of this processing. - _runCompilerPlugins({ + async _runCompilerPlugins({ minifiers = [], minifyMode = "development", }) { @@ -1117,7 +1118,7 @@ class Target { // Takes a CssOutputResource and returns a string of minified CSS, // or null to indicate no minification occurred. - minifyCssResource: (resource) => { + minifyCssResource: async (resource) => { if (! minifiersByExt.css) { // Indicates the caller should use the original resource.data // without minification. @@ -1125,27 +1126,29 @@ class Target { } let sourcePath; - if (resource.data && resource.sourceRoot && resource.sourcePath) { + if ((await resource.data) && resource.sourceRoot && resource.sourcePath) { sourcePath = files.pathJoin(resource.sourceRoot, resource.sourcePath); } const file = new File({ info: 'resource ' + resource.servePath, arch: target.arch, - data: resource.data, - hash: resource.hash, + data: await resource.data, + hash: await resource.hash, sourcePath }); file.setTargetPathFromRelPath( stripLeadingSlash(resource.servePath)); - return minifyCssFiles([file], { + const results = await minifyCssFiles([file], { arch: target.arch, minifier: minifiersByExt.css, minifyMode, watchSet: this.watchSet - }).map(file => file.contents("utf8")).join("\n"); + }); + + return results.map(file => file.contents("utf8")).join("\n"); } }); @@ -1154,13 +1157,13 @@ class Target { // Process all of the sorted unibuilds (which includes running the JavaScript // linker). - _emitResources(sourceBatches, onJsOutputFiles = () => {}) { + async _emitResources(sourceBatches, onJsOutputFiles = () => {}) { buildmessage.assertInJob(); const isWeb = archinfo.matches(this.arch, 'web'); const isOs = archinfo.matches(this.arch, 'os'); - const jsOutputFilesMap = compilerPluginModule.PackageSourceBatch + const jsOutputFilesMap = await compilerPluginModule.PackageSourceBatch .computeJsOutputFilesMap(sourceBatches); sourceBatches.forEach(batch => { @@ -1190,44 +1193,46 @@ class Target { const dynamicImportFiles = new Set; // Copy their resources into the bundle in order - sourceBatches.forEach((sourceBatch) => { + for (const sourceBatch of sourceBatches) { const unibuild = sourceBatch.unibuild; if (this.cordovaDependencies) { _.each(unibuild.pkg.cordovaDependencies, (version, name) => { this._addCordovaDependency( - name, - version, - // use newer version if another version has already been added - false + name, + version, + // use newer version if another version has already been added + false ); }); } const name = unibuild.pkg.name || null; - const isApp = ! name; // Emit the resources - const resources = sourceBatch.getResources( - jsOutputFilesMap.get(name).files, - (linkCacheKey, jsResources) => onJsOutputFiles(jsResources, sourceBatch, linkCacheKey) + const resources = await sourceBatch.getResources( + jsOutputFilesMap.get(name).files, + (linkCacheKey, jsResources) => onJsOutputFiles(jsResources, sourceBatch, linkCacheKey) ); // First, find all the assets, so that we can associate them with each js // resource (for os unibuilds). const unibuildAssets = {}; - resources.forEach((resource) => { + for (const resource of resources) { if (resource.type !== 'asset') { - return; + continue; } + var data = await resource.data; + var hash = await resource.hash; + const fileOptions = { info: 'unbuild ' + resource, arch: this.arch, - data: resource.data, + data, cacheable: false, - hash: resource.hash, - skipSri: !!resource.hash + hash, + skipSri: !!hash }; const file = new File(fileOptions); @@ -1243,8 +1248,8 @@ class Target { assetFiles.forEach(f => { const relPath = isOs - ? files.pathJoin('assets', resource.servePath) - : stripLeadingSlash(resource.servePath); + ? files.pathJoin('assets', resource.servePath) + : stripLeadingSlash(resource.servePath); f.setTargetPathFromRelPath(relPath); @@ -1256,20 +1261,25 @@ class Target { this.asset.push(f); }); - }); + } // Now look for the other kinds of resources. - resources.forEach((resource) => { + for (const resource of resources) { if (resource.type === 'asset') { // already handled - return; + continue; } if (resource.type !== "js" && resource.lazy) { // Only files that compile to JS can be imported, so any other // files should be ignored here, if lazy. - return; + continue; + } + + if (await resource.hasPendingErrors?.()) { + await resource.reportPendingErrors(); + break; } if (['js', 'css'].includes(resource.type)) { @@ -1280,18 +1290,20 @@ class Target { // XXX XXX can't we easily do that in the css handler in // meteor.js? - return; + continue; } + var data = await resource.data; + var hash = await resource.hash; let sourcePath; - if (resource.data && resource.sourceRoot && resource.sourcePath) { + if (data && resource.sourceRoot && resource.sourcePath) { sourcePath = files.pathJoin(resource.sourceRoot, resource.sourcePath); } const f = new File({ info: 'resource ' + resource.servePath, arch: this.arch, - data: resource.data, - hash: resource.hash, + data, + hash, cacheable: false, replaceable: resource.type === 'js' && sourceBatch.hmrAvailable, sourcePath @@ -1316,18 +1328,19 @@ class Target { }); } + var sourceMap = await resource.sourceMap; // Both CSS and JS files can have source maps - if (resource.sourceMap) { + if (sourceMap) { // XXX we used to set sourceMapRoot to // files.pathDirname(relPath) but it's unclear why. With the // currently generated source map file names, it works without it // and doesn't work well with it... maybe? we were getting // 'packages/packages/foo/bar.js' - f.setSourceMap(resource.sourceMap, null); + f.setSourceMap(sourceMap, null); } this[resource.type].push(f); - return; + continue; } if (['head', 'body'].includes(resource.type)) { @@ -1335,11 +1348,11 @@ class Target { throw new Error('HTML segments can only go to the client'); } this[resource.type].push(resource.data); - return; + continue; } throw new Error('Unknown type ' + resource.type); - }); + } this.js.forEach(file => { if (file.targetPath === "packages/dynamic-import.js") { @@ -1350,7 +1363,7 @@ class Target { addToTree(file.hash(), file.targetPath, versions); } }); - }); + } dynamicImportFiles.forEach(file => { file.setContents( @@ -1364,15 +1377,15 @@ class Target { // Call any plugin.afterLink callbacks defined by compiler plugins, // and update the watch set's list of potentially unused files // now that all compilation (including lazy compilation) is finished. - sourceBatches.forEach(batch => { - batch.resourceSlots.forEach(slot => { + for (const batch of sourceBatches) { + for (const slot of batch.resourceSlots) { const plugin = - slot.sourceProcessor && - slot.sourceProcessor.userPlugin; + slot.sourceProcessor && + slot.sourceProcessor.userPlugin; if (plugin && typeof plugin.afterLink === "function") { - plugin.afterLink(); + await plugin.afterLink(); } - }); + } // Any source resource that the content or hash was accessed for are marked // as definitely used. @@ -1386,19 +1399,18 @@ class Target { } assert.strictEqual( - typeof resource._dataUsed, - "boolean" + typeof resource._dataUsed, + "boolean" ); let absPath = files.pathJoin(batch.sourceRoot, resource.path); this.watchSet.addFile(absPath, resource.hash); }); - }); - + } } // Minify the JS in this target - minifyJs(minifierDef, minifyMode) { + async minifyJs(minifierDef, minifyMode) { const staticFiles = []; const dynamicFiles = []; const { arch } = this; @@ -1421,14 +1433,14 @@ class Target { minifierDef.userPlugin ); - buildmessage.enterJob('minifying app code', function () { + await buildmessage.enterJob('minifying app code', async function () { try { - Promise.all([ + await Promise.all([ markedMinifier(staticFiles, { minifyMode }), ...dynamicFiles.map( file => markedMinifier([file], { minifyMode }) ), - ]).await(); + ]); } catch (e) { buildmessage.exception(e); } @@ -1436,7 +1448,7 @@ class Target { const js = []; - function handle(source, dynamic) { + async function handle(source, dynamic) { // Allows minifiers to be compatible with HMR without being // updated to support it. // In development most minifiers add the file to itself with no @@ -1446,23 +1458,24 @@ class Target { // and believe HMR will still update the client correctly. const possiblyReplaceable = source._minifiedFiles.length === 1 && source._source.replaceable; - source._minifiedFiles.forEach(file => { - if (typeof file.data === 'string') { - file.data = Buffer.from(file.data, "utf8"); + for (const file of source._minifiedFiles) { + const fileData = await file.data; + if (typeof fileData === 'string') { + file.data = Buffer.from(fileData, "utf8"); } const replaceable = possiblyReplaceable && - file.data.equals(source._source.contents()); + file.data.equals(source._source.contents()); const newFile = new File({ info: 'minified js', arch, - data: file.data, + data: await file.data, hash: inputHashesByJsFile.get(source), replaceable }); - if (file.sourceMap) { - newFile.setSourceMap(file.sourceMap, '/'); + if (await file.sourceMap) { + newFile.setSourceMap(await file.sourceMap, '/'); } if (file.path) { @@ -1500,7 +1513,7 @@ class Target { statsFile.url = newFile.url.replace(/\.js\b/, ".stats.json"); statsFile.targetPath = - newFile.targetPath.replace(/\.js\b/, ".stats.json"); + newFile.targetPath.replace(/\.js\b/, ".stats.json"); statsFile.cacheable = true; statsFile.type = "json"; @@ -1514,11 +1527,16 @@ class Target { js.push(statsFile); } } - }); + } } - staticFiles.forEach(file => handle(file, false)); - dynamicFiles.forEach(file => handle(file, true)); + for (const file of staticFiles) { + await handle(file, false); + } + + for (const file of dynamicFiles) { + await handle(file, true); + } this.js = js; } @@ -1528,6 +1546,9 @@ class Target { // with the original sources. rewriteSourceMaps() { const rewriteSourceMap = function (sm) { + if (!sm.sources) { + return sm; + } sm.sources = sm.sources.map(function (path) { const prefix = SOURCE_URL_PREFIX; if (path.slice(0, prefix.length) === prefix) { @@ -1694,8 +1715,8 @@ class ClientTarget extends Target { } // Minify the CSS in this target - minifyCss(minifierDef, minifyMode) { - this.css = minifyCssFiles(this.css, { + async minifyCss(minifierDef, minifyMode) { + this.css = await minifyCssFiles(this.css, { arch: this.arch, minifier: minifierDef, minifyMode, @@ -1708,23 +1729,23 @@ class ClientTarget extends Target { // Returns an object with the following keys: // - controlFile: the path (relative to 'builder') of the control file for // the target - write(builder, {minifyMode, buildMode}) { + async write(builder, {minifyMode, buildMode}) { builder.reserve("program.json"); // Helper to iterate over all resources that we serve over HTTP. - const eachResource = function (f) { - ["js", "css", "asset"].forEach((type) => { - this[type].forEach((file) => { - f(file, file.type || type); - }); - }); + const eachResource = async function (f) { + for (const type of ["js", "css", "asset"]) { + for (const file of this[type]) { + await f(file, file.type || type); + } + } }.bind(this); // Reserve all file names from the manifest, so that interleaved // generateFilename calls don't overlap with them. const targetPathToHash = new Map; - eachResource((file, type) => { + await eachResource((file, type) => { const hash = targetPathToHash.get(file.targetPath); if (hash) { // When we add assets that have a URL prefix like /__cordova, we @@ -1747,7 +1768,7 @@ class ClientTarget extends Target { // Build up a manifest of all resources served via HTTP. const manifest = []; - eachResource((file, type) => { + await eachResource(async (file, type) => { const manifestItem = { path: file.targetPath, where: "client", @@ -1778,7 +1799,7 @@ class ClientTarget extends Target { mapData = Buffer.from(JSON.stringify(file.sourceMap), 'utf8'); } - manifestItem.sourceMap = builder.writeToGeneratedFilename( + manifestItem.sourceMap = await builder.writeToGeneratedFilename( file.targetPath + '.map', {data: mapData}); // Use a SHA to make this cacheable. @@ -1793,7 +1814,7 @@ class ClientTarget extends Target { manifestItem.sri = file.sri(); if (! file.targetPath.startsWith("dynamic/")) { - writeFile(file, builder, { + await writeFile(file, builder, { leaveSourceMapUrls: type === 'asset' }); manifest.push(manifestItem); @@ -1819,7 +1840,7 @@ class ClientTarget extends Target { // source maps can be very large), but rather include a normal URL // referring to the source map (as a comment), so that it can be // loaded from the web server when needed. - writeFile(file, builder, { + await writeFile(file, builder, { sourceMapUrl: manifestItem.sourceMapUrl, }); @@ -1844,16 +1865,16 @@ class ClientTarget extends Target { } else { // If the dynamic module does not have a source map, just write it // normally. - writeFile(file, builder); + await writeFile(file, builder); } }); - ['head', 'body'].forEach((type) => { + for (const type of ['head', 'body']) { const data = this[type].join('\n'); if (data) { const dataBuffer = Buffer.from(data, 'utf8'); - const dataFile = builder.writeToGeneratedFilename( - type + '.html', { data: dataBuffer }); + const dataFile = await builder.writeToGeneratedFilename( + type + '.html', { data: dataBuffer }); manifest.push({ path: dataFile, where: 'internal', @@ -1861,7 +1882,7 @@ class ClientTarget extends Target { hash: watch.sha1(dataBuffer) }); } - }); + } // Control file const program = { @@ -1871,7 +1892,7 @@ class ClientTarget extends Target { if (this.arch === 'web.cordova') { import { CORDOVA_PLATFORM_VERSIONS } from '../cordova'; - const { WebAppHashing } = loadIsopackage('webapp-hashing'); + const { WebAppHashing } = await loadIsopackage('webapp-hashing'); const cordovaCompatibilityVersions = _.object(_.map(CORDOVA_PLATFORM_VERSIONS, (version, platform) => { @@ -1896,8 +1917,7 @@ class ClientTarget extends Target { if (buildMode === 'development') { program.hmrVersion = Date.now(); } - - builder.writeJson('program.json', program); + await builder.writeJson('program.json', program); return { controlFile: "program.json" @@ -1905,7 +1925,7 @@ class ClientTarget extends Target { } } -function minifyCssFiles (files, { +async function minifyCssFiles (files, { arch, minifier, minifyMode, @@ -1922,9 +1942,9 @@ function minifyCssFiles (files, { minifier.userPlugin, ); - buildmessage.enterJob('minifying app stylesheet', function () { + await buildmessage.enterJob('minifying app stylesheet', async function () { try { - Promise.await(markedMinifier(sources, { minifyMode })); + await markedMinifier(sources, { minifyMode }); } catch (e) { buildmessage.exception(e); } @@ -2029,7 +2049,7 @@ class JsImage { // XXX throw an error if the image includes any "app-style" code // that is built to put symbols in the global namespace rather than // in a compartment of Package - load(bindings) { + async load(bindings) { var self = this; var ret = new PackageRegistry(); @@ -2106,9 +2126,21 @@ class JsImage { // packages, and an 'Assets' symbol to help the package find its // static assets. var failed = false; - _.each(self.jsToLoad, function (item) { + for (const item of self.jsToLoad) { if (failed) { - return; + continue; + } + + let moduleStubs = Object.create(null); + if (item.targetPath === 'packages/meteor.js') { + // Old versions of the Meteor package would require + // fibers but only use it in certain api's. + // Adds a stub so build plugins with old versions of the Meteor package + // can still work as long as they don't directly or indirectly use + // fibers. + let stubs = require('./fiber-stubs.js'); + moduleStubs.fibers = stubs.Fiber; + moduleStubs['fibers/future'] = stubs.Future; } var env = Object.assign({ @@ -2123,6 +2155,10 @@ class JsImage { // someone passes a Windows-y module identifier. name = name.split("\\").join("/"); + if (name in moduleStubs) { + return moduleStubs[name]; + } + let resolved; try { resolved = require.resolve(name); @@ -2144,13 +2180,13 @@ class JsImage { } var nodeModulesTopDir = files.pathJoin( - nodeModulesPath, - name.split("/", 1)[0] + nodeModulesPath, + name.split("/", 1)[0] ); if (files.exists(nodeModulesTopDir)) { return fullPath = files.convertToOSPath( - files.pathJoin(nodeModulesPath, name) + files.pathJoin(nodeModulesPath, name) ); } } @@ -2176,7 +2212,7 @@ class JsImage { // // in the parent package (e.g. ecmascript, coffeescript). const nmdSourcePaths = - nodeModulesDirsByPackageName.get(bindings.Plugin.name); + nodeModulesDirsByPackageName.get(bindings.Plugin.name); if (Array.isArray(nmdSourcePaths)) { found = _.some(nmdSourcePaths, sourcePath => { return tryLookup(sourcePath, name); @@ -2193,7 +2229,7 @@ class JsImage { if (appDir && resolved) { const isOutsideAppDir = - files.pathRelative(appDir, resolved).startsWith(".."); + files.pathRelative(appDir, resolved).startsWith(".."); if (! isOutsideAppDir) { return require(resolved); @@ -2201,7 +2237,7 @@ class JsImage { } throw error || new Error( - "Cannot find module " + JSON.stringify(name) + "Cannot find module " + JSON.stringify(name) ); }) }, @@ -2220,19 +2256,6 @@ class JsImage { * @param {String} assetPath The path of the asset, relative to the application's `private` subdirectory. * @param {Function} [asyncCallback] Optional callback, which is called asynchronously with the error or result after the function is complete. If not provided, the function runs synchronously. */ - getText: function (assetPath, callback) { - const result = getAsset(item.assets, assetPath, "utf8", callback); - - if (!callback) { - if (!Fiber.current) { - throw new Error("The synchronous Assets API can " + - "only be called from within a Fiber."); - } - - return Promise.await(result); - } - }, - getTextAsync: function (assetPath) { return getAsset(item.assets, assetPath, "utf8"); }, @@ -2244,19 +2267,6 @@ class JsImage { * @param {String} assetPath The path of the asset, relative to the application's `private` subdirectory. * @param {Function} [asyncCallback] Optional callback, which is called asynchronously with the error or result after the function is complete. If not provided, the function runs synchronously. */ - getBinary: function (assetPath, callback) { - const result = getAsset(item.assets, assetPath, undefined, callback); - - if (!callback) { - if (!Fiber.current) { - throw new Error("The synchronous Assets API can " + - "only be called from within a Fiber."); - } - - return Promise.await(result); - } - }, - getBinaryAsync: function (assetPath) { return getAsset(item.assets, assetPath, undefined); } @@ -2272,7 +2282,7 @@ class JsImage { // XXX XXX Get the actual source file path -- item.targetPath // is not actually correct (it's the path in the bundle rather // than in the source tree). - files.runJavaScript(item.source.toString('utf8'), { + await files.runJavaScript(item.source.toString('utf8'), { filename: item.targetPath, symbols: env, sourceMap: item.sourceMap, @@ -2284,7 +2294,14 @@ class JsImage { failed = true; return; } - }); + } + + if (ret['core-runtime']) { + var promise = ret['core-runtime'].waitUntilAllLoaded(); + if (promise) { + await promise + } + } return ret; } @@ -2368,7 +2385,7 @@ class JsImage { // Returns an object with the following keys: // - controlFile: the path (relative to 'builder') of the control file for // the image - write(builder, { + async write(builder, { buildMode, // falsy or 'symlink', documented on exports.bundle includeNodeModules, @@ -2407,7 +2424,7 @@ class JsImage { // JavaScript sources var load = []; - _.each(self.jsToLoad, function (item) { + for (const item of self.jsToLoad) { if (! item.targetPath) { throw new Error("No targetPath?"); } @@ -2416,7 +2433,7 @@ class JsImage { node_modules: {} }; - _.each(item.nodeModulesDirectories, nmd => { + for (const nmd of Object.values(item.nodeModulesDirectories || {})) { // We need to make sure to use the directory name we got from // builder.generateFilename here. // XXX these two parallel data structures of self.jsToLoad and @@ -2424,14 +2441,14 @@ class JsImage { const generatedNMD = nodeModulesDirectories[nmd.sourcePath]; if (generatedNMD) { assert.strictEqual( - typeof generatedNMD.preferredBundlePath, - "string" + typeof generatedNMD.preferredBundlePath, + "string" ); loadItem.node_modules[generatedNMD.preferredBundlePath] = - generatedNMD.toJSON(); + await generatedNMD.toJSON(); } - }); + } const preferredPaths = Object.keys(loadItem.node_modules); if (preferredPaths.length === 1) { @@ -2450,23 +2467,23 @@ class JsImage { if (item.sourceMap) { const sourceMapBuffer = - Buffer.from(JSON.stringify(item.sourceMap), "utf8"); + Buffer.from(JSON.stringify(item.sourceMap), "utf8"); - loadItem.sourceMap = builder.writeToGeneratedFilename( - item.targetPath + ".map", - { data: sourceMapBuffer } + loadItem.sourceMap = await builder.writeToGeneratedFilename( + item.targetPath + ".map", + { data: sourceMapBuffer } ); const sourceMappingURL = - "data:application/json;charset=utf8;base64," + - sourceMapBuffer.toString("base64"); + "data:application/json;charset=utf8;base64," + + sourceMapBuffer.toString("base64"); // Remove any existing sourceMappingURL line. (eg, if roundtripping // through JsImage.readFromDisk, don't end up with two!) sourceBuffer = addSourceMappingURL( - item.source, - sourceMappingURL, - item.targetPath, + item.source, + sourceMappingURL, + item.targetPath, ); if (item.sourceMapRoot) { @@ -2479,9 +2496,9 @@ class JsImage { sourceBuffer = removeSourceMappingURLs(item.source); } - loadItem.path = builder.writeToGeneratedFilename( - item.targetPath, - { data: sourceBuffer } + loadItem.path = await builder.writeToGeneratedFilename( + item.targetPath, + { data: sourceBuffer } ); if (!_.isEmpty(item.assets)) { @@ -2489,7 +2506,7 @@ class JsImage { // assets/packages specific to this package. Application assets (e.g. those // inside private/) go in assets/app/. // XXX same hack as setTargetPathFromRelPath - var assetBundlePath; + var assetBundlePath; if (item.targetPath.match(/^packages\//)) { var dir = files.pathDirname(item.targetPath); var base = files.pathBasename(item.targetPath, ".js"); @@ -2499,22 +2516,22 @@ class JsImage { } loadItem.assets = {}; - _.each(item.assets, function (data, relPath) { + for (const [relPath, data] of Object.entries(item.assets)) { var sha = watch.sha1(data); if (_.has(assetFilesBySha, sha)) { loadItem.assets[relPath] = assetFilesBySha[sha]; } else { loadItem.assets[relPath] = assetFilesBySha[sha] = - builder.writeToGeneratedFilename( - files.pathJoin(assetBundlePath, relPath), { data: data }); + await builder.writeToGeneratedFilename( + files.pathJoin(assetBundlePath, relPath), { data: data }); } - }); + } } if (! item.targetPath.startsWith("dynamic/")) { load.push(loadItem); } - }); + } const rebuildDirs = Object.create(null); @@ -2523,7 +2540,7 @@ class JsImage { // them, and 'meteor run' symlinks them. If these contain // arch-specific code then the target will end up having an // appropriately specific arch. - _.each(nodeModulesDirectories, function (nmd) { + for (const nmd of Object.values(nodeModulesDirectories)) { assert.strictEqual(typeof nmd.preferredBundlePath, "string"); // Skip calculating isPortable in 'meteor run' since the @@ -2542,15 +2559,15 @@ class JsImage { }; const prodPackagePredicate = - // This condition essentially means we don't strip devDependencies - // when running tests, which is important for use cases like the one - // described in #7953. Note that devDependencies can still be used - // when buildMode === "development" because the app has access to - // the original node_modules. - (buildMode === "production" || - buildMode === "development") && - nmd.local && // Only filter local node_modules directories. - nmd.getProdPackagePredicate(); + // This condition essentially means we don't strip devDependencies + // when running tests, which is important for use cases like the one + // described in #7953. Note that devDependencies can still be used + // when buildMode === "development" because the app has access to + // the original node_modules. + (buildMode === "production" || + buildMode === "development") && + nmd.local && // Only filter local node_modules directories. + nmd.getProdPackagePredicate(); if (prodPackagePredicate) { // When copying a local node_modules directory, ignore any npm @@ -2566,13 +2583,13 @@ class JsImage { copyOptions.filter = prodPackagePredicate; } - builder.copyNodeModulesDirectory(copyOptions); + await builder.copyNodeModulesDirectory(copyOptions); } - }); + } // This JSON file will be read by npm-rebuild.js, which is executed to // trigger rebuilds for all non-portable npm packages. - builder.write("npm-rebuilds.json", { + await builder.write("npm-rebuilds.json", { data: Buffer.from( JSON.stringify(Object.keys(rebuildDirs), null, 2) + "\n", "utf8" @@ -2580,7 +2597,7 @@ class JsImage { }); // Control file - builder.writeJson('program.json', { + await builder.writeJson('program.json', { format: "javascript-image-pre1", arch: self.arch, load: load @@ -2594,8 +2611,8 @@ class JsImage { // Create a JsImage by loading a bundle of format // 'javascript-image-pre1' from disk (eg, previously written out with // write()). `dir` is the path to the control file. - static readFromDisk (controlFilePath) { - var ret = new JsImage; + static async readFromDisk (controlFilePath) { + var ret = new JsImage(); var json = JSON.parse(files.readFile(controlFilePath)); var dir = files.pathDirname(controlFilePath); @@ -2609,18 +2626,18 @@ class JsImage { // Rebuild binary npm packages if host arch matches image arch. const rebuildBinaries = archinfo.matches(archinfo.host(), ret.arch); - _.each(json.load, function (item) { + for (const item of json.load) { rejectBadPath(item.path); let nodeModulesDirectories; if (item.node_modules) { Object.assign( - ret.nodeModulesDirectories, - nodeModulesDirectories = - NodeModulesDirectory.readDirsFromJSON(item.node_modules, { - sourceRoot: dir, - rebuildBinaries, - }) + ret.nodeModulesDirectories, + nodeModulesDirectories = + await NodeModulesDirectory.readDirsFromJSON(item.node_modules, { + sourceRoot: dir, + rebuildBinaries, + }) ); } @@ -2634,7 +2651,7 @@ class JsImage { // XXX this is the same code as isopack.initFromPath rejectBadPath(item.sourceMap); loadItem.sourceMap = JSON.parse(files.readFile( - files.pathJoin(dir, item.sourceMap), 'utf8')); + files.pathJoin(dir, item.sourceMap), 'utf8')); loadItem.sourceMapRoot = item.sourceMapRoot; } @@ -2646,7 +2663,7 @@ class JsImage { } ret.jsToLoad.push(loadItem); - }); + } return ret; } @@ -2717,7 +2734,7 @@ class ServerTarget extends JsImageTarget { // // Returns the path (relative to 'builder') of the control file for // the plugin and the required NODE_PATH. - write(builder, { + async write(builder, { buildMode, // falsy or 'symlink', documented in exports.bundle includeNodeModules, @@ -2729,7 +2746,7 @@ class ServerTarget extends JsImageTarget { // We will write out config.json, the dependency kit, and the // server driver alongside the JsImage - builder.writeJson("config.json", { + await builder.writeJson("config.json", { meteorRelease: self.releaseName || undefined, appId: self.appIdentifier || undefined, clientArchs: self.clientArchs || undefined, @@ -2747,17 +2764,17 @@ class ServerTarget extends JsImageTarget { serverPkgJson.dependencies["node-gyp"] = require("node-gyp/package.json").version; - serverPkgJson.dependencies["node-pre-gyp"] = - require("node-pre-gyp/package.json").version; + serverPkgJson.dependencies["@mapbox/node-pre-gyp"] = + require("@mapbox/node-pre-gyp/package.json").version; - builder.write('package.json', { + await builder.write('package.json', { data: Buffer.from( JSON.stringify(serverPkgJson, null, 2) + "\n", "utf8" ) }); - builder.write('npm-shrinkwrap.json', { + await builder.write('npm-shrinkwrap.json', { file: files.pathJoin(files.getDevBundle(), 'etc', 'npm-shrinkwrap.json') }); @@ -2765,7 +2782,7 @@ class ServerTarget extends JsImageTarget { // install' using the above package.json and npm-shrinkwrap.json on every // rebuild). if (includeNodeModules === 'symlink') { - builder.write('node_modules', { + await builder.write('node_modules', { symlink: files.pathJoin(files.getDevBundle(), 'server-lib', 'node_modules') }); } else if (includeNodeModules) { @@ -2778,7 +2795,7 @@ class ServerTarget extends JsImageTarget { // Linked JavaScript image (including static assets, assuming that there are // any JS files at all) var jsImage = self.toJsImage(); - jsImage.write(builder, { + await jsImage.write(builder, { buildMode, includeNodeModules, }); @@ -2786,14 +2803,14 @@ class ServerTarget extends JsImageTarget { const toolsDir = files.pathDirname( files.convertToStandardPath(__dirname)); - builder.copyTranspiledModules([ + await builder.copyTranspiledModules([ "profile.ts" ], { sourceRootDir: files.pathJoin(toolsDir, "tool-env"), }); // Server bootstrap - builder.copyTranspiledModules([ + await builder.copyTranspiledModules([ "boot.js", "boot-utils.js", "debug.ts", @@ -2841,7 +2858,7 @@ class ServerTarget extends JsImageTarget { ServerTarget.prototype[method] = Profile(`ServerTarget#${method}`, ServerTarget.prototype[method]); }); -var writeFile = Profile("bundler writeFile", function (file, builder, options) { +var writeFile = Profile("bundler writeFile", async function (file, builder, options) { if (! file.targetPath) { throw new Error("No targetPath?"); } @@ -2852,7 +2869,7 @@ var writeFile = Profile("bundler writeFile", function (file, builder, options) { // directories) let data = file.contents(); - const hash = file.hash(); + const hash = await file.hash(); if (builder.usePreviousWrite(file.targetPath, hash)) { return; @@ -2868,7 +2885,7 @@ var writeFile = Profile("bundler writeFile", function (file, builder, options) { data = removeSourceMappingURLs(data); } - builder.write(file.targetPath, { data, hash }); + await builder.write(file.targetPath, { data, hash }); }); // Takes a Buffer or string and returns a Buffer. If it looks like there @@ -2927,7 +2944,7 @@ function addSourceMappingURL(data, url, targetPath) { // Writes a target a path in 'programs' var writeTargetToPath = Profile( "bundler writeTargetToPath", - function (name, target, outputPath, { + async function (name, target, outputPath, { includeNodeModules, previousBuilder = null, buildMode, @@ -2946,13 +2963,15 @@ var writeTargetToPath = Profile( forceInPlaceBuild }); - var targetBuild = target.write(builder, { + await builder.init(); + + var targetBuild = await target.write(builder, { includeNodeModules, buildMode, minifyMode, }); - builder.complete(); + await builder.complete(); return { name, @@ -2987,7 +3006,7 @@ var writeTargetToPath = Profile( // - builtBy: vanity identification string to write into metadata // - releaseName: The Meteor release version // - previousBuilder: previous Builder object used in previous iteration -var writeSiteArchive = Profile("bundler writeSiteArchive", function ( +var writeSiteArchive = Profile("bundler writeSiteArchive", async function ( targets, outputPath, { includeNodeModules, builtBy, @@ -3012,6 +3031,8 @@ var writeSiteArchive = Profile("bundler writeSiteArchive", function ( forceInPlaceBuild: true, }); + await builders.star.init(); + try { Object.keys(targets).forEach(key => { // Both makeClientTarget and makeServerTarget get their sourceRoot @@ -3026,7 +3047,7 @@ var writeSiteArchive = Profile("bundler writeSiteArchive", function ( meteorRelease: releaseName, nodeVersion: process.versions.node, npmVersion: meteorNpm.npmVersion, - gitCommitHash: process.env.METEOR_GIT_COMMIT_HASH || files.findGitCommitHash(sourceRoot), + gitCommitHash: process.env.METEOR_GIT_COMMIT_HASH || await files.findGitCommitHash(sourceRoot), }; // Tell the deploy server what version of the dependency kit we're using, so @@ -3034,22 +3055,22 @@ var writeSiteArchive = Profile("bundler writeSiteArchive", function ( // symlinked a node_modules, since that's probably enough for it to work in // spite of the presence of node_modules for the wrong arch). The place we // stash this is grody for temporary reasons of backwards compatibility. - builder.write(files.pathJoin('server', '.bundle_version.txt'), { + await builder.write(files.pathJoin('server', '.bundle_version.txt'), { file: files.pathJoin(files.getDevBundle(), '.bundle_version.txt') }); - builder.write('.node_version.txt', { + await builder.write('.node_version.txt', { data: Buffer.from(process.version + '\n', 'utf8') }); // Affordances for standalone use if (targets.server) { // add program.json as the first argument after "node main.js" to the boot script. - builder.write('main.js', { + await builder.write('main.js', { data: Buffer.from(exports._mainJsContents, 'utf8') }); - builder.write('README', { data: Buffer.from( + await builder.write('README', { data: Buffer.from( `This is a Meteor application bundle. It has only one external dependency: Node.js ${process.version}. To run the application: @@ -3080,12 +3101,12 @@ Find out more about Meteor at meteor.com. } }); - Object.keys(targets).forEach(name => { + for (const name of Object.keys(targets)) { const target = targets[name]; const { arch, path, cordovaDependencies, builder: targetBuilder - } = writeTargetToPath(name, target, builder.buildPath, { + } = await writeTargetToPath(name, target, builder.buildPath, { includeNodeModules, builtBy, releaseName, @@ -3100,13 +3121,13 @@ Find out more about Meteor at meteor.com. json.programs.push({ name, arch, path, cordovaDependencies }); - }); + } // Control file - builder.writeJson('star.json', json); + await builder.writeJson('star.json', json); // We did it! - builder.complete(); + await builder.complete(); // Now, go and "fix up" the outputPath properties of the sub-builders. // Since the sub-builders originally were targeted at a temporary @@ -3125,7 +3146,7 @@ Find out more about Meteor at meteor.com. builders, }; } catch (e) { - builder.abort(); + await builder.abort(); throw e; } }); @@ -3205,7 +3226,7 @@ exports.bundle = Profile("bundler.bundle", function (options) { return files.withCache(() => bundle(options)); }); -function bundle({ +async function bundle({ projectContext, outputPath, includeNodeModules, @@ -3259,14 +3280,14 @@ function bundle({ throw new Error('Unrecognized build mode: ' + buildMode); } - var messages = buildmessage.capture({ + var messages = await buildmessage.capture({ title: "building the application" - }, function () { - var packageSource = new PackageSource; + }, async function () { + var packageSource = new PackageSource(); packageSource.initFromAppDir(projectContext, exports.ignoreFiles); var makeClientTarget = Profile( - "bundler.bundle..makeClientTarget", function (app, webArch, options) { + "bundler.bundle..makeClientTarget", async function (app, webArch, options) { var client = new ClientTarget({ bundlerCacheDir, packageMap: projectContext.packageMap, @@ -3278,19 +3299,19 @@ function bundle({ buildMode: buildOptions.buildMode }); - client.make({ + await client.make({ packages: [app], minifyMode: minifyMode, minifiers: options.minifiers || [], addCacheBusters: true, - onJsOutputFiles + onJsOutputFiles, }); return client; }); var makeServerTarget = Profile( - "bundler.bundle..makeServerTarget", function (app, clientArchs) { + "bundler.bundle..makeServerTarget", async function (app, clientArchs) { const server = new ServerTarget({ bundlerCacheDir, packageMap: projectContext.packageMap, @@ -3303,7 +3324,7 @@ function bundle({ clientArchs, }); - server.make({ + await server.make({ packages: [app] }); @@ -3313,7 +3334,7 @@ function bundle({ // Create a Isopack object that represents the app // XXX should this be part of prepareProjectForBuild and get cached? // at the very least, would speed up deploy after build. - var app = compiler.compile(packageSource, { + var app = await compiler.compile(packageSource, { packageMap: projectContext.packageMap, isopackCache: projectContext.isopackCache, includeCordovaUnibuild: projectContext.platformList.usesCordova() @@ -3338,7 +3359,7 @@ function bundle({ } if (! buildmessage.jobHasMessages()) { - lintingMessages = lintBundle(projectContext, app, packageSource); + lintingMessages = await lintBundle(projectContext, app, packageSource); } // If while trying to lint, we got a compilation error (eg, an issue loading // plugins in one of the linter packages), restart on any relevant change, @@ -3351,7 +3372,7 @@ function bundle({ if (! ['development', 'production'].includes(minifyMode)) { throw new Error('Unrecognized minification mode: ' + minifyMode); } - minifiers = compiler.getMinifiers(packageSource, { + minifiers = await compiler.getMinifiers(packageSource, { isopackCache: projectContext.isopackCache, isopack: app }); @@ -3380,9 +3401,9 @@ function bundle({ forceInPlaceBuild, }; - function writeClientTarget(target) { + async function writeClientTarget(target) { const { arch } = target; - const written = writeTargetToPath(arch, target, outputPath, { + const written = await writeTargetToPath(arch, target, outputPath, { buildMode: buildOptions.buildMode, previousBuilder: previousBuilders[arch], ...writeOptions, @@ -3392,7 +3413,7 @@ function bundle({ } // Client - webArchs.forEach(arch => { + for (const arch of webArchs) { if (allowDelayedClientBuilds && hasOwn.call(previousBuilders, arch) && projectContext.platformList.canDelayBuildingArch(arch)) { @@ -3401,14 +3422,14 @@ function bundle({ // build later (e.g. web.browser.legacy), then schedule it to be // built after the server has started up. postStartupCallbacks.push(async ({ - pauseClient, - refreshClient, - runLog, - }) => { + pauseClient, + refreshClient, + runLog, + }) => { const start = +new Date; // Build the target first. - const target = makeClientTarget(app, arch, { minifiers }); + const target = await makeClientTarget(app, arch, { minifiers }); // Tell the webapp package to pause responding to requests from // clients that use this arch, because we're about to write a @@ -3420,7 +3441,7 @@ function bundle({ // Now write the target to disk. Note that we are rewriting the // bundle in place, so this work is not atomic by any means, // which is why we needed to pause the client. - writeClientTarget(target); + await writeClientTarget(target); // Refresh and unpause the client, now that writing is finished. // If the child process exited for some reason, don't worry if @@ -3431,29 +3452,30 @@ function bundle({ // should regenerate the client program for this arch. if (Profile.enabled) { runLog.log(`Finished delayed build of ${arch} in ${ - new Date - start + new Date - start }ms`, { arrow: true }); } }); - } else { // Otherwise make the client target now, and write it below. - targets[arch] = makeClientTarget(app, arch, {minifiers}); + targets[arch] = await makeClientTarget(app, arch, {minifiers}); } - }); + } // Server if (! hasCachedBundle) { - targets.server = makeServerTarget(app, webArchs); + targets.server = await makeServerTarget(app, webArchs); } if (outputPath !== null) { if (hasCachedBundle) { // If we already have a cached bundle, just recreate the new targets. // XXX This might make the contents of "star.json" out of date. - _.each(targets, writeClientTarget); + for (const target of Object.values(targets)) { + await writeClientTarget(target); + } } else { - starResult = writeSiteArchive(targets, outputPath, { + starResult = await writeSiteArchive(targets, outputPath, { buildMode: buildOptions.buildMode, previousBuilders, sourceRoot: packageSource.sourceRoot, @@ -3497,14 +3519,14 @@ function ignoreHarmlessErrors(error) { // Returns null if there are no lint warnings and the app has no linters // defined. Returns an empty MessageSet if the app has a linter defined but // there are no lint warnings (on app or packages). -function lintBundle (projectContext, isopack, packageSource) { +async function lintBundle (projectContext, isopack, packageSource) { buildmessage.assertInJob(); let lintedAnything = false; const lintingMessages = new buildmessage._MessageSet(); if (projectContext.lintAppAndLocalPackages) { - const {warnings: appMessages, linted} = compiler.lint(packageSource, { + const {warnings: appMessages, linted} = await compiler.lint(packageSource, { isopack, isopackCache: projectContext.isopackCache }); @@ -3515,7 +3537,7 @@ function lintBundle (projectContext, isopack, packageSource) { } const localPackagesMessages = - projectContext.getLintingMessagesForLocalPackages(); + await projectContext.getLintingMessagesForLocalPackages(); if (localPackagesMessages) { lintedAnything = true; lintingMessages.merge(localPackagesMessages); @@ -3564,7 +3586,7 @@ function lintBundle (projectContext, isopack, packageSource) { // It would be nice to have a way to say "make this package anonymous" // without also saying "make its namespace the same as the global // namespace." It should be an easy refactor, -exports.buildJsImage = Profile("bundler.buildJsImage", function (options) { +exports.buildJsImage = Profile("bundler.buildJsImage", async function (options) { buildmessage.assertInCapture(); if (options.npmDependencies && ! options.npmDir) { throw new Error("Must indicate .npm directory to use"); @@ -3573,9 +3595,9 @@ exports.buildJsImage = Profile("bundler.buildJsImage", function (options) { throw new Error("Must provide a name"); } - var packageSource = new PackageSource; + var packageSource = new PackageSource(); - packageSource.initFromOptions(options.name, { + await packageSource.initFromOptions(options.name, { kind: "plugin", use: options.use || [], sourceRoot: options.sourceRoot, @@ -3588,7 +3610,7 @@ exports.buildJsImage = Profile("bundler.buildJsImage", function (options) { localNodeModulesDirs: options.localNodeModulesDirs, }); - var isopack = compiler.compile(packageSource, { + var isopack = await compiler.compile(packageSource, { packageMap: options.packageMap, isopackCache: options.isopackCache, // There's no web.cordova unibuild here anyway, just os. @@ -3606,7 +3628,8 @@ exports.buildJsImage = Profile("bundler.buildJsImage", function (options) { // (which always wants to build for the current host). arch: archinfo.host() }); - target.make({ packages: [isopack] }); + + await target.make({ packages: [isopack] }); return { image: target.toJsImage(), diff --git a/tools/isobuild/compiler-plugin.js b/tools/isobuild/compiler-plugin.js index 9f58f39c33..6eaa2f332c 100644 --- a/tools/isobuild/compiler-plugin.js +++ b/tools/isobuild/compiler-plugin.js @@ -8,23 +8,16 @@ var linker = require('./linker.js'); var _ = require('underscore'); var Profile = require('../tool-env/profile').Profile; import assert from "assert"; -import { - WatchSet, - sha1, - readAndWatchFileWithHash, -} from '../fs/watch'; -import LRU from 'lru-cache'; +import {readAndWatchFileWithHash, sha1, WatchSet,} from '../fs/watch'; +import LRUCache from 'lru-cache'; import {sourceMapLength} from '../utils/utils.js'; import {Console} from '../console/console.js'; import ImportScanner from './import-scanner'; import {cssToCommonJS} from "./css-modules"; import Resolver from "./resolver"; -import { - optimisticStatOrNull, - optimisticHashOrNull, -} from "../fs/optimistic"; +import {optimisticHashOrNull, optimisticStatOrNull,} from "../fs/optimistic"; -import { isTestFilePath } from './test-files.js'; +import {isTestFilePath} from './test-files.js'; const hasOwn = Object.prototype.hasOwnProperty; @@ -68,12 +61,12 @@ const hasOwn = Object.prototype.hasOwnProperty; // Cache the (slightly post-processed) results of linker.fullLink. const CACHE_SIZE = process.env.METEOR_LINKER_CACHE_SIZE || 1024*1024*100; const CACHE_DEBUG = !! process.env.METEOR_TEST_PRINT_LINKER_CACHE_DEBUG; -const LINKER_CACHE_SALT = 24; // Increment this number to force relinking. -const LINKER_CACHE = new LRU({ +const LINKER_CACHE_SALT = 26; // Increment this number to force relinking. +const LINKER_CACHE = new LRUCache({ max: CACHE_SIZE, // Cache is measured in bytes. We don't care about servePath. // Key is JSONification of all options plus all hashes. - length: function (files) { + length (files) { return files.reduce((soFar, current) => { return soFar + current.data.length + sourceMapLength(current.sourceMap); }, 0); @@ -137,25 +130,30 @@ export class CompilerPluginProcessor { } } - runCompilerPlugins() { + async runCompilerPlugins() { const self = this; buildmessage.assertInJob(); // plugin id -> {sourceProcessor, resourceSlots} var sourceProcessorsWithSlots = {}; - var sourceBatches = _.map(self.unibuilds, function (unibuild) { + const sourceBatches = []; + for (const unibuild of self.unibuilds) { const { pkg: { name }, arch } = unibuild; const sourceRoot = name - && self.isopackCache.getSourceRoot(name, arch) - || self.sourceRoot; + && self.isopackCache.getSourceRoot(name, arch) + || self.sourceRoot; - return new PackageSourceBatch(unibuild, self, { + const batch = new PackageSourceBatch(unibuild, self, { sourceRoot, linkerCacheDir: self.linkerCacheDir, scannerCacheDir: self.scannerCacheDir, }); - }); + + await batch.init(); + + sourceBatches.push(batch); + } // If we failed to match sources with processors, we're done. if (buildmessage.jobHasMessages()) { @@ -182,8 +180,8 @@ export class CompilerPluginProcessor { }); }); - // Now actually run the handlers. - _.each(sourceProcessorsWithSlots, function (data, id) { + // Now actually run the handlers + for (const [id, data] of Object.entries(sourceProcessorsWithSlots)) { var sourceProcessor = data.sourceProcessor; var resourceSlots = data.resourceSlots; @@ -193,27 +191,25 @@ export class CompilerPluginProcessor { " (for target ", self.arch, ")" ].join(''); - Profile.time("plugin "+sourceProcessor.isopack.name, () => { - buildmessage.enterJob({ + await Profile.time("plugin "+sourceProcessor.isopack.name, async () => { + await buildmessage.enterJob({ title: jobTitle - }, function () { - var inputFiles = _.map(resourceSlots, function (resourceSlot) { - return new InputFile(resourceSlot); - }); + }, async function () { + var inputFiles = resourceSlots.map(resourceSlot => new InputFile(resourceSlot)); const markedMethod = buildmessage.markBoundary( - sourceProcessor.userPlugin.processFilesForTarget, - sourceProcessor.userPlugin + sourceProcessor.userPlugin.processFilesForTarget, + sourceProcessor.userPlugin ); try { - Promise.await(markedMethod(inputFiles)); + await markedMethod(inputFiles); } catch (e) { buildmessage.exception(e); } }); }); - }); + } return sourceBatches; } @@ -243,6 +239,13 @@ class InputFile extends buildPluginModule.InputFile { // accept a lazy finalizer function as a second argument, so that // compilation can be avoided until/unless absolutely necessary. this.supportsLazyCompilation = true; + + // Communicate to compiler plugins that this version of Meteor + // is able to support top level await + // TODO: maybe this should also check if the file and package meet the + // minimum requirements to use top level await (file isn't bare, and + // package uses core-runtime and modules) + this.supportsTopLevelAwait = true; } getContentsAsBuffer() { @@ -539,13 +542,13 @@ class InputFile extends buildPluginModule.InputFile { * @memberOf InputFile * @instance */ - addHtml(options, lazyFinalizer) { + async addHtml(options, lazyFinalizer) { if (typeof lazyFinalizer === "function") { // For now, just call the lazyFinalizer function immediately. Since // HTML is not compiled, this immediate invocation is probably // permanently appropriate for addHtml, whereas methods like // addJavaScript benefit from waiting to call lazyFinalizer. - Object.assign(options, Promise.await(lazyFinalizer())); + Object.assign(options, await lazyFinalizer()); } this._resourceSlot.addHtml(options); @@ -576,16 +579,16 @@ class ResourceSlot { self.packageSourceBatch = packageSourceBatch; if (self.inputResource.type === "source") { - if (sourceProcessor) { + if (self.sourceProcessor) { // If we have a sourceProcessor, it will handle the adding of the // final processed JavaScript. } else if (self.inputResource.extension === "js") { self._addDirectlyToJsOutputResources(); } } else { - if (sourceProcessor) { + if (self.sourceProcessor) { throw Error("sourceProcessor for non-source? " + - JSON.stringify(unibuildResourceInfo)); + JSON.stringify(self.inputResource)); } // Any resource that isn't handled by compiler plugins just gets passed // through. @@ -726,16 +729,16 @@ class ResourceSlot { // file is lazy, add it as a lazy JS module instead of adding it // unconditionally as a CSS resource, so that it can be imported // when needed. - const jsResource = this.addJavaScript(options, () => { + const jsResource = this.addJavaScript(options, async () => { const result = {}; - let css = this.packageSourceBatch.processor + let css = await this.packageSourceBatch.processor .minifyCssResource(cssResource); if (! css && typeof css !== "string") { // The minifier didn't do anything, so we should use the // original contents of cssResource.data. - css = cssResource.data.toString("utf8"); + css = (await cssResource.data).toString("utf8"); if (cssResource.sourceMap) { // Add the source map as an asset, and append a @@ -780,13 +783,16 @@ class ResourceSlot { // stub, so setting .implicit marks the resource as disposable. }).implicit = true; - if (! cssResource.lazy && - ! Buffer.isBuffer(cssResource.data)) { - // If there was an error processing this file, cssResource.data - // will not be a Buffer, and accessing cssResource.data here - // should cause the error to be reported via inputFile.error. - return; - } + // TODO[FIBERS]: Look into this. We probably don't want addStylesheet + // to be async, and I'm also not sure the old behavior here is what we wanted + // + // if (! cssResource.lazy &&s + // ! Buffer.isBuffer(cssResource.data)) { + // // If there was an error processing this file, cssResource.data + // // will not be a Buffer, and accessing cssResource.data here + // // should cause the error to be reported via inputFile.error. + // return; + // } this.outputResources.push(cssResource); } @@ -899,45 +905,47 @@ class OutputResource { }); } - finalize() { + async finalize() { if (this._finalizerPromise) { - this._finalizerPromise.await(); + await this._finalizerPromise; } else if (this._lazyFinalizer) { const finalize = this._lazyFinalizer; this._lazyFinalizer = null; - (this._finalizerPromise = - // It's important to initialize this._finalizerPromise to the new - // Promise before calling finalize(), so there's no possibility of - // finalize() triggering code that reenters this function before we - // have the final version of this._finalizerPromise. If this code - // used `new Promise(resolve => resolve(finalize()))` instead of - // `Promise.resolve().then(finalize)`, the finalize() call would - // begin before this._finalizerPromise was fully initialized. - Promise.resolve().then(finalize).then(result => { - if (result) { - Object.assign(this._initialOptions, result); - } else if (this._errors.length === 0) { - // In case the finalize() call failed without reporting any - // errors, create at least one generic error that can be - // reported when reportPendingErrors is called. - const error = new Error("lazyFinalizer failed"); - error.info = { resource: this, finalize } - this._errors.push(error); - } - // The this._finalizerPromise object only survives for the - // duration of the initial finalization. - this._finalizerPromise = null; - })).await(); + + // It's important to initialize this._finalizerPromise to the new + // Promise before calling finalize(), so there's no possibility of + // finalize() triggering code that reenters this function before we + // have the final version of this._finalizerPromise. If this code + // used `new Promise(resolve => resolve(finalize()))` instead of + // `Promise.resolve().then(finalize)`, the finalize() call would + // begin before this._finalizerPromise was fully initialized. + (this._finalizerPromise = Promise.resolve().then(finalize).then(result => { + if (result) { + Object.assign(this._initialOptions, result); + } else if (this._errors.length === 0) { + // In case the finalize() call failed without reporting any + // errors, create at least one generic error that can be + // reported when reportPendingErrors is called. + const error = new Error("lazyFinalizer failed"); + error.info = { resource: this, finalize }; + this._errors.push(error); + } + // The this._finalizerPromise object only survives for the + // duration of the initial finalization. + this._finalizerPromise = null; + })); + + await this._finalizerPromise; } } - hasPendingErrors() { - this.finalize(); + async hasPendingErrors() { + await this.finalize(); return this._errors.length > 0; } - reportPendingErrors() { - if (this.hasPendingErrors()) { + async reportPendingErrors() { + if (await this.hasPendingErrors()) { const firstError = this._errors[0]; buildmessage.error( firstError.message, @@ -958,18 +966,22 @@ class OutputResource { // Method for getting properties that may be computed lazily, or that // require some one-time post-processing. - _get(name) { + async _get(name) { if (hasOwn.call(this, name)) { return this[name]; } - if (this.hasPendingErrors()) { + if (await this.hasPendingErrors()) { // If you're considering using this resource, you should call // hasPendingErrors or reportPendingErrors to find out if it's safe // to access computed properties like .data, .hash, or .sourceMap. // If you get here without checking for errors first, those errors // will be fatal. - throw this._errors[0]; + throw new Error( + `_get "${name}" called for file with pending errors | ERROR: ${JSON.stringify( + this._errors[0] + )}` + ); } switch (name) { @@ -987,7 +999,7 @@ class OutputResource { hashes.push(this._inputHash); } - hashes.push(sha1(this._get("data"))); + hashes.push(sha1(await this._get("data"))); return this._set("hash", sha1(...hashes)); } @@ -1061,12 +1073,6 @@ export class PackageSourceBatch { self._nodeModulesPaths = null; self.resourceSlots = []; - unibuild.resources.forEach(resource => { - const slot = self.makeResourceSlot(resource); - if (slot) { - self.resourceSlots.push(slot); - } - }); // Compute imports by merging the exports of all of the packages we // use. Note that in the case of conflicting symbols, later packages get @@ -1080,7 +1086,19 @@ export class PackageSourceBatch { // depends on something). self.importedSymbolToPackageName = {}; // map from symbol to supplying package name - compiler.eachUsedUnibuild({ + self.deps = []; + } + + async init() { + const self = this; + for (const resource of this.unibuild.resources) { + const slot = await self.makeResourceSlot(resource); + if (slot) { + self.resourceSlots.push(slot); + } + } + + await compiler.eachUsedUnibuild({ dependencies: self.unibuild.uses, arch: self.processor.arch, isopackCache: self.processor.isopackCache, @@ -1091,34 +1109,38 @@ export class PackageSourceBatch { skipDebugOnly: true, skipProdOnly: true, skipTestOnly: true, - }, depUnibuild => { + }, (depUnibuild, { weak, unordered }) => { + let packageName = depUnibuild.pkg.name; + _.each(depUnibuild.declaredExports, function (symbol) { // Slightly hacky implementation of test-only exports. if (! symbol.testOnly || self.unibuild.pkg.isTest) { - self.importedSymbolToPackageName[symbol.name] = depUnibuild.pkg.name; + self.importedSymbolToPackageName[symbol.name] = packageName; } }); + + self.deps.push({ package: packageName, weak, unordered }); }); self.useMeteorInstall = - _.isString(self.sourceRoot) && - self.processor.isopackCache.uses( - self.unibuild.pkg, - "modules", - self.unibuild.arch - ); + _.isString(self.sourceRoot) && + self.processor.isopackCache.uses( + self.unibuild.pkg, + "modules", + self.unibuild.arch + ); const isDevelopment = self.processor.buildMode === 'development'; const usesHMRPackage = self.unibuild.pkg.name !== "hot-module-replacement" && - self.processor.isopackCache.uses( - self.unibuild.pkg, - "hot-module-replacement", - self.unibuild.arch - ); + self.processor.isopackCache.uses( + self.unibuild.pkg, + "hot-module-replacement", + self.unibuild.arch + ); const supportedArch = archinfo.matches(self.unibuild.arch, 'web'); self.hmrAvailable = self.useMeteorInstall && isDevelopment - && usesHMRPackage && supportedArch; + && usesHMRPackage && supportedArch; // These are the options that should be passed as the second argument // to meteorInstall when modules in this source batch are installed. @@ -1127,8 +1149,8 @@ export class PackageSourceBatch { } : null; } - compileOneJsResource(resource) { - const slot = this.makeResourceSlot({ + async compileOneJsResource(resource) { + const slot = await this.makeResourceSlot({ type: "source", extension: "js", // Need { data, path, hash } here, at least. @@ -1144,7 +1166,7 @@ export class PackageSourceBatch { // added directly to slot.jsOutputResources by makeResourceSlot, // meaning we do not need to compile it. if (slot.jsOutputResources.length > 0) { - return slot.jsOutputResources + return slot.jsOutputResources; } const inputFile = new InputFile(slot); @@ -1158,7 +1180,7 @@ export class PackageSourceBatch { userPlugin ); try { - Promise.await(markedMethod([inputFile])); + await markedMethod([inputFile]); } catch (e) { buildmessage.exception(e); } @@ -1171,13 +1193,13 @@ export class PackageSourceBatch { return []; } - makeResourceSlot(resource) { + async makeResourceSlot(resource) { let sourceProcessor = null; if (resource.type === "source") { var extension = resource.extension; if (extension === null) { const filename = files.pathBasename(resource.path); - sourceProcessor = this._getSourceProcessorSet().getByFilename(filename); + sourceProcessor = (await this._getSourceProcessorSet()).getByFilename(filename); if (! sourceProcessor) { buildmessage.error( `no plugin found for ${ resource.path } in ` + @@ -1187,7 +1209,7 @@ export class PackageSourceBatch { // recover by ignoring } } else { - sourceProcessor = this._getSourceProcessorSet().getByExtension(extension); + sourceProcessor = (await this._getSourceProcessorSet()).getByExtension(extension); // If resource.extension === 'js', it's ok for there to be no // sourceProcessor, since we #HardcodeJs in ResourceSlot. if (! sourceProcessor && extension !== 'js') { @@ -1203,7 +1225,7 @@ export class PackageSourceBatch { } } - return new ResourceSlot(resource, sourceProcessor, this); + return new ResourceSlot(resource, sourceProcessor, this); } addImportExtension(extension) { @@ -1245,12 +1267,12 @@ export class PackageSourceBatch { return this._nodeModulesPaths; } - _getSourceProcessorSet() { + async _getSourceProcessorSet() { if (! this._sourceProcessorSet) { buildmessage.assertInJob(); const isopack = this.unibuild.pkg; - const activePluginPackages = compiler.getActivePluginPackages(isopack, { + const activePluginPackages = await compiler.getActivePluginPackages(isopack, { uses: this.unibuild.uses, isopackCache: this.processor.isopackCache }); @@ -1258,19 +1280,19 @@ export class PackageSourceBatch { this._sourceProcessorSet = new buildPluginModule.SourceProcessorSet( isopack.displayName(), { hardcodeJs: true }); - _.each(activePluginPackages, otherPkg => { - otherPkg.ensurePluginsInitialized(); + for (const otherPkg of activePluginPackages) { + await otherPkg.ensurePluginsInitialized(); this._sourceProcessorSet.merge(otherPkg.sourceProcessors.compiler, { arch: this.processor.arch, }); - }); + } } return this._sourceProcessorSet; } // Returns a map from package names to arrays of JS output files. - static computeJsOutputFilesMap(sourceBatches) { + static async computeJsOutputFilesMap(sourceBatches) { const map = new Map; sourceBatches.forEach(batch => { @@ -1298,40 +1320,42 @@ export class PackageSourceBatch { // Append install() calls to the install-packages.js file in the // modules package for every Meteor package name used. - map.get("modules").files.some(file => { + for (const file of map.get("modules").files) { if (file.sourcePath !== "install-packages.js") { - return false; + continue; } const meteorPackageInstalls = []; - map.forEach((info, name) => { if (! name) return; const mainModule = info.mainModule && - `meteor/${name}/${info.mainModule.targetPath}`; + `meteor/${name}/${info.mainModule.targetPath}`; meteorPackageInstalls.push( - "install(" + JSON.stringify(name) + + "install(" + JSON.stringify(name) + (mainModule ? ", " + JSON.stringify(mainModule) : '') + - ");\n" + ");\n" ); }); if (meteorPackageInstalls.length === 0) { - return false; + continue; } - file.data = Buffer.from( - file.data.toString("utf8") + "\n" + + const fileData = await file.data; + const bufferData = Buffer.from( + fileData.toString("utf8") + "\n" + meteorPackageInstalls.join(""), - "utf8" + "utf8" ); + const fileHash = sha1(bufferData); - file.hash = sha1(file.data); - - return true; - }); + // The getter's from file (file.data and file.hash) are async, unfortunately. + // That's why we need the Object.assign here. + Object.assign(file, { data: bufferData, hash: fileHash }); + break; + } // Map from module identifiers that previously could not be imported // to lists of info objects describing the failed imports. @@ -1340,16 +1364,16 @@ export class PackageSourceBatch { // Records the subset of allMissingModules that were successfully // relocated to a source batch that could handle them. const allRelocatedModules = Object.create(null); - const scannerMap = new Map; + const scannerMap = new Map(); - sourceBatches.forEach(batch => { + for (const batch of sourceBatches) { const name = batch.unibuild.pkg.name || null; const isApp = ! name; if (! batch.useMeteorInstall && ! isApp) { // If this batch represents a package that does not use the module // system, then we don't need to scan its dependencies. - return; + continue; } const nodeModulesPaths = []; @@ -1374,23 +1398,23 @@ export class PackageSourceBatch { cacheDir: batch.scannerCacheDir, }); - scanner.addInputFiles(entry.files); + await scanner.addInputFiles(entry.files); if (batch.useMeteorInstall) { - scanner.scanImports(); - ImportScanner.mergeMissing( - allMissingModules, - scanner.allMissingModules + await scanner.scanImports(); + await ImportScanner.mergeMissing( + allMissingModules, + scanner.allMissingModules ); } scannerMap.set(name, scanner); - }); + } - function handleMissing(missingModules) { + async function handleMissing(missingModules) { const missingMap = new Map; - _.each(missingModules, (importInfoList, id) => { + for (let [id, importInfoList] of Object.entries(missingModules)) { const parts = id.split("/"); let name = null; @@ -1413,39 +1437,39 @@ export class PackageSourceBatch { } if (! found) { - return; + continue; } } if (! scannerMap.has(name)) { - return; + continue; } if (! missingMap.has(name)) { missingMap.set(name, Object.create(null)); } - ImportScanner.mergeMissing( - missingMap.get(name), - { [id]: importInfoList } + await ImportScanner.mergeMissing( + missingMap.get(name), + { [id]: importInfoList } ); - }); + } const nextMissingModules = Object.create(null); - missingMap.forEach((missing, name) => { + for (const [name, missing] of missingMap) { const { newlyAdded, newlyMissing } = - scannerMap.get(name).scanMissingModules(missing); - ImportScanner.mergeMissing(allRelocatedModules, newlyAdded); - ImportScanner.mergeMissing(nextMissingModules, newlyMissing); - }); + await scannerMap.get(name).scanMissingModules(missing); + await ImportScanner.mergeMissing(allRelocatedModules, newlyAdded); + await ImportScanner.mergeMissing(nextMissingModules, newlyMissing); + } if (! _.isEmpty(nextMissingModules)) { - handleMissing(nextMissingModules); + await handleMissing(nextMissingModules); } } - handleMissing(allMissingModules); + await handleMissing(allMissingModules); Object.keys(allRelocatedModules).forEach(id => { delete allMissingModules[id]; @@ -1651,7 +1675,7 @@ export class PackageSourceBatch { // that end up in the program for this package. By this point, it knows what // its dependencies are and what their exports are, so it can set up // linker-style imports and exports. - getResources(jsResources, onCacheKey) { + async getResources(jsResources, onCacheKey) { buildmessage.assertInJob(); const resources = []; @@ -1660,12 +1684,12 @@ export class PackageSourceBatch { resources.push(...slot.outputResources); }); - resources.push(...this._linkJS(jsResources, onCacheKey)); + resources.push(...await this._linkJS(jsResources, onCacheKey)); return resources; } - _linkJS(jsResources, onCacheKey = () => {}) { + async _linkJS(jsResources, onCacheKey = () => {}) { const self = this; buildmessage.assertInJob(); @@ -1690,31 +1714,34 @@ export class PackageSourceBatch { imports: self.importedSymbolToPackageName, // XXX report an error if there is a package called global-imports includeSourceMapInstructions: isWeb, + deps: self.deps }; const fileHashes = []; const cacheKeyPrefix = sha1(JSON.stringify({ linkerOptions, - files: jsResources.map((inputFile) => { - fileHashes.push(inputFile.hash); - return { - meteorInstallOptions: inputFile.meteorInstallOptions, - absModuleId: inputFile.absModuleId, - sourceMap: !! inputFile.sourceMap, - mainModule: inputFile.mainModule, - imported: inputFile.imported, - alias: inputFile.alias, - lazy: inputFile.lazy, - bare: inputFile.bare, - }; - }) + files: await Promise.all( + jsResources.map(async (inputFile) => { + fileHashes.push(await inputFile.hash); + return { + meteorInstallOptions: inputFile.meteorInstallOptions, + absModuleId: inputFile.absModuleId, + sourceMap: !!(await inputFile.sourceMap), + mainModule: inputFile.mainModule, + imported: inputFile.imported, + alias: inputFile.alias, + lazy: inputFile.lazy, + bare: inputFile.bare, + }; + }) + ) })); const cacheKeySuffix = sha1(JSON.stringify({ LINKER_CACHE_SALT, fileHashes })); const cacheKey = `${cacheKeyPrefix}_${cacheKeySuffix}`; - onCacheKey(cacheKey, jsResources); + await onCacheKey(cacheKey, jsResources); if (LINKER_CACHE.has(cacheKey)) { if (CACHE_DEBUG) { @@ -1770,8 +1797,8 @@ export class PackageSourceBatch { // mutate anything from it. let canCache = true; let linkedFiles = null; - buildmessage.enterJob('linking', () => { - linkedFiles = linker.fullLink(jsResources, linkerOptions); + await buildmessage.enterJob('linking', async () => { + linkedFiles = await linker.fullLink(jsResources, linkerOptions); if (buildmessage.jobHasMessages()) { canCache = false; } @@ -1804,13 +1831,11 @@ export class PackageSourceBatch { LINKER_CACHE.set(cacheKey, ret); if (cacheFilename) { // Write asynchronously. - Promise.resolve().then(() => { - try { - files.rm_recursive(wildcardCacheFilename); - } finally { - files.writeFileAtomically(cacheFilename, retAsJSON); - } - }); + try { + await files.rm_recursive_deferred(wildcardCacheFilename); + } finally { + await files.writeFileAtomically(cacheFilename, retAsJSON); + } } } diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index d9793d8037..8e03f3d8ca 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -25,7 +25,7 @@ var compiler = exports; // this version number. The idea is that the "format" field of the isopack // JSON file only changes when the actual specified structure of the // isopack/unibuild changes, but this version (which is build-tool-specific) -// can change when the the contents (not structure) of the built output +// can change when the contents (not structure) of the built output // changes. So eg, if we improve the linker's static analysis, this should be // bumped. // @@ -47,7 +47,7 @@ compiler.ALL_ARCHES = [ compiler.compile = Profile(function (packageSource, options) { return `compiler.compile(${ packageSource.name || 'the app' })`; -}, function (packageSource, options) { +}, async function (packageSource, options) { buildmessage.assertInCapture(); var packageMap = options.packageMap; @@ -59,14 +59,14 @@ compiler.compile = Profile(function (packageSource, options) { var pluginProviderPackageNames = {}; - // Build plugins - _.each(packageSource.pluginInfo, function (info) { - buildmessage.enterJob({ + for (const info of Object.values(packageSource.pluginInfo)) { + // build plugins + await buildmessage.enterJob({ title: "building plugin `" + info.name + - "` in package `" + packageSource.name + "`", + "` in package `" + packageSource.name + "`", rootPath: packageSource.sourceRoot - }, function () { - var buildResult = buildJsImage({ + }, async function () { + var buildResult = await buildJsImage({ name: info.name, packageMap: packageMap, isopackCache: isopackCache, @@ -81,8 +81,8 @@ compiler.compile = Profile(function (packageSource, options) { // rest of the package, so they need their own separate npm // shrinkwrap and cache state. npmDir: files.pathResolve(files.pathJoin( - packageSource.sourceRoot, - '.npm', 'plugin', colonConverter.convert(info.name) + packageSource.sourceRoot, + '.npm', 'plugin', colonConverter.convert(info.name) )) }); // Add this plugin's dependencies to our "plugin dependency" @@ -109,7 +109,7 @@ compiler.compile = Profile(function (packageSource, options) { } plugins[info.name][buildResult.image.arch] = buildResult.image; }); - }); + } // Grab any npm dependencies. Keep them in a cache in the package // source directory so we don't have to do this from scratch on @@ -125,7 +125,7 @@ compiler.compile = Profile(function (packageSource, options) { // need to delete dependencies we used to have. var nodeModulesPath = null; if (packageSource.npmCacheDirectory) { - if (meteorNpm.updateDependencies(packageSource.name, + if (await meteorNpm.updateDependencies(packageSource.name, packageSource.npmCacheDirectory, packageSource.npmDependencies)) { nodeModulesPath = files.pathJoin( @@ -150,6 +150,7 @@ compiler.compile = Profile(function (packageSource, options) { // Isopack#initFromPath). var isobuildFeatures = []; packageSource.architectures.forEach((sourceArch) => { + if (global.includedWebArchs != null && ![...global.includedWebArchs, 'os'].includes(sourceArch.arch)) return; sourceArch.uses.forEach((use) => { if (!use.weak && isIsobuildFeaturePackage(use.package) && isobuildFeatures.indexOf(use.package) === -1) { @@ -159,7 +160,7 @@ compiler.compile = Profile(function (packageSource, options) { }); isobuildFeatures = _.uniq(isobuildFeatures); - var isopk = new isopack.Isopack; + var isopk = new isopack.Isopack(); isopk.initFromOptions({ name: packageSource.name, metadata: packageSource.metadata, @@ -177,13 +178,15 @@ compiler.compile = Profile(function (packageSource, options) { isobuildFeatures }); - _.each(packageSource.architectures, function (architecture) { + for (const architecture of packageSource.architectures) { if (architecture.arch === 'web.cordova' && ! includeCordovaUnibuild) { - return; + continue; } + if (global.includedWebArchs != null && ![...global.includedWebArchs, 'os'].includes(architecture.arch)) continue; - files.withCache(() => { - var unibuildResult = compileUnibuild({ + // TODO -> Maybe this withCache will bring some problems in other commands. + await files.withCache(async () => { + var unibuildResult = await compileUnibuild({ isopack: isopk, sourceArch: architecture, isopackCache: isopackCache, @@ -191,9 +194,9 @@ compiler.compile = Profile(function (packageSource, options) { }); Object.assign(pluginProviderPackageNames, - unibuildResult.pluginProviderPackageNames); + unibuildResult.pluginProviderPackageNames); }); - }); + } if (options.includePluginProviderPackageMap) { isopk.setPluginProviderPackageMap( @@ -209,23 +212,25 @@ compiler.compile = Profile(function (packageSource, options) { // - includeCordovaUnibuild compiler.lint = Profile(function (packageSource, options) { return `compiler.lint(${ packageSource.name || 'the app' })`; -}, function (packageSource, options) { +}, async function (packageSource, options) { // Note: the buildmessage context of compiler.lint and lintUnibuild is a // normal error message context (eg, there might be errors from initializing // plugins in getLinterSourceProcessorSet). We return the linter warnings as // our return value. buildmessage.assertInJob(); - const warnings = new buildmessage._MessageSet; + const warnings = new buildmessage._MessageSet(); let linted = false; - _.each(packageSource.architectures, function (architecture) { + + for (const architecture of packageSource.architectures) { // skip Cordova if not required if (! options.includeCordovaUnibuild && architecture.arch === 'web.cordova') { - return; + continue; } + if (global.includedWebArchs != null && ![...global.includedWebArchs, 'os'].includes(architecture.arch)) continue; - const unibuildWarnings = lintUnibuild({ + const unibuildWarnings = await lintUnibuild({ isopack: options.isopack, isopackCache: options.isopackCache, sourceArch: architecture @@ -234,28 +239,31 @@ compiler.lint = Profile(function (packageSource, options) { linted = true; warnings.merge(unibuildWarnings); } - }); + } + return {warnings, linted}; }); -compiler.getMinifiers = function (packageSource, options) { +compiler.getMinifiers = async function (packageSource, options) { buildmessage.assertInJob(); var minifiers = []; - _.each(packageSource.architectures, function (architecture) { - var activePluginPackages = getActivePluginPackages(options.isopack, { + for (const architecture of packageSource.architectures) { + if (global.includedWebArchs != null && ![...global.includedWebArchs, 'os'].includes(architecture.arch)) continue; + + var activePluginPackages = await getActivePluginPackages(options.isopack, { isopackCache: options.isopackCache, uses: architecture.uses }); - _.each(activePluginPackages, function (otherPkg) { - otherPkg.ensurePluginsInitialized(); + for (const otherPkg of activePluginPackages) { + await otherPkg.ensurePluginsInitialized(); _.each(otherPkg.sourceProcessors.minifier.allSourceProcessors, (sp) => { minifiers.push(sp); }); - }); - }); + } + } minifiers = _.uniq(minifiers); // check for extension-wise uniqness @@ -273,36 +281,36 @@ compiler.getMinifiers = function (packageSource, options) { return minifiers; }; -function getLinterSourceProcessorSet({isopack, activePluginPackages}) { +async function getLinterSourceProcessorSet({isopack, activePluginPackages}) { buildmessage.assertInJob(); const sourceProcessorSet = new SourceProcessorSet( isopack.displayName, { allowConflicts: true }); - _.each(activePluginPackages, function (otherPkg) { - otherPkg.ensurePluginsInitialized(); + for (const otherPkg of Object.values(activePluginPackages)) { + await otherPkg.ensurePluginsInitialized(); sourceProcessorSet.merge(otherPkg.sourceProcessors.linter); - }); + } return sourceProcessorSet; } -var lintUnibuild = function ({isopack, isopackCache, sourceArch}) { +var lintUnibuild = async function ({isopack, isopackCache, sourceArch}) { // Note: the buildmessage context of compiler.lint and lintUnibuild is a // normal error message context (eg, there might be errors from initializing // plugins in getLinterSourceProcessorSet). We return the linter warnings as // our return value. buildmessage.assertInJob(); - var activePluginPackages = getActivePluginPackages( + var activePluginPackages = await getActivePluginPackages( isopack, { isopackCache, uses: sourceArch.uses }); const sourceProcessorSet = - getLinterSourceProcessorSet({isopack, activePluginPackages}); + await getLinterSourceProcessorSet({isopack, activePluginPackages}); // bail out early if we had trouble loading plugins or if we're not // going to lint anything if (buildmessage.jobHasMessages() || sourceProcessorSet.isEmpty()) { @@ -320,8 +328,8 @@ var lintUnibuild = function ({isopack, isopackCache, sourceArch}) { const {sources} = sourceArch.getFiles(sourceProcessorSet, unibuild.watchSet); - const linterMessages = buildmessage.capture(() => { - runLinters({ + const linterMessages = await buildmessage.capture(() => { + return runLinters({ isopackCache, sources, sourceProcessorSet, @@ -339,7 +347,7 @@ var lintUnibuild = function ({isopack, isopackCache, sourceArch}) { // Returns a list of source files that were used in the compilation. var compileUnibuild = Profile(function (options) { return `compileUnibuild (${options.isopack.name || 'the app'})`; -}, function (options) { +}, async function (options) { buildmessage.assertInCapture(); const isopk = options.isopack; @@ -352,7 +360,7 @@ var compileUnibuild = Profile(function (options) { const watchSet = inputSourceArch.watchSet.clone(); // *** Determine and load active plugins - const activePluginPackages = getActivePluginPackages(isopk, { + const activePluginPackages = await getActivePluginPackages(isopk, { uses: inputSourceArch.uses, isopackCache: isopackCache, // If other package is built from source, then we need to rebuild this @@ -373,22 +381,23 @@ var compileUnibuild = Profile(function (options) { // handled by anything (which is an error unless explicitly declared // as a static asset). let sourceProcessorSet, linterSourceProcessorSet; - buildmessage.enterJob("determining active plugins", () => { + await buildmessage.enterJob("determining active plugins", async () => { sourceProcessorSet = new SourceProcessorSet( isopk.displayName(), { hardcodeJs: true}); - activePluginPackages.forEach((otherPkg) => { - otherPkg.ensurePluginsInitialized(); + for (const otherPkg of activePluginPackages) { + await otherPkg.ensurePluginsInitialized(); // Note that this may log a buildmessage if there are conflicts. sourceProcessorSet.merge(otherPkg.sourceProcessors.compiler); - }); + } // Used to excuse functions from the "undeclared static asset" check. - linterSourceProcessorSet = getLinterSourceProcessorSet({ + linterSourceProcessorSet = await getLinterSourceProcessorSet({ activePluginPackages, isopack: isopk }); + if (buildmessage.jobHasMessages()) { // Recover by not calling getFiles and pretending there are no // items. @@ -487,7 +496,7 @@ var compileUnibuild = Profile(function (options) { }); // Add and compile all source files - _.values(sources).forEach((source) => { + for (const source of sources) { const relPath = source.relPath; const fileOptions = _.clone(source.fileOptions) || {}; const absPath = files.pathResolve(inputSourceArch.sourceRoot, relPath); @@ -496,14 +505,14 @@ var compileUnibuild = Profile(function (options) { // Find the handler for source files with this extension let classification = null; classification = sourceProcessorSet.classifyFilename( - filename, inputSourceArch.arch); + filename, inputSourceArch.arch); if (classification.type === 'wrong-arch') { // This file is for a compiler plugin but not for this arch. Skip it, // and don't even watch it. (eg, skip CSS preprocessor files on the // server.) This `return` skips this source file and goes on to the next // one. - return; + continue; } if (classification.type === 'unmatched') { @@ -535,23 +544,23 @@ var compileUnibuild = Profile(function (options) { // removed while the Tool is running. Given that this is not a // common occurrence however, we'll ignore this situation and let the // Tool rebuild continue. - return; + continue; } const linterClassification = linterSourceProcessorSet.classifyFilename( - filename, inputSourceArch.arch); + filename, inputSourceArch.arch); if (linterClassification.type !== 'unmatched') { // The linter knows about this, so we'll just ignore it instead of // throwing an error. - return; + continue; } buildmessage.error( - `No plugin known to handle file '${ relPath }'. If you want this \ + `No plugin known to handle file '${ relPath }'. If you want this \ file to be a static asset, use addAssets instead of addFiles; eg, \ api.addAssets('${relPath}', 'client').`); // recover by ignoring - return; + continue; } const contents = optimisticReadFile(absPath); @@ -565,14 +574,13 @@ api.addAssets('${relPath}', 'client').`); } else { watchSet.addFile(absPath, hash); } - - Console.nudge(true); + await Console.yield(); if (classification.type === "meteor-ignore") { // Return after watching .meteorignore files but before adding them // as resources to be processed by compiler plugins. To see how // these files are handled, see PackageSource#_findSources. - return; + continue; } if (contents === null) { @@ -583,15 +591,15 @@ api.addAssets('${relPath}', 'client').`); // more. if (source.relPath.match(/:/)) { buildmessage.error( - "Couldn't build this package on Windows due to the following file " + - "with a colon -- " + source.relPath + ". Please rename and " + - "and re-publish the package."); + "Couldn't build this package on Windows due to the following file " + + "with a colon -- " + source.relPath + ". Please rename and " + + "and re-publish the package."); } else { buildmessage.error("File not found: " + source.relPath); } // recover by ignoring (but still watching the file) - return; + continue; } if (classification.isNonLegacySource()) { @@ -605,7 +613,7 @@ api.addAssets('${relPath}', 'client').`); hash, fileOptions })); - return; + continue; } if (classification.type !== 'legacy-handler') { @@ -614,16 +622,16 @@ api.addAssets('${relPath}', 'client').`); // OK, time to handle legacy handlers. var compileStep = compileStepModule.makeCompileStep( - source, file, inputSourceArch, { - resources: resources, - addAsset: addAsset - }); + source, file, inputSourceArch, { + resources: resources, + addAsset: addAsset + }); const handler = buildmessage.markBoundary(classification.legacyHandler); try { - Profile.time(`legacy handler (.${classification.extension})`, () => { - handler(compileStep); + await Profile.time(`legacy handler (.${classification.extension})`, () => { + return handler(compileStep); }); } catch (e) { e.message = e.message + " (compiling " + relPath + ")"; @@ -632,7 +640,7 @@ api.addAssets('${relPath}', 'client').`); // Recover by ignoring this source file (as best we can -- the // handler might already have emitted resources) } - }); + } // *** Determine captured variables var declaredExports = _.map(inputSourceArch.declaredExports, function (symbol) { @@ -651,16 +659,16 @@ api.addAssets('${relPath}', 'client').`); if (! process.env.METEOR_FORCE_PORTABLE) { // Make sure we've rebuilt these npm packages according to the current // process.{platform,arch,versions}. - _.each(nodeModulesDirectories, nmd => { + for (const nmd of Object.values(nodeModulesDirectories)) { if (nmd.local) { // Meteor never attempts to modify the contents of local // node_modules directories (such as the one in the root directory // of an application), so we call nmd.rebuildIfNonPortable() only // when nmd.local is false. } else { - nmd.rebuildIfNonPortable(); + await nmd.rebuildIfNonPortable(); } - }); + } if (process.env.METEOR_ALLOW_NON_PORTABLE || isopk.name === "meteor-tool") { @@ -698,7 +706,7 @@ api.addAssets('${relPath}', 'client').`); }; }); -function runLinters({inputSourceArch, isopackCache, sources, +async function runLinters({inputSourceArch, isopackCache, sources, sourceProcessorSet, watchSet}) { // The buildmessage context here is for linter warnings only! runLinters // should not do anything that can have a real build failure. @@ -740,7 +748,7 @@ function runLinters({inputSourceArch, isopackCache, sources, globalImports.push('Npm', 'Assets'); } - compiler.eachUsedUnibuild({ + await compiler.eachUsedUnibuild({ dependencies: inputSourceArch.uses, arch: whichArch, isopackCache: isopackCache, @@ -788,8 +796,9 @@ function runLinters({inputSourceArch, isopackCache, sources, const absPath = files.pathResolve(inputSourceArch.sourceRoot, relPath); const hash = optimisticHashOrNull(absPath); - const contents = optimisticReadFile(absPath); - watchSet.addFile(absPath, hash); + if (!watchSet.hasFile(absPath)) { + watchSet.addFile(absPath, hash); + } if (classification.type === "meteor-ignore") { // Return after watching .meteorignore files but before adding them @@ -798,6 +807,7 @@ function runLinters({inputSourceArch, isopackCache, sources, return; } + const contents = optimisticReadFile(absPath); const wrappedSource = { relPath, contents, hash, fileOptions, arch: inputSourceArch.arch, @@ -817,14 +827,14 @@ function runLinters({inputSourceArch, isopackCache, sources, }); // Run linters on files. This skips linters that don't have any files. - _.each(sourceItemsForLinter, ({sourceProcessor, sources}) => { + for (const {sourceProcessor, sources} of Object.values(sourceItemsForLinter)) { const sourcesToLint = sources.map( - wrappedSource => new linterPluginModule.LintingFile(wrappedSource) + wrappedSource => new linterPluginModule.LintingFile(wrappedSource) ); const markedLinter = buildmessage.markBoundary( - sourceProcessor.userPlugin.processFilesForPackage, - sourceProcessor.userPlugin + sourceProcessor.userPlugin.processFilesForPackage, + sourceProcessor.userPlugin ); function archToString(arch) { @@ -840,27 +850,27 @@ function runLinters({inputSourceArch, isopackCache, sources, throw new Error("Don't know how to display the arch: " + arch); } - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "linting files with " + - sourceProcessor.isopack.name + - " for " + - inputSourceArch.pkg.displayName() + - " (" + archToString(inputSourceArch.arch) + ")" - }, () => { + sourceProcessor.isopack.name + + " for " + + inputSourceArch.pkg.displayName() + + " (" + archToString(inputSourceArch.arch) + ")" + }, async () => { try { - Promise.await(markedLinter(sourcesToLint, { + await markedLinter(sourcesToLint, { globals: globalImports - })); + }); } catch (e) { buildmessage.exception(e); } }); - }); + } }; // takes an isopack and returns a list of packages isopack depends on, // containing at least one plugin -export function getActivePluginPackages(isopk, { +export async function getActivePluginPackages(isopk, { uses, isopackCache, pluginProviderPackageNames, @@ -892,7 +902,7 @@ export function getActivePluginPackages(isopk, { // // We pass archinfo.host here, not self.arch, because it may be more specific, // and because plugins always have to run on the host architecture. - compiler.eachUsedUnibuild({ + await compiler.eachUsedUnibuild({ dependencies: uses, arch: archinfo.host(), isopackCache: isopackCache, @@ -923,7 +933,7 @@ export function getActivePluginPackages(isopk, { // options.isopackCache. // // Skips isobuild:* pseudo-packages. -compiler.eachUsedUnibuild = function ( +compiler.eachUsedUnibuild = async function ( options, callback) { buildmessage.assertInCapture(); var dependencies = options.dependencies; @@ -980,7 +990,7 @@ compiler.eachUsedUnibuild = function ( } processedUnibuildId[unibuild.id] = true; - callback(unibuild, { + await callback(unibuild, { unordered: !!use.unordered, weak: !!use.weak }); diff --git a/tools/isobuild/fiber-stubs.js b/tools/isobuild/fiber-stubs.js new file mode 100644 index 0000000000..abc074a4e9 --- /dev/null +++ b/tools/isobuild/fiber-stubs.js @@ -0,0 +1,19 @@ +function unsupported () { + throw new Error('Fibers are not supported'); +} + +export const Fiber = function Fiber () { + throw new Error('Fibers are not supported'); +}; + +Fiber.yield = unsupported; +Fiber.current = undefined; + +export const Future = function () { + throw new Error('fibers/future is not supported'); +}; + +Future.wrap = unsupported; +Future.task = unsupported; +Future.wait = unsupported; +Future.fromPromise = unsupported; diff --git a/tools/isobuild/import-scanner.ts b/tools/isobuild/import-scanner.ts index b45767b7b9..7aff1ee0e6 100644 --- a/tools/isobuild/import-scanner.ts +++ b/tools/isobuild/import-scanner.ts @@ -45,9 +45,11 @@ import { import { wrap } from "optimism"; const { compile: reifyCompile } = require("@meteorjs/reify/lib/compiler"); +const { parse: reifyAcornParse } = require("@meteorjs/reify/lib/parsers/acorn"); const { parse: reifyBabelParse } = require("@meteorjs/reify/lib/parsers/babel"); import Resolver, { Resolution } from "./resolver"; +import LRUCache from 'lru-cache'; const fakeFileStat = { isFile() { @@ -86,18 +88,36 @@ const reifyCompileWithCache = Profile("reifyCompileWithCache", wrap(function ( } const isLegacy = isLegacyArch(bundleArch); - let result = reifyCompile(stripHashBang(source), { - parse: reifyBabelParse, + const reifyOptions = { generateLetDeclarations: !isLegacy, avoidModernSyntax: isLegacy, enforceStrictMode: false, dynamicImport: true, ast: false, - }).code; + }; + + let result; + try { + // First attempt: use Acorn + result = reifyCompile(stripHashBang(source), { + ...reifyOptions, + parse: reifyAcornParse, + }).code; + } catch (acornError) { + // Fallback: use Babel parser + // acorn may throw SyntaxError due to the lack of support for + // some features, but babel should still be able to parse the file + // For example, acorn don’t support JSX, only with acorn-jsx, + // but it isn’t included in Reify. + result = reifyCompile(stripHashBang(source), { + ...reifyOptions, + parse: reifyBabelParse, + }).code; + } if (cacheFilePath) { Promise.resolve().then( - () => writeFileAtomically(cacheFilePath, result), + async () => await writeFileAtomically(cacheFilePath, result), ); } @@ -132,11 +152,11 @@ class DefaultHandlers { call( method: "js" | "mjs" | "json" | "css", file: RawFile, - ): string { + ): string | Promise { return this[method](file); } - js(file: RawFile) { + async js(file: RawFile) { const parts = file.absPath.split("/"); const nmi = parts.lastIndexOf("node_modules"); if (nmi >= 0) { @@ -156,7 +176,7 @@ class DefaultHandlers { return reifyCompileWithCache( file.dataString, - file.hash, + await file.hash, this.bundleArch, cacheFileName ) @@ -289,8 +309,8 @@ function setImportedStatus(file: File, status: string | boolean) { // The cache can be global because findImportedModuleIdentifiers // is a pure function, and that way it applies across instances // of ImportScanner (which do not persist across builds). -const LRU = require("lru-cache"); -const IMPORT_SCANNER_CACHE = new LRU({ + +const IMPORT_SCANNER_CACHE = new LRUCache({ max: Math.pow(2, 23), length(ids: Record) { let total = 40; // size of key @@ -347,7 +367,7 @@ interface File extends RawFile { implicit?: boolean; imported: string | boolean; [fakeSymbol]?: boolean; - reportPendingErrors?: () => number; + reportPendingErrors?: () => Promise; hasErrors?: boolean; missingModules?: Record; alias?: FileAlias; @@ -474,9 +494,9 @@ export default class ImportScanner { return null; } - addInputFiles(files: File[]) { - files.forEach(file => { - this.checkSourceAndTargetPaths(file); + async addInputFiles(files: File[]) { + for (const file of files) { + await this.checkSourceAndTargetPaths(file); // Note: this absolute path may not necessarily exist on the file // system, but any import statements or require calls in file.data @@ -489,16 +509,16 @@ export default class ImportScanner { file.imported = false; file.absModuleId = file.absModuleId || - this.getAbsModuleId(file.absPath); + this.getAbsModuleId(file.absPath); if (! this.addFile(file.absPath, file)) { // Collisions can happen if a compiler plugin calls addJavaScript // multiple times with the same sourcePath. #6422 - this.combineFiles(this.getFile(file.absPath)!, file); + await this.combineFiles(this.getFile(file.absPath)!, file); } this.addFileByRealPath(file, this.realPath(file.absPath)); - }); + } return this; } @@ -517,16 +537,16 @@ export default class ImportScanner { return file; } - private getInfoByRealPath(realPath: string): RawFile | null { + private async getInfoByRealPath(realPath: string): Promise { const files = this.realPathToFiles[realPath]; if (files && files.length > 0) { const firstFile = files[0]; - const dataString = this.getDataString(firstFile); + const dataString = await this.getDataString(firstFile); return { absPath: realPath, - data: firstFile.data, + data: await firstFile.data, dataString: dataString, - hash: firstFile.hash, + hash: await firstFile.hash, }; } return null; @@ -578,7 +598,7 @@ export default class ImportScanner { // Make sure file.sourcePath is defined, and handle the possibility that // file.targetPath differs from file.sourcePath. - private checkSourceAndTargetPaths(file: File) { + private async checkSourceAndTargetPaths(file: File) { file.sourcePath = this.getSourcePath(file); if (! isString(file.targetPath)) { @@ -647,13 +667,13 @@ export default class ImportScanner { // plugin calling inputFile.addJavaScript multiple times for the // same source file (see discussion in #9176), with different target // paths, code, laziness, etc. - sourceFile.dataString = this.getDataString(sourceFile) + + sourceFile.dataString = await this.getDataString(sourceFile) + // The + in "*+" indicates that the "default" property should be // included as well as any other re-exported properties. "module.link(" + JSON.stringify(relativeId) + ', { "*": "*+" });\n'; sourceFile.data = Buffer.from(sourceFile.dataString, "utf8"); - sourceFile.hash = sha1(sourceFile.data); + sourceFile.hash = sha1(await sourceFile.data); sourceFile.deps = sourceFile.deps || Object.create(null); sourceFile.deps![relativeId] = { dynamic: false, @@ -666,7 +686,7 @@ export default class ImportScanner { // Concatenate the contents of oldFile and newFile, combining source // maps and updating all other properties appropriately. Once this // combination is done, oldFile should be kept and newFile discarded. - private combineFiles(oldFile: File, newFile: File) { + private async combineFiles(oldFile: File, newFile: File) { const scanner = this; function checkProperty(name: "lazy" | "bare") { @@ -697,17 +717,17 @@ export default class ImportScanner { checkProperty("lazy"); checkProperty("bare"); - function getChunk(file: File) { + async function getChunk(file: File) { if (file.sourceMap) { - const consumer = Promise.await(new SourceMapConsumer(file.sourceMap)); + const consumer = await new SourceMapConsumer(file.sourceMap); const node = SourceNode.fromStringWithSourceMap( - scanner.getDataString(file), + await scanner.getDataString(file), consumer ); consumer.destroy(); return node; } else { - return scanner.getDataString(file); + return await scanner.getDataString(file); } } @@ -715,16 +735,16 @@ export default class ImportScanner { code: combinedDataString, map: combinedSourceMap, } = new SourceNode(null, null, null, [ - getChunk(oldFile), + await getChunk(oldFile), "\n\n", - getChunk(newFile) + await getChunk(newFile) ]).toStringWithSourceMap({ file: oldFile.servePath || newFile.servePath }); oldFile.dataString = combinedDataString; oldFile.data = Buffer.from(oldFile.dataString, "utf8"); - oldFile.hash = sha1(oldFile.data); + oldFile.hash = sha1(await oldFile.data); alignImportedStatuses(oldFile, newFile); @@ -734,17 +754,17 @@ export default class ImportScanner { } } - scanImports() { - this.outputFiles.forEach(file => { - if (! file.lazy) { - this.scanFile(file); + async scanImports() { + for (const file of this.outputFiles) { + if (!file.lazy) { + await this.scanFile(file); } - }); + } return this; } - scanMissingModules(missingModules: MissingMap) { + async scanMissingModules(missingModules: MissingMap) { assert.ok(missingModules); assert.ok(typeof missingModules === "object"); assert.ok(! Array.isArray(missingModules)); @@ -756,7 +776,7 @@ export default class ImportScanner { const previousAllMissingModules = this.allMissingModules; this.allMissingModules = newlyMissing; - Object.keys(missingModules).forEach(id => { + for (const id of Object.keys(missingModules)) { let staticImportInfo: ImportInfo | null = null; let dynamicImportInfo: ImportInfo | null = null; @@ -791,7 +811,7 @@ export default class ImportScanner { } if (staticImportInfo) { - this.scanFile({ + await this.scanFile({ ...fakeStub, // By specifying the .deps property of this fake file ahead of // time, we can avoid calling findImportedModuleIdentifiers in @@ -802,12 +822,12 @@ export default class ImportScanner { } if (dynamicImportInfo) { - this.scanFile({ + await this.scanFile({ ...fakeStub, deps: { [id]: dynamicImportInfo }, }, true); // forDynamicImport } - }); + } this.allMissingModules = previousAllMissingModules; @@ -822,21 +842,21 @@ export default class ImportScanner { // Remove previously seen missing module identifiers from // newlyMissing and merge the new identifiers back into // this.allMissingModules. - Object.keys(newlyMissing).forEach(id => { + for (const id of Object.keys(newlyMissing)) { const skipScan = has(previousAllMissingModules, id) && - !isHigherStatus( - getParentStatus(newlyMissing[id]), - getParentStatus(previousAllMissingModules[id])); + !isHigherStatus( + getParentStatus(newlyMissing[id]), + getParentStatus(previousAllMissingModules[id])); if (skipScan) { delete newlyMissing[id]; } else { - ImportScanner.mergeMissing( - previousAllMissingModules, - { [id]: newlyMissing[id] } + await ImportScanner.mergeMissing( + previousAllMissingModules, + { [id]: newlyMissing[id] } ); } - }); + } } return { @@ -973,21 +993,22 @@ export default class ImportScanner { return pathNormalize(pathJoin(".", sourcePath)); } - private findImportedModuleIdentifiers( + private async findImportedModuleIdentifiers( file: File, - ): Record { - if (IMPORT_SCANNER_CACHE.has(file.hash)) { - return IMPORT_SCANNER_CACHE.get(file.hash); + ): Promise> { + const fileHash = file.hash instanceof Promise ? await file.hash : file.hash; + if (IMPORT_SCANNER_CACHE.has(fileHash)) { + return IMPORT_SCANNER_CACHE.get(fileHash) as Record; } const result = findImportedModuleIdentifiers( - this.getDataString(file), - file.hash, + await this.getDataString(file), + fileHash, ); // there should always be file.hash, but better safe than sorry - if (file.hash) { - IMPORT_SCANNER_CACHE.set(file.hash, result); + if (fileHash) { + IMPORT_SCANNER_CACHE.set(fileHash, result); } return result; @@ -1062,7 +1083,7 @@ export default class ImportScanner { return relativeId; } - private scanFile(file: File, forDynamicImport = false) { + private async scanFile(file: File, forDynamicImport = false) { if (file.imported === "static") { // If we've already scanned this file non-dynamically, then we don't // need to scan it again. @@ -1080,7 +1101,7 @@ export default class ImportScanner { setImportedStatus(file, forDynamicImport ? Status.DYNAMIC : Status.STATIC); if (file.reportPendingErrors && - file.reportPendingErrors() > 0) { + await file.reportPendingErrors() > 0) { file.hasErrors = true; // Any errors reported to InputFile#error were saved but not // reported at compilation time. Now that we know the file has been @@ -1089,7 +1110,7 @@ export default class ImportScanner { } try { - file.deps = file.deps || this.findImportedModuleIdentifiers(file); + file.deps = file.deps || await this.findImportedModuleIdentifiers(file); } catch (e: any) { if (e.$ParseError) { (buildmessage as any).error(e.message, { @@ -1102,19 +1123,19 @@ export default class ImportScanner { throw e; } - each(file.deps, (info: ImportInfo, id: string) => { + for (const [id, info] of Object.entries(file.deps)) { // Asynchronous module fetching only really makes sense in the // browser (even though it works equally well on the server), so // it's better if forDynamicImport never becomes true on the server. const dynamic = this.isWebBrowser() && - (forDynamicImport || - info.parentWasDynamic || - info.dynamic); + (forDynamicImport || + info.parentWasDynamic || + info.dynamic); const resolved = this.resolve(file, id, dynamic); const absImportedPath = resolved && resolved !== "missing" && resolved.path; if (! absImportedPath) { - return; + continue; } let depFile = this.getFile(absImportedPath); @@ -1139,22 +1160,22 @@ export default class ImportScanner { // If depFile has already been scanned, this._scanFile will return // immediately thanks to the depFile.imported-checking logic at // the top of the method. - this.scanFile(depFile, dynamic); + await this.scanFile(depFile, dynamic); - return; + continue; } - depFile = this.readDepFile(absImportedPath); + depFile = await this.readDepFile(absImportedPath); if (! depFile) { - return; + continue; } // Append this file to the output array and record its index. this.addFile(absImportedPath, depFile); // Recursively scan the module's imported dependencies. - this.scanFile(depFile, dynamic); - }); + await this.scanFile(depFile, dynamic); + } } isWeb() { @@ -1166,19 +1187,20 @@ export default class ImportScanner { return archMatches(this.bundleArch, "web.browser"); } - private getDataString(file: File) { - if (typeof file.dataString === "string") { - return file.dataString; + private async getDataString(file: File) { + const fileData = await file.data; + if (typeof fileData === "string") { + return fileData; } - const rawDataString = file.data.toString("utf8"); + const rawDataString = fileData.toString("utf8"); if (file.type === "js") { // Avoid compiling .js file with Reify when all we want is a string // version of file.data. file.dataString = stripHashBang(rawDataString); } else { file.dataString = rawDataString; - file.dataString = this.defaultHandlers.call(file.type as any, file); + file.dataString = await this.defaultHandlers.call(file.type as any, file); } if (! (file.data instanceof Buffer) || @@ -1239,7 +1261,7 @@ export default class ImportScanner { return info; } - private readModule(absPath: string): RawFile | null { + private async readModule(absPath: string): Promise { const dotExt = pathExtname(absPath).toLowerCase(); if (dotExt === ".node") { @@ -1273,7 +1295,7 @@ export default class ImportScanner { } } - info.dataString = this.defaultHandlers.call(ext as any, info); + info.dataString = await this.defaultHandlers.call(ext as any, info); if (info.dataString !== dataString) { info.data = Buffer.from(info.dataString, "utf8"); } @@ -1281,7 +1303,7 @@ export default class ImportScanner { return info; } - private readDepFile(absPath: string): File | null { + private async readDepFile(absPath: string): Promise { const absModuleId = this.getAbsModuleId(absPath); if (! absModuleId) { // The given path cannot be installed on this architecture. @@ -1290,7 +1312,7 @@ export default class ImportScanner { const realPath = this.realPath(absPath); - let rawFile = this.getInfoByRealPath(realPath); + let rawFile = await this.getInfoByRealPath(realPath); if (rawFile) { // If we already have a file with the same real path, use its data // rather than reading the file again, or generating a stub. This @@ -1317,7 +1339,7 @@ export default class ImportScanner { } else { rawFile = absModuleId.endsWith("/package.json") ? this.readPackageJson(absPath) - : this.readModule(absPath); + : await this.readModule(absPath); // If the module is not readable, _readModule may return null. // Otherwise it will return { data, dataString, hash }. diff --git a/tools/isobuild/isopack-cache.js b/tools/isobuild/isopack-cache.js index 371cd2f9cd..850db04166 100644 --- a/tools/isobuild/isopack-cache.js +++ b/tools/isobuild/isopack-cache.js @@ -56,7 +56,7 @@ export class IsopackCache { self.allLoadedLocalPackagesWatchSet = new watch.WatchSet; } - buildLocalPackages(rootPackageNames) { + async buildLocalPackages(rootPackageNames) { var self = this; buildmessage.assertInCapture(); @@ -66,36 +66,36 @@ export class IsopackCache { var onStack = {}; if (rootPackageNames) { - _.each(rootPackageNames, function (name) { - self._ensurePackageLoaded(name, onStack); - }); + for (const name of rootPackageNames) { + await self._ensurePackageLoaded(name, onStack); + } } else { - self._packageMap.eachPackage(function (name, packageInfo) { - self._ensurePackageLoaded(name, onStack); - requestGarbageCollection(); + await self._packageMap.eachPackage(async function (name) { + await self._ensurePackageLoaded(name, onStack); + await requestGarbageCollection(); }); } } - wipeCachedPackages(packages) { + async wipeCachedPackages(packages) { var self = this; if (packages) { // Wipe specific packages. - _.each(packages, function (packageName) { + for (const packageName of packages) { if (self.cacheDir) { - files.rm_recursive(self._isopackDir(packageName)); + await files.rm_recursive_deferred(self._isopackDir(packageName)); } if (self._pluginCacheDirRoot) { - files.rm_recursive(self._pluginCacheDirForPackage(packageName)); + await files.rm_recursive_deferred(self._pluginCacheDirForPackage(packageName)); } - }); + } } else { // Wipe all packages. if (self.cacheDir) { - files.rm_recursive(self.cacheDir); + await files.rm_recursive_deferred(self.cacheDir); } if (self._pluginCacheDirRoot) { - files.rm_recursive(self._pluginCacheDirRoot); + await files.rm_recursive_deferred(self._pluginCacheDirRoot); } } } @@ -112,11 +112,11 @@ export class IsopackCache { return self._isopacks[name]; } - eachBuiltIsopack(iterator) { + async eachBuiltIsopack(iterator) { var self = this; - _.each(self._isopacks, function (isopack, packageName) { - iterator(packageName, isopack); - }); + for (const [packageName, isopack] of Object.entries(self._isopacks)) { + await iterator(packageName, isopack) + } } getSourceRoot(name, arch) { @@ -155,13 +155,15 @@ export class IsopackCache { return false; } - return _.some(unibuild.uses, use => { - return this.implies( - this._isopacks[use.package], - name, - arch, + for (const use of unibuild.uses) { + const implies = this.implies( + this._isopacks[use.package], + name, + arch, ); - }); + + if (implies) return implies; + } } implies(isopack, name, arch) { @@ -179,23 +181,25 @@ export class IsopackCache { return false; } - return _.some(unibuild.implies, imp => { - return this.implies( - this._isopacks[imp.package], - name, - arch, + for (const imp of unibuild.implies) { + const implies = this.implies( + this._isopacks[imp.package], + name, + arch, ); - }); + + if (implies) return implies; + } } - _ensurePackageLoaded(name, onStack) { + async _ensurePackageLoaded(name, onStack) { var self = this; buildmessage.assertInCapture(); if (_.has(self._isopacks, name)) { return; } - var ensureLoaded = function (depName) { + var ensureLoaded = async function (depName) { if (_.has(onStack, depName)) { buildmessage.error("circular dependency between packages " + name + " and " + depName); @@ -203,7 +207,7 @@ export class IsopackCache { return; } onStack[depName] = true; - self._ensurePackageLoaded(depName, onStack); + await self._ensurePackageLoaded(depName, onStack); delete onStack[depName]; }; @@ -229,17 +233,17 @@ export class IsopackCache { if (packageInfo.kind === 'local') { var packageNames = packageInfo.packageSource.getPackagesToLoadFirst(self._packageMap); - buildmessage.enterJob("preparing to build package " + name, function () { - _.each(packageNames, function (depName) { - ensureLoaded(depName); - }); + await buildmessage.enterJob("preparing to build package " + name, async function () { + for (const depName of packageNames) { + await ensureLoaded(depName); + } // If we failed to load something that this package depends on, don't // load it. if (buildmessage.jobHasMessages()) { return; } - Profile.time('IsopackCache Build local isopack', () => { - self._loadLocalPackage(name, packageInfo, previousIsopack); + await Profile.time('IsopackCache Build local isopack', async () => { + await self._loadLocalPackage(name, packageInfo, previousIsopack); }); }); } else if (packageInfo.kind === 'versioned') { @@ -252,19 +256,19 @@ export class IsopackCache { var isopack = null, packagesToLoad = []; - Profile.time('IsopackCache Load local isopack', () => { + await Profile.time('IsopackCache Load local isopack', async () => { if (previousIsopack) { // We can always reuse a previous Isopack for a versioned package, since // we assume that it never changes. (Admittedly, this means we won't // notice if we download an additional build for the package.) isopack = previousIsopack; - packagesToLoad = isopack.getStrongOrderedUsedAndImpliedPackages(); + packagesToLoad = await isopack.getStrongOrderedUsedAndImpliedPackages(); } if (! isopack) { // Load the isopack from disk. - buildmessage.enterJob( + await buildmessage.enterJob( "loading package " + name + "@" + packageInfo.version, - function () { + async function () { var pluginCacheDir; if (self._pluginCacheDirRoot) { pluginCacheDir = self._pluginCacheDirForVersion( @@ -276,7 +280,7 @@ export class IsopackCache { var Isopack = isopackModule.Isopack; isopack = new Isopack(); - isopack.initFromPath(name, isopackPath, { + await isopack.initFromPath(name, isopackPath, { pluginCacheDir: pluginCacheDir }); // If loading the isopack fails, then we don't need to look for more @@ -285,7 +289,7 @@ export class IsopackCache { if (buildmessage.jobHasMessages()) { return; } - packagesToLoad = isopack.getStrongOrderedUsedAndImpliedPackages(); + packagesToLoad = await isopack.getStrongOrderedUsedAndImpliedPackages(); }); } }); @@ -294,20 +298,20 @@ export class IsopackCache { // Also load its dependencies. This is so that if this package is being // built as part of a plugin, all the transitive dependencies of the // plugin are loaded. - _.each(packagesToLoad, function (packageToLoad) { - ensureLoaded(packageToLoad); - }); + for (const packageToLoad of packagesToLoad) { + await ensureLoaded(packageToLoad); + } } else { throw Error("unknown packageInfo kind?"); } } - _loadLocalPackage(name, packageInfo, previousIsopack) { + async _loadLocalPackage(name, packageInfo, previousIsopack) { var self = this; buildmessage.assertInCapture(); - buildmessage.enterJob("building package " + name, function () { + await buildmessage.enterJob("building package " + name, async function () { var isopack; - if (previousIsopack && self._checkUpToDatePreloaded(previousIsopack)) { + if (previousIsopack && await self._checkUpToDatePreloaded(previousIsopack)) { isopack = previousIsopack; // We don't need to call self._lintLocalPackage here, because // lintingMessages is saved on the isopack. @@ -320,14 +324,14 @@ export class IsopackCache { // Do we have an up-to-date package on disk? var isopackBuildInfoJson = self.cacheDir && files.readJSONOrNull( self._isopackBuildInfoPath(name)); - var upToDate = self._checkUpToDate(isopackBuildInfoJson); + var upToDate = await self._checkUpToDate(isopackBuildInfoJson); if (upToDate) { // Reuse existing plugin cache dir pluginCacheDir && files.mkdir_p(pluginCacheDir); isopack = new isopackModule.Isopack(); - isopack.initFromPath(name, self._isopackDir(name), { + await isopack.initFromPath(name, self._isopackDir(name), { isopackBuildInfoJson: isopackBuildInfoJson, pluginCacheDir: pluginCacheDir }); @@ -343,14 +347,15 @@ export class IsopackCache { // Because we don't save linter messages to disk, we have to relint // this package. // XXX save linter messages to disk? - self._lintLocalPackage(packageInfo.packageSource, isopack); + await self._lintLocalPackage(packageInfo.packageSource, isopack); } else { // Nope! Compile it again. Give it a fresh plugin cache. if (pluginCacheDir) { - files.rm_recursive(pluginCacheDir); + await files.rm_recursive_deferred(pluginCacheDir); files.mkdir_p(pluginCacheDir); } - isopack = compiler.compile(packageInfo.packageSource, { + + isopack = await compiler.compile(packageInfo.packageSource, { packageMap: self._packageMap, isopackCache: self, includeCordovaUnibuild: self._includeCordovaUnibuild, @@ -364,10 +369,10 @@ export class IsopackCache { if (! buildmessage.jobHasMessages()) { // Lint the package. We do this before saving so that the linter can // augment the saved-to-disk WatchSet with linter-specific files. - self._lintLocalPackage(packageInfo.packageSource, isopack); + await self._lintLocalPackage(packageInfo.packageSource, isopack); if (self.cacheDir) { // Save to disk, for next time! - isopack.saveToPath(self._isopackDir(name), { + await isopack.saveToPath(self._isopackDir(name), { includeIsopackBuildInfo: true, isopackCache: self, }); @@ -385,12 +390,12 @@ export class IsopackCache { // Runs appropriate linters on a package. It also augments their unibuilds' // WatchSets with files used by the linter. - _lintLocalPackage(packageSource, isopack) { + async _lintLocalPackage(packageSource, isopack) { buildmessage.assertInJob(); if (!this._shouldLintPackage(packageSource)) { return; } - const {warnings, linted} = compiler.lint(packageSource, { + const {warnings, linted} = await compiler.lint(packageSource, { isopackCache: this, isopack: isopack, includeCordovaUnibuild: this._includeCordovaUnibuild @@ -508,11 +513,11 @@ export class IsopackCache { return this._lintPackageWithSourceRoot === packageSource.sourceRoot; } - getLintingMessagesForLocalPackages() { + async getLintingMessagesForLocalPackages() { const messages = new buildmessage._MessageSet(); let anyLinters = false; - this._packageMap.eachPackage((name, packageInfo) => { + await this._packageMap.eachPackage((name, packageInfo) => { const isopack = this._isopacks[name]; if (packageInfo.kind === 'local') { if (!this._shouldLintPackage(packageInfo.packageSource)) { diff --git a/tools/isobuild/isopack.js b/tools/isobuild/isopack.js index ceb439f9a9..aa397e0a80 100644 --- a/tools/isobuild/isopack.js +++ b/tools/isobuild/isopack.js @@ -1,3 +1,5 @@ +import { getMeteorConfig } from "../tool-env/meteor-config"; + var compiler = require('./compiler.js'); var archinfo = require('../utils/archinfo'); var _ = require('underscore'); @@ -435,7 +437,7 @@ Object.assign(Isopack.prototype, { // If this package has plugins, initialize them (run the startup // code in them so that they register their extensions). Idempotent. - ensurePluginsInitialized: Profile("Isopack#ensurePluginsInitialized", function () { + ensurePluginsInitialized: Profile("Isopack#ensurePluginsInitialized", async function () { var self = this; buildmessage.assertInJob(); @@ -451,31 +453,42 @@ Object.assign(Isopack.prototype, { self.sourceProcessors.minifier = new buildPluginModule.SourceProcessorSet( self.displayName(), { singlePackage: true }); - _.each(self.plugins, function (pluginsByArch, name) { + for (const [name, pluginsByArch] of Object.entries(self.plugins)) { var arch = archinfo.mostSpecificMatch( - archinfo.host(), Object.keys(pluginsByArch)); + archinfo.host(), Object.keys(pluginsByArch)); if (! arch) { buildmessage.error("package `" + name + "` is built for incompatible " + - "architecture"); + "architecture"); // Recover by ignoring plugin // XXX does this recovery work? - return; + continue; } var plugin = pluginsByArch[arch]; - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "loading plugin `" + name + - "` from package `" + self.name + "`" + "` from package `" + self.name + "`" // don't necessarily have rootPath anymore // (XXX we do, if the isopack was locally built, which is // the important case for debugging. it'd be nice to get this // case right.) - }, function () { + }, async function () { // Make a new Plugin API object for this plugin. - var Plugin = self._makePluginApi(name); - plugin.load({ Plugin: Plugin, Profile: Profile }); + const Plugin = self._makePluginApi(name); + const __meteor_bootstrap__ = { + isFibersDisabled: true, + // Set to null to tell Meteor.startup to call hooks immediately + // XXX: should we fully support startup hooks in build plugins? + startupHooks: null + }; + + await plugin.load({ + Plugin, + Profile, + __meteor_bootstrap__ + }); }); - }); + } // Instantiate each of the registered batch plugins. Note that we don't // do this directly in the registerCompiler (etc) call, because we want @@ -483,11 +496,11 @@ Object.assign(Isopack.prototype, { // Plugin.registerCompiler({...}, function () { return new C; }); // var C = function () {...} // and so we want to wait for C to be defined. - _.each(self.sourceProcessors, (sourceProcessorSet) => { - _.each(sourceProcessorSet.allSourceProcessors, (sourceProcessor) => { - sourceProcessor.instantiatePlugin(); - }); - }); + for (const sourceProcessorSet of Object.values(self.sourceProcessors)) { + for (const sourceProcessor of sourceProcessorSet.allSourceProcessors) { + await sourceProcessor.instantiatePlugin(); + } + } self._pluginsInitialized = true; }), @@ -503,6 +516,9 @@ Object.assign(Isopack.prototype, { var Plugin = { name: pluginName, + // Share the meteorConfig object as part of plugin API + getMeteorConfig: getMeteorConfig, + // 'extension' is a file extension without the separation dot // (eg 'js', 'coffee', 'coffee.md') // @@ -790,7 +806,10 @@ Object.assign(Isopack.prototype, { }, nudge: function () { - Console.nudge(true); + Console.nudge(); + }, + yield: function () { + return Console.yield(); }, convertToOSPath: files.convertToOSPath, @@ -816,7 +835,7 @@ Object.assign(Isopack.prototype, { // - isopackBuildInfoJson: parsed isopack-buildinfo.json object, // if loading from an IsopackCache. initFromPath: Profile( - "Isopack#initFromPath", function (name, dir, options) { + "Isopack#initFromPath", async function (name, dir, options) { var self = this; options = _.clone(options || {}); options.firstIsopack = true; @@ -825,10 +844,10 @@ Object.assign(Isopack.prototype, { self.pluginCacheDir = options.pluginCacheDir; } - return self._loadUnibuildsFromPath(name, dir, options); + await self._loadUnibuildsFromPath(name, dir, options); }), - _loadUnibuildsFromPath: function (name, dir, options) { + _loadUnibuildsFromPath: async function (name, dir, options) { var self = this; options = options || {}; @@ -838,7 +857,7 @@ Object.assign(Isopack.prototype, { // realpath'ing dir. dir = files.realpath(dir); - var {metadata: mainJson} = Isopack.readMetadataFromDirectory(dir); + var {metadata: mainJson} = await Isopack.readMetadataFromDirectory(dir); if (! mainJson) { throw new Error("No metadata files found for isopack at: " + dir); } @@ -891,10 +910,10 @@ Object.assign(Isopack.prototype, { self.prodOnly = !!mainJson.prodOnly; self.testOnly = !!mainJson.testOnly; } - _.each(mainJson.plugins, function (pluginMeta) { + for (const pluginMeta of mainJson.plugins) { rejectBadPath(pluginMeta.path); - var plugin = bundler.readJsImage(files.pathJoin(dir, pluginMeta.path)); + var plugin = await bundler.readJsImage(files.pathJoin(dir, pluginMeta.path)); if (!_.has(self.plugins, pluginMeta.name)) { self.plugins[pluginMeta.name] = {}; @@ -903,9 +922,9 @@ Object.assign(Isopack.prototype, { if (!_.has(self.plugins[pluginMeta.name], plugin.arch)) { self.plugins[pluginMeta.name][plugin.arch] = plugin; } - }); + } self.pluginsBuilt = true; - _.each(mainJson.builds, function (unibuildMeta) { + for (const unibuildMeta of mainJson.builds) { // aggressively sanitize path (don't let it escape to parent // directory) rejectBadPath(unibuildMeta.path); @@ -915,17 +934,17 @@ Object.assign(Isopack.prototype, { return unibuild.arch === unibuildMeta.arch; }); if (alreadyHaveUnibuild) { - return; + continue; } - const unibuild = Unibuild.fromJSON(JSON.parse( - files.readFile(files.pathJoin(dir, unibuildMeta.path)) + const unibuild = await Unibuild.fromJSON(JSON.parse( + files.readFile(files.pathJoin(dir, unibuildMeta.path)) ), { isopack: self, kind: unibuildMeta.kind, arch: unibuildMeta.arch, unibuildBasePath: files.pathDirname( - files.pathJoin(dir, unibuildMeta.path)), + files.pathJoin(dir, unibuildMeta.path)), watchSet: unibuildWatchSets[unibuildMeta.path], }); @@ -940,7 +959,7 @@ Object.assign(Isopack.prototype, { } self.unibuilds.push(unibuild); - }); + } self.cordovaDependencies = mainJson.cordovaDependencies || null; @@ -1009,7 +1028,10 @@ Object.assign(Isopack.prototype, { // of this flag is allow us to optimize cases that never need to write the // older format, such as the per-app isopack cache.) // - isopackCache: isopack cache in which this isopack is registered - saveToPath: Profile("Isopack#saveToPath", function (outputDir, { + /** + * @return {Promise} + */ + saveToPath: Profile("Isopack#saveToPath", async function (outputDir, { includePreCompilerPluginIsopackVersions, includeIsopackBuildInfo, isopackCache = null, @@ -1018,6 +1040,7 @@ Object.assign(Isopack.prototype, { var outputPath = outputDir; var builder = new Builder({ outputPath: outputPath }); + await builder.init(); try { var mainJson = { name: self.name, @@ -1088,7 +1111,7 @@ Object.assign(Isopack.prototype, { // to see if package.js exists instead of just looking for the package // directory.) // XXX Remove this once we can. - builder.write("package.js", { + await builder.write("package.js", { data: Buffer.from( ("// This file is included for compatibility with the Meteor " + "0.6.4 package downloader.\n"), @@ -1098,13 +1121,13 @@ Object.assign(Isopack.prototype, { var unibuildInfos = []; // Unibuilds - _.each(self.unibuilds, function (unibuild) { + for (const unibuild of self.unibuilds) { // Make up a filename for this unibuild var baseUnibuildName = unibuild.arch; var unibuildDir = - builder.generateFilename(baseUnibuildName, { directory: true }); + await builder.generateFilename(baseUnibuildName, { directory: true }); var unibuildJsonFile = - builder.generateFilename(baseUnibuildName + ".json"); + await builder.generateFilename(baseUnibuildName + ".json"); mainJson.builds.push({ kind: unibuild.kind, arch: unibuild.arch, @@ -1115,13 +1138,13 @@ Object.assign(Isopack.prototype, { // too hard about how to encode pair (name, arch). if (isopackBuildInfoJson) { isopackBuildInfoJson.unibuildDependencies[unibuildJsonFile] = - unibuild.watchSet.toJSON(); + unibuild.watchSet.toJSON(); } const usesModules = ! isopackCache || - isopackCache.uses(self, "modules", unibuild.arch); + isopackCache.uses(self, "modules", unibuild.arch); - const unibuildJson = unibuild.toJSON({ + const unibuildJson = await unibuild.toJSON({ builder, unibuildDir, usesModules, @@ -1132,59 +1155,59 @@ Object.assign(Isopack.prototype, { // original form of the resource object (with the source in a // Buffer, etc) instead of the later version. #HardcodeJs const jsResourcesForLegacyPrelink = - writeLegacyBuilds ? unibuild.getLegacyJsResources() : []; + writeLegacyBuilds ? unibuild.getLegacyJsResources() : []; // Control file for unibuild - builder.writeJson(unibuildJsonFile, unibuildJson); + await builder.writeJson(unibuildJsonFile, unibuildJson); unibuildInfos.push({ unibuild, unibuildJson, jsResourcesForLegacyPrelink, }); - }); + } // If unibuilds included node_modules, copy them in. - _.each(npmDirsToCopy, (bundlePath, sourcePath) => { - builder.copyNodeModulesDirectory({ + for (const [sourcePath, bundlePath] of Object.entries(npmDirsToCopy)) { + await builder.copyNodeModulesDirectory({ from: sourcePath, to: bundlePath, npmDiscards: self.npmDiscards, symlink: false }); - }); + } // Plugins - _.each(self.plugins, function (pluginsByArch, name) { - _.each(pluginsByArch, function (plugin) { + for (const [name, pluginsByArch] of Object.entries(self.plugins)) { + for (const plugin of Object.values(pluginsByArch)) { // XXX the name of the plugin doesn't typically contain a colon, but // escape it just in case. - var pluginDir = builder.generateFilename( - 'plugin.' + colonConverter.convert(name) + '.' + plugin.arch, - { directory: true }); - var pluginBuild = plugin.write(builder.enter(pluginDir)); + var pluginDir = await builder.generateFilename( + 'plugin.' + colonConverter.convert(name) + '.' + plugin.arch, + { directory: true }); + var pluginBuild = await plugin.write(await builder.enter(pluginDir)); var pluginEntry = { name: name, arch: plugin.arch, path: files.pathJoin(pluginDir, pluginBuild.controlFile) }; mainJson.plugins.push(pluginEntry); - }); - }); + } + } // Tools // First, are we supposed to include our own source as a tool? if (self.includeTool) { - var toolsJson = self._writeTool(builder); + var toolsJson = await self._writeTool(builder); mainJson.tools = toolsJson; } // Next, what about other tools we may be merging from other isopacks? // XXX check for overlap - _.each(self.toolsOnDisk, function (toolMeta) { + for (let toolMeta of self.toolsOnDisk) { toolMeta = _.clone(toolMeta); var rootDir = toolMeta.rootDir; delete toolMeta.rootDir; - builder.copyDirectory({ + await builder.copyDirectory({ from: files.pathJoin(rootDir, toolMeta.path), to: toolMeta.path, symlink: false @@ -1193,20 +1216,20 @@ Object.assign(Isopack.prototype, { mainJson.tools = []; } mainJson.tools.push(toolMeta); - }); + } var mainLegacyJson = null; if (writeLegacyBuilds) { mainLegacyJson = _.clone(mainJson); mainLegacyJson.builds = []; - _.each(unibuildInfos, function (unibuildInfo) { + for (const unibuildInfo of unibuildInfos) { var unibuild = unibuildInfo.unibuild; var unibuildJson = unibuildInfo.unibuildJson; var jsResourcesForLegacyPrelink = - unibuildInfo.jsResourcesForLegacyPrelink; - var legacyFilename = builder.generateFilename( - unibuild.arch + '-legacy.json'); + unibuildInfo.jsResourcesForLegacyPrelink; + var legacyFilename = await builder.generateFilename( + unibuild.arch + '-legacy.json'); var legacyDir = unibuild.arch + '-legacy'; mainLegacyJson.builds.push({ kind: unibuild.kind, @@ -1234,7 +1257,7 @@ Object.assign(Isopack.prototype, { // already, in the format that linker.prelink understands. } else { throw Error( - "shouldn't write legacy builds for non-JS/CSS source " + "shouldn't write legacy builds for non-JS/CSS source " + JSON.stringify(resource)); } }); @@ -1251,7 +1274,7 @@ Object.assign(Isopack.prototype, { // assignment differs from that below), ah well. prelinkData = prelinkFile.data; packageVariables = - jsResourcesForLegacyPrelink[0].legacyPrelink.packageVariables; + jsResourcesForLegacyPrelink[0].legacyPrelink.packageVariables; } else { // Determine captured variables, legacy way. First, start with the // exports. We'll add the package variables after running prelink. @@ -1270,21 +1293,21 @@ Object.assign(Isopack.prototype, { if (jsResourcesForLegacyPrelink.length) { // Not originally legacy; let's run prelink to make it legacy. - var results = linker.prelink({ + var results = await linker.prelink({ inputFiles: jsResourcesForLegacyPrelink, // I was confused about this, so I am leaving a comment -- the // combinedServePath is either [pkgname].js or [pluginName]:plugin.js. // XXX: If we change this, we can get rid of source arch names! combinedServePath: ( - "/packages/" + colonConverter.convert( - unibuild.pkg.name + - (unibuild.kind === "main" ? "" : (":" + unibuild.kind)) + - ".js")), + "/packages/" + colonConverter.convert( + unibuild.pkg.name + + (unibuild.kind === "main" ? "" : (":" + unibuild.kind)) + + ".js")), name: unibuild.pkg.name }); if (results.files.length !== 1) { throw Error("prelink should return 1 file, not " + - results.files.length); + results.files.length); } prelinkFile = results.files[0]; prelinkData = Buffer.from(prelinkFile.source, 'utf8'); @@ -1304,9 +1327,9 @@ Object.assign(Isopack.prototype, { if (prelinkFile && prelinkData) { var prelinkResource = { type: 'prelink', - file: builder.writeToGeneratedFilename( - files.pathJoin(legacyDir, prelinkFile.servePath), - { data: prelinkData }), + file: await builder.writeToGeneratedFilename( + files.pathJoin(legacyDir, prelinkFile.servePath), + { data: prelinkData }), length: prelinkData.length, offset: 0, servePath: prelinkFile.servePath || undefined @@ -1319,9 +1342,9 @@ Object.assign(Isopack.prototype, { // so here's some exhaustive checking of things buffer // _will_ accept. var acceptedByBuffer = _.isString(prelinkFile.sourceMap) - || _.isNumber(prelinkFile.sourceMap) - || _.isArray(prelinkFile.sourceMap) - || (prelinkFile.sourceMap instanceof Buffer); + || _.isNumber(prelinkFile.sourceMap) + || _.isArray(prelinkFile.sourceMap) + || (prelinkFile.sourceMap instanceof Buffer); if (!acceptedByBuffer) { prelinkFile.sourceMap = JSON.stringify(prelinkFile.sourceMap); } @@ -1331,9 +1354,9 @@ Object.assign(Isopack.prototype, { prelinkFile.sourceMap = JSON.stringify(prelinkFile.sourceMap); } - prelinkResource.sourceMap = builder.writeToGeneratedFilename( - files.pathJoin(legacyDir, prelinkFile.servePath + '.map'), - { data: Buffer.from(prelinkFile.sourceMap, 'utf8') } + prelinkResource.sourceMap = await builder.writeToGeneratedFilename( + files.pathJoin(legacyDir, prelinkFile.servePath + '.map'), + { data: Buffer.from(prelinkFile.sourceMap, 'utf8') } ); } newResources.push(prelinkResource); @@ -1345,13 +1368,13 @@ Object.assign(Isopack.prototype, { unibuildJson.resources = newResources; delete unibuildJson.declaredExports; - builder.writeJson(legacyFilename, unibuildJson); - }); + await builder.writeJson(legacyFilename, unibuildJson); + } // old unipackage.json format/filename. no point to save this if // we can't even support isopack-1. // XXX COMPAT WITH 0.9.3 - builder.writeJson( + await builder.writeJson( "unipackage.json", Isopack.convertIsopackFormat( // Note that mainLegacyJson is isopack-1 (has no "source" resources) @@ -1374,22 +1397,22 @@ Object.assign(Isopack.prototype, { // isopack-1: {... data ...}, // isopack-2: {... data ...} // } - builder.writeJson("isopack.json", isopackJson); + await builder.writeJson("isopack.json", isopackJson); if (isopackBuildInfoJson) { - builder.writeJson("isopack-buildinfo.json", isopackBuildInfoJson); + await builder.writeJson("isopack-buildinfo.json", isopackBuildInfoJson); } - builder.complete(); + await builder.complete(); } catch (e) { - builder.abort(); + await builder.abort(); throw e; } }), - _writeTool: Profile("Isopack#_writeTool", function (builder) { + _writeTool: Profile("Isopack#_writeTool", async function (builder) { var self = this; - var pathsToCopy = utils.runGitInCheckout( + var pathsToCopy = await utils.runGitInCheckout( 'ls-tree', '-r', '--name-only', @@ -1399,7 +1422,7 @@ Object.assign(Isopack.prototype, { 'tools', 'examples', 'LICENSE.txt', 'LICENSES', 'meteor', 'meteor.bat', 'scripts/admin/launch-meteor', 'packages/package-version-parser/package-version-parser.js', - 'packages/meteor/define-package.js', + 'packages/core-runtime/package-registry.js', 'packages/meteor/flush-buffers-on-exit-in-windows.js', ); @@ -1444,19 +1467,19 @@ Object.assign(Isopack.prototype, { // Set up builder to write to the correct directory var toolPath = 'mt-' + archinfo.host(); - builder = builder.enter(toolPath); + builder = await builder.enter(toolPath); const sourceRootDir = files.getCurrentToolsDir(); - builder.copyTranspiledModules(pathsToTranspile, { + await builder.copyTranspiledModules(pathsToTranspile, { sourceRootDir, needToTranspile: true, }); - var gitSha = utils.runGitInCheckout('rev-parse', 'HEAD'); + var gitSha = await utils.runGitInCheckout('rev-parse', 'HEAD'); builder.reserve('isopackets', {directory: true}); - builder.write('.git_version.txt', {data: Buffer.from(gitSha, 'utf8')}); + await builder.write('.git_version.txt', {data: Buffer.from(gitSha, 'utf8')}); - builder.copyDirectory({ + await builder.copyDirectory({ from: files.getCurrentToolsDir(), to: '', specificFiles: pathsToCopyStraight, @@ -1467,7 +1490,7 @@ Object.assign(Isopack.prototype, { // self-test (which isn't supported from release). var devBundleIgnore = _.clone(bundler.ignoreFiles); devBundleIgnore.push(/BrowserStackLocal/, /browserstack-webdriver/); - builder.copyDirectory({ + await builder.copyDirectory({ from: files.pathJoin(files.getDevBundle()), to: 'dev_bundle', ignore: devBundleIgnore, @@ -1478,40 +1501,39 @@ Object.assign(Isopack.prototype, { // Build all of the isopackets now, so that no build step is required when // you're actually running meteor from a release in order to load packages. - var isopacketBuildContext = makeIsopacketBuildContext(); + var isopacketBuildContext = await makeIsopacketBuildContext(); - var messages = buildmessage.capture(function () { + var messages = await buildmessage.capture(async function () { // We rebuild them in the order listed in ISOPACKETS. This is not strictly // necessary here, since any isopackets loaded as part of the build // process are going to be the current tool's isopackets, not the // isopackets that we're writing out. - _.each(ISOPACKETS, function (packages, isopacketName) { + for (const [isopacketName, packages] of Object.entries(ISOPACKETS)) { requestGarbageCollection(); - - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "compiling " + isopacketName + " packages for the tool" - }, function () { - isopacketBuildContext.isopackCache.buildLocalPackages(packages); + }, async function () { + await isopacketBuildContext.isopackCache.buildLocalPackages(packages); if (buildmessage.jobHasMessages()) { return; } - var image = bundler.buildJsImage({ + var image = (await bundler.buildJsImage({ name: "isopacket-" + isopacketName, packageMap: isopacketBuildContext.packageMap, isopackCache: isopacketBuildContext.isopackCache, use: packages - }).image; + })).image; if (buildmessage.jobHasMessages()) { return; } requestGarbageCollection(); - image.write( - builder.enter(files.pathJoin('isopackets', isopacketName))); + await image.write( + await builder.enter(files.pathJoin('isopackets', isopacketName))); }); - }); + } }); // This is a build step ... but it's one that only happens in development, // and similar to a isopacket load failure, it can just crash the app diff --git a/tools/isobuild/js-analyze.js b/tools/isobuild/js-analyze.js index 834f8ea809..2de961be63 100644 --- a/tools/isobuild/js-analyze.js +++ b/tools/isobuild/js-analyze.js @@ -1,9 +1,10 @@ import { parse } from '@meteorjs/babel'; import { analyze as analyzeScope } from 'escope'; -import LRU from "lru-cache"; - +import LRUCache from "lru-cache"; +import { Profile } from '../tool-env/profile'; import Visitor from "@meteorjs/reify/lib/visitor.js"; import { findPossibleIndexes } from "@meteorjs/reify/lib/utils.js"; +import acorn from 'acorn'; const hasOwn = Object.prototype.hasOwnProperty; const objToStr = Object.prototype.toString @@ -12,10 +13,12 @@ function isRegExp(value) { return value && objToStr.call(value) === "[object RegExp]"; } -var AST_CACHE = new LRU({ +var AST_CACHE = new LRUCache({ max: Math.pow(2, 12), length(ast) { - return ast.loc.end.line; + // Estimate cached lines based on average length per character + const avgCharsPerLine = 40; + return Math.ceil(ast.end / avgCharsPerLine); } }); @@ -26,9 +29,35 @@ function tryToParse(source, hash) { } let ast; - try { - ast = parse(source); + Profile.time('jsAnalyze.parse', () => { + try { + ast = acorn.parse(source, { + ecmaVersion: 'latest', + sourceType: 'script', + allowAwaitOutsideFunction: true, + allowImportExportEverywhere: true, + allowReturnOutsideFunction: true, + allowHashBang: true, + checkPrivateFields: false, + }); + } catch (error) { + ast = parse(source, { + strictMode: false, + sourceType: 'module', + allowImportExportEverywhere: true, + allowReturnOutsideFunction: true, + allowUndeclaredExports: true, + plugins: [ + // Only plugins for stage 3 features are enabled + // Enabling some plugins significantly affects parser performance + 'importAttributes', + 'explicitResourceManagement', + 'decorators' + ] + }); + } + }); } catch (e) { if (typeof e.loc === 'object') { e.$ParseError = true; @@ -71,7 +100,10 @@ export function findImportedModuleIdentifiers(source, hash) { } const ast = tryToParse(source, hash); - importedIdentifierVisitor.visit(ast, source, possibleIndexes); + Profile.time('findImportedModuleIdentifiersVisitor', () => { + importedIdentifierVisitor.visit(ast, source, possibleIndexes); + }); + return importedIdentifierVisitor.identifiers; } @@ -242,12 +274,12 @@ function isPropertyWithName(node, name) { // // It only cares about assignments to variables; an assignment to a field on an // object (`Foo.Bar = true`) neither causes `Foo` nor `Foo.Bar` to be returned. -const globalsCache = new LRU({ +const globalsCache = new LRUCache({ max: Math.pow(2, 12), length(globals) { let sum = 0; Object.keys(globals).forEach(name => sum += name.length); - return sum; + return sum === 0 ? 1 : sum; } }); @@ -273,7 +305,7 @@ export function findAssignedGlobals(source, hash) { // But it can't pull references outward, so for our purposes it is safe to // ignore. const scopeManager = analyzeScope(ast, { - ecmaVersion: 6, + ecmaVersion: 9, sourceType: "module", ignoreEval: true, // Ensures we don't treat top-level var declarations as globals. diff --git a/tools/isobuild/linker.js b/tools/isobuild/linker.js index 8edd4fc117..5f0754b0a3 100644 --- a/tools/isobuild/linker.js +++ b/tools/isobuild/linker.js @@ -4,7 +4,7 @@ var buildmessage = require('../utils/buildmessage.js'); var watch = require('../fs/watch'); var Profile = require('../tool-env/profile').Profile; import assert from 'assert'; -import LRU from 'lru-cache'; +import LRUCache from 'lru-cache'; import { sourceMapLength } from '../utils/utils.js'; import files from '../fs/files'; import { findAssignedGlobals } from './js-analyze.js'; @@ -15,14 +15,14 @@ import { convert as convertColons } from '../utils/colon-converter.js'; const CACHE_SIZE = process.env.METEOR_APP_PRELINK_CACHE_SIZE || 1024*1024*20; // Cache individual files prelinked -const APP_PRELINK_CACHE = new LRU({ +const APP_PRELINK_CACHE = new LRUCache({ max: CACHE_SIZE, - length: function (prelinked) { + length (prelinked) { return prelinked.source.length + sourceMapLength(prelinked.sourceMap); } }); // Caches code with source map for dynamic files -const DYNAMIC_PRELINKED_OUTPUT_CACHE = new LRU({ +const DYNAMIC_PRELINKED_OUTPUT_CACHE = new LRUCache({ max: Math.pow(2, 11) }); @@ -34,6 +34,8 @@ var packageDot = function (name) { } }; +const enableClientTLA = process.env.METEOR_ENABLE_CLIENT_TOP_LEVEL_AWAIT === 'true'; + /////////////////////////////////////////////////////////////////////////////// // Module /////////////////////////////////////////////////////////////////////////////// @@ -56,6 +58,7 @@ var Module = function (options) { // options self.useGlobalNamespace = options.useGlobalNamespace; self.combinedServePath = options.combinedServePath; + self.addEagerRequires = !!options.addEagerRequires; }; Object.assign(Module.prototype, { @@ -86,7 +89,7 @@ Object.assign(Module.prototype, { // Figure out which vars need to be specifically put in the module // scope. - computeAssignedVariables: Profile("linker Module#computeAssignedVariables", function () { + computeAssignedVariables: Profile("linker Module#computeAssignedVariables", async function () { var self = this; // The assigned variables in the app aren't actually used for anything: @@ -99,10 +102,10 @@ Object.assign(Module.prototype, { // Find all global references in any files var assignedVariables = []; - _.each(self.files, function (file) { + for (const file of self.files) { assignedVariables = assignedVariables.concat( - file.computeAssignedVariables()); - }); + await file.computeAssignedVariables()); + } assignedVariables = _.uniq(assignedVariables); return assignedVariables; @@ -110,7 +113,7 @@ Object.assign(Module.prototype, { // Output is a list of objects with keys 'source', 'servePath', 'sourceMap', // 'sourcePath' - getPrelinkedFiles: Profile("linker Module#getPrelinkedFiles", function () { + getPrelinkedFiles: Profile("linker Module#getPrelinkedFiles", async function () { var self = this; const haveMeteorInstallOptions = @@ -124,7 +127,8 @@ Object.assign(Module.prototype, { // Ignore lazy files unless we have a module system. const eagerFiles = _.filter(self.files, file => ! file.lazy); - return _.map(eagerFiles, function (file) { + const ret = []; + for (const file of eagerFiles) { const cacheKey = JSON.stringify([ file._inputHash, file.bare, @@ -132,16 +136,17 @@ Object.assign(Module.prototype, { ]); if (APP_PRELINK_CACHE.has(cacheKey)) { - return APP_PRELINK_CACHE.get(cacheKey); + ret.push(APP_PRELINK_CACHE.get(cacheKey)); + continue; } - const node = file.getPrelinkedOutput({ preserveLineNumbers: true }); - const results = Profile.time( - "toStringWithSourceMap (app)", () => { - return node.toStringWithSourceMap({ - file: file.servePath - }); // results has 'code' and 'map' attributes - } + const node = await file.getPrelinkedOutput({ preserveLineNumbers: true }); + const results = await Profile.time( + "toStringWithSourceMap (app)", () => { + return node.toStringWithSourceMap({ + file: file.servePath + }); // results has 'code' and 'map' attributes + } ); let sourceMap = results.map.toJSON(); @@ -158,8 +163,10 @@ Object.assign(Module.prototype, { }; APP_PRELINK_CACHE.set(cacheKey, prelinked); - return prelinked; - }); + ret.push(prelinked); + } + + return ret; } // Otherwise.. @@ -178,40 +185,58 @@ Object.assign(Module.prototype, { }; const results = [result]; - // An array of strings and SourceNode objects. let chunks = []; let fileCount = 0; // Emit each file if (haveMeteorInstallOptions) { - const trees = self._buildModuleTrees(results, sourceWidth); - fileCount = self._chunkifyModuleTrees(trees, chunks, sourceWidth); - result.exportsName = - self._chunkifyEagerRequires(chunks, fileCount, sourceWidth); + const trees = await self._buildModuleTrees(results, sourceWidth); + fileCount = await self._chunkifyModuleTrees(trees, chunks, sourceWidth); + // During the full link, code will be added to pass these to the + // core runtime so it can handle evaluating the modules + result.eagerModulePaths = []; + result.mainModulePath = null; + + for (const file of this.files) { + if (file.bare) { + chunks.push('\n', await file.getPrelinkedOutput({ + sourceWidth + })); + } else if (!file.lazy) { + result.eagerModulePaths.push(file.absModuleId); + if (file.mainModule) { + result.mainModulePath = file.absModuleId; + } + + if (self.addEagerRequires) { + chunks.push(`\nrequire(${JSON.stringify(file.absModuleId)});`); + } + } + } } else { - _.each(self.files, function (file) { + for (const file of self.files) { if (file.lazy) { // Ignore lazy files unless we have a module system. - return; + continue; } if (!_.isEmpty(chunks)) { chunks.push("\n\n\n\n\n\n"); } - chunks.push(file.getPrelinkedOutput({ + chunks.push(await file.getPrelinkedOutput({ sourceWidth: sourceWidth, })); ++fileCount; - }); + } } var node = new sourcemap.SourceNode(null, null, null, chunks); - Profile.time( + await Profile.time( 'getPrelinkedFiles toStringWithSourceMap', function () { if (fileCount > 0) { @@ -239,10 +264,10 @@ Object.assign(Module.prototype, { // files or directories, and the values are either nested objects // (representing directories) or File objects (representing modules). // Bare files and lazy files that are never imported are ignored. - _buildModuleTrees(results, sourceWidth) { + async _buildModuleTrees(results, sourceWidth) { // Map from meteorInstallOptions objects to trees of File objects for // all non-dynamic modules. - const trees = new Map; + const trees = new Map(); function getTree({ meteorInstallOptions }) { if (! trees.has(meteorInstallOptions)) { @@ -251,31 +276,30 @@ Object.assign(Module.prototype, { return trees.get(meteorInstallOptions); } - _.each(this.files, file => { + for (const file of this.files) { if (file.bare) { - // Bare files will be added before the synchronous require calls - // in _chunkifyEagerRequires. - return; + // Bare files will be added after the module tree + continue; } if (file.lazy && ! file.imported) { // If the file is not eagerly evaluated, and no other files // import or require it, then it need not be included in the // bundle. - return; + continue; } const tree = getTree(file); if (file.aliasId) { addToTree(file.aliasId, file.absModuleId, tree); - return; + continue; } if (file.isDynamic()) { const servePath = files.pathJoin("dynamic", file.absModuleId); const { code: source, map } = - getOutputWithSourceMapCached(file, servePath, { sourceWidth }) + await getOutputWithSourceMapCached(file, servePath, { sourceWidth }) results.push({ source, @@ -312,7 +336,7 @@ Object.assign(Module.prototype, { // initial bundle, so we add it to the static tree. addToTree(file, file.absModuleId, tree); } - }); + } return trees; }, @@ -320,7 +344,7 @@ Object.assign(Module.prototype, { // Take the tree generated in getPrelinkedFiles and populate the chunks // array with strings and SourceNode objects that can be combined into a // single SourceNode object. Return the count of modules in the tree. - _chunkifyModuleTrees(trees, chunks, sourceWidth) { + async _chunkifyModuleTrees(trees, chunks, sourceWidth) { const self = this; assert.ok(_.isArray(chunks)); @@ -328,11 +352,10 @@ Object.assign(Module.prototype, { let moduleCount = 0; - function walk(t) { + async function walk(t) { if (Array.isArray(t)) { ++moduleCount; chunks.push(JSON.stringify(t, null, 2)); - } else if (typeof t === "string") { // This case can happen if a package.json file has an // object-valued "browser" field that aliases this module to a @@ -344,31 +367,28 @@ Object.assign(Module.prototype, { // are meant to be resolved relative to the package.json file. ++moduleCount; chunks.push(JSON.stringify(t)); - } else if (t === false) { // This case can happen if a package.json file has an // object-valued "browser" field that maps this module to `false`, // indicating it should be replaced by an empty stub. ++moduleCount; chunks.push("function(){}"); - } else if (t instanceof File) { ++moduleCount; - chunks.push(t.getPrelinkedOutput({ + chunks.push(await t.getPrelinkedOutput({ sourceWidth, })); - } else if (_.isObject(t)) { chunks.push("{"); const keys = Object.keys(t); - _.each(keys, (key, i) => { + for (const [i, key] of keys.entries()) { chunks.push(JSON.stringify(key), ":"); - walk(t[key]); + await walk(t[key]); if (i < keys.length - 1) { chunks.push(","); } - }); + } chunks.push("}"); } } @@ -382,11 +402,11 @@ Object.assign(Module.prototype, { // Emit one meteorInstall call per distinct meteorInstallOptions // object, since the options apply to all modules installed by a given // call to meteorInstall. - trees.forEach((tree, options) => { + for (const [options, tree] of trees) { chunks.push("meteorInstall("); - walk(tree); + await walk(tree); chunks.push(",", self._stringifyInstallOptions(options), ");\n"); - }); + } if (moduleCount === 0) { // If no files were actually added to the chunks array, roll back @@ -428,51 +448,6 @@ Object.assign(Module.prototype, { _hasDynamicModules() { return this.files.some(file => file.isDynamic()); - }, - - // Adds require calls to the chunks array for all modules that should be - // eagerly evaluated, and also includes any bare files before the - // require calls. Returns the name of the variable that holds the main - // exports object, if api.mainModule was used to define a main module. - _chunkifyEagerRequires(chunks, moduleCount, sourceWidth) { - assert.ok(_.isArray(chunks)); - assert.ok(_.isNumber(moduleCount)); - assert.ok(_.isNumber(sourceWidth)); - - let exportsName; - - // Now that we have installed everything in this package or - // application, first evaluate the bare files, then require the - // non-lazy (eager) modules. - - const eagerModuleFiles = []; - - _.each(this.files, file => { - if (file.bare) { - chunks.push("\n", file.getPrelinkedOutput({ - sourceWidth, - })); - } else if (moduleCount > 0 && ! file.lazy) { - eagerModuleFiles.push(file); - } - }); - - if (eagerModuleFiles.length > 0) { - _.each(eagerModuleFiles, file => { - if (file.mainModule) { - exportsName = "exports"; - } - - chunks.push( - file.mainModule ? "\nvar " + exportsName + " = " : "\n", - "require(", - JSON.stringify(file.absModuleId), - ");" - ); - }); - } - - return exportsName; } }); @@ -630,7 +605,7 @@ Object.assign(File.prototype, { // example: if the code references 'Foo.bar.baz' and 'Quux', and // neither are declared in a scope enclosing the point where they're // referenced, then globalReferences would include ["Foo", "Quux"]. - computeAssignedVariables: Profile("linker File#computeAssignedVariables", function () { + computeAssignedVariables: Profile("linker File#computeAssignedVariables", async function () { var self = this; if (self.absModuleId) { @@ -657,7 +632,7 @@ Object.assign(File.prototype, { column: e.column }; if (self.sourceMap) { - var parsed = Promise.await(new sourcemap.SourceMapConsumer(self.sourceMap)); + var parsed = await new sourcemap.SourceMapConsumer(self.sourceMap); var original = parsed.originalPositionFor( {line: e.lineNumber, column: e.column - 1}); if (original.source) { @@ -726,7 +701,7 @@ Object.assign(File.prototype, { }); const getPrelinkedOutputCached = require("optimism").wrap( - function (file, options) { + async function (file, options) { var width = options.sourceWidth || 70; var bannerWidth = width + 3; var preserveLineNumbers = options.preserveLineNumbers; @@ -780,7 +755,7 @@ const getPrelinkedOutputCached = require("optimism").wrap( let chunk = result.code; if (result.map) { - const sourcemapConsumer = Promise.await(new sourcemap.SourceMapConsumer(result.map)); + const sourcemapConsumer = await new sourcemap.SourceMapConsumer(result.map); chunk = sourcemap.SourceNode.fromStringWithSourceMap( result.code, sourcemapConsumer, @@ -836,7 +811,7 @@ const getPrelinkedOutputCached = require("optimism").wrap( } ); -function getOutputWithSourceMapCached(file, servePath, options) { +async function getOutputWithSourceMapCached(file, servePath, options) { const key = JSON.stringify({ hash: file._inputHash, arch: file.bundleArch, @@ -850,10 +825,12 @@ function getOutputWithSourceMapCached(file, servePath, options) { return DYNAMIC_PRELINKED_OUTPUT_CACHE.get(key); } - const result = file.getPrelinkedOutput({ + const linkedOutput = await file.getPrelinkedOutput({ ...options, disableCache: true - }).toStringWithSourceMap({ + }); + + const result = linkedOutput.toStringWithSourceMap({ file: servePath, }); @@ -932,7 +909,7 @@ var bannerPadding = function (bannerWidth) { // sourceMap (a string) (XXX) // - assignedPackageVariables: an array of variables assigned to without // being declared -export var prelink = Profile("linker.prelink", function (options) { +export var prelink = Profile("linker.prelink", async function (options) { var module = new Module({ name: options.name, combinedServePath: options.combinedServePath, @@ -945,8 +922,8 @@ export var prelink = Profile("linker.prelink", function (options) { // Do static analysis to compute module-scoped variables. Error recovery from // the static analysis mutates the sources, so this has to be done before // concatenation. - var assignedVariables = module.computeAssignedVariables(); - var files = module.getPrelinkedFiles(); + var assignedVariables = await module.computeAssignedVariables(); + var files = await module.getPrelinkedFiles(); return { files: files, @@ -962,12 +939,22 @@ var SOURCE_MAP_INSTRUCTIONS_COMMENT = banner([ ]); var getHeader = function (options) { - var chunks = []; + if (!options.hasRuntime) { + return '(function() {\n\n'; + } - chunks.push( - "(function () {\n\n", - getImportCode(options.imports, "/* Imports */\n", false), - ); + var chunks = [`Package["core-runtime"].queue("${options.name}",function () {`]; + + var isApp = options.name === null; + if (isApp) { + chunks.push( + getImportCode(options.imports, "/* Imports for global scope */\n\n", true), + ); + } else { + chunks.push( + getImportCode(options.imports, "/* Imports */\n", false), + ); + } const packageVariables = _.filter( options.packageVariables, @@ -976,8 +963,7 @@ var getHeader = function (options) { if (!_.isEmpty(packageVariables)) { chunks.push( - "/* Package-scope variables */\n", - "var ", + "/* Package-scope variables */\nvar ", packageVariables.join(', '), ";\n\n", ); @@ -1011,39 +997,93 @@ function getImportCode(imports, header, omitVar) { return buf; } -var getFooter = function ({ +function getFooter ({ name, exported, - exportsName, + mainModulePath, + eagerModulePaths, + imports, + hasRuntime }) { - var chunks = []; - - if (name && exported) { - chunks.push("\n\n/* Exports */\n"); - - // Even if there are no exports, we need to define Package.foo, - // because the existence of Package.foo is how another package - // (e.g., one that weakly depends on foo) can tell if foo is loaded. - chunks.push("Package._define(" + JSON.stringify(name)); - - if (exportsName) { - // If we have an exports object, use it as Package[name]. - chunks.push(", ", exportsName); - } - - if (! _.isEmpty(exported)) { - const scratch = {}; - _.each(exported, symbol => scratch[symbol] = symbol); - const symbolTree = writeSymbolTree(buildSymbolTree(scratch)); - chunks.push(", ", symbolTree); - } - - chunks.push(");\n"); + if (!hasRuntime) { + return '\n})();\n'; } - chunks.push("\n})();\n"); + let chunks = []; + let returnObj = Object.create(null); + + if (! _.isEmpty(exported)) { + const scratch = {}; + _.each(exported, symbol => scratch[symbol] = symbol); + const symbolTree = writeSymbolTree(buildSymbolTree(scratch), 4); + returnObj.export = `function () { return ${symbolTree};}`; + } + + + if (eagerModulePaths && eagerModulePaths.length > 0) { + returnObj.require = 'require'; + + let modulePaths = eagerModulePaths.map(path => ` ${JSON.stringify(path)}`); + returnObj.eagerModulePaths = `[\n${modulePaths.join(',\n')}\n ]`; + } + if (mainModulePath) { + returnObj.mainModulePath = JSON.stringify(mainModulePath); + } + + chunks.push("\n\n/* Exports */\n"); + chunks.push('return {\n'); + + let entries = Object.entries(returnObj); + entries.forEach(([ key, value ], index) => { + chunks.push(` ${key}: ${value}`); + if (index !== entries.length - 1) { + chunks.push(',\n'); + } + }); + + chunks.push("\n}});\n"); + return chunks.join(''); -}; +} + +function wrapWithHeaderAndFooter(files, header, footer) { + // Bias the source map by the length of the header without + // (fully) parsing and re-serializing it. (We used to do this + // with the source-map library, but it was incredibly slow, + // accounting for over half of bundling time.) It would be nice + // if we could use "index maps" for this (the 'sections' key), + // as that would let us avoid even JSON-parsing the source map, + // but that doesn't seem to be supported by Firefox yet. + if (header.charAt(header.length - 1) !== "\n") { + // make sure it's a whole number of lines + header += "\n"; + } + var headerLines = header.split('\n').length - 1; + var headerContent = (new Array(headerLines + 1).join(';')); + + return files.map(file => { + if (file.dynamic) { + return file; + } + + if (file.sourceMap) { + var sourceMap = file.sourceMap; + sourceMap.mappings = headerContent + sourceMap.mappings; + return { + source: header + file.source + footer, + sourcePath: file.sourcePath, + servePath: file.servePath, + sourceMap: sourceMap + }; + } + + return { + source: header + file.source + footer, + sourcePath: file.sourcePath, + servePath: file.servePath + }; + }) +} // This is the real entry point that's still used to produce Meteor apps. It // takes in information about the files in the package including imports and @@ -1064,7 +1104,7 @@ var getFooter = function ({ // // Output is an array of output files: objects with keys source, servePath, // sourceMap. -export var fullLink = Profile("linker.fullLink", function (inputFiles, { +export var fullLink = Profile("linker.fullLink", async function (inputFiles, { // True if we're linking the application (as opposed to a // package). Among other consequences, this makes the top level // namespace be the same as the global namespace, so that symbols are @@ -1089,6 +1129,10 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { // True if JS files with source maps should have a comment explaining // how to use them in a browser. includeSourceMapInstructions, + + // List of packages this bundle directly uses, or is implied by the packages + // it uses + deps }) { buildmessage.assertInJob(); @@ -1097,15 +1141,74 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { bundleArch, useGlobalNamespace: isApp, combinedServePath, + // To support `/client/compatibility`, we can't use the runtime for the + // app on the client when TLA is disabled since it wraps all of + // the app code in a function. Instead, we have the module add eager requires. + addEagerRequires: !bundleArch.startsWith('os.') && isApp && !enableClientTLA }); + // Check if the core-runtime package will already be loaded + // It is a dependency of the meteor package, and all packages depend + // on the Meteor package, so if there are any packages loaded first, + // we can be sure the runtime will be available + // The main situations it is not available is the core-runtime + // package itself, or any build plugins with no dependencies + let hasRuntime = deps.some(entry => entry.unordered !== true); + _.each(inputFiles, file => module.addFile(file)); - var prelinkedFiles = module.getPrelinkedFiles(); + var prelinkedFiles = await module.getPrelinkedFiles(); + + let eagerModulePaths; + let mainModulePath; + _.each(prelinkedFiles, file => { + if (file.eagerModulePaths && file.eagerModulePaths.length > 0) { + eagerModulePaths = file.eagerModulePaths; + mainModulePath = file.mainModulePath; + } + }); + + if (!hasRuntime && ( + Object.keys(declaredExports).length > 0 || + eagerModulePaths || + mainModulePath + )) { + throw new Error(`Runtime is not available, but it uses features needing the runtime: ${name}`); + } // If we're in the app, then we just add the import code as its own file in // the front. if (isApp) { + let wrapForTLA = hasRuntime && + (bundleArch.startsWith('os.') || enableClientTLA); + + if (wrapForTLA) { + // Ensure there is always at least one file + // so the globals can be defined + if (prelinkedFiles.length === 0) { + prelinkedFiles.unshift({ + source: '', + servePath: "/global-imports.js" + }); + } + + let header = getHeader({ + name: null, + imports, + packageVariables: [], + hasRuntime, + deps + }); + let footer = getFooter({ + name: null, + exported: {}, + eagerModulePaths, + hasRuntime + }); + + return wrapWithHeaderAndFooter(prelinkedFiles, header, footer); + } + if (! _.isEmpty(imports)) { prelinkedFiles.unshift({ source: getImportCode( @@ -1116,6 +1219,7 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { servePath: "/global-imports.js" }); } + return prelinkedFiles; } @@ -1123,8 +1227,8 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { // the static analysis mutates the sources, so this has to be done before // concatenation. let assignedVariables; - const failed = buildmessage.enterJob('computing assigned variables', () => { - assignedVariables = module.computeAssignedVariables(); + const failed = await buildmessage.enterJob('computing assigned variables', async () => { + assignedVariables = await module.computeAssignedVariables(); return buildmessage.jobHasMessages(); }); if (failed) { @@ -1150,61 +1254,25 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { // Otherwise we're making a package and we have to actually combine the files // into a single scope. var header = getHeader({ + name, imports, - packageVariables: _.union(assignedVariables, declaredExports) - }); - - let exportsName; - _.each(prelinkedFiles, file => { - if (file.exportsName) { - exportsName = file.exportsName; - } + packageVariables: _.union(assignedVariables, declaredExports), + hasRuntime, + deps }); var footer = getFooter({ + name, exported: declaredExports, - exportsName, - name + mainModulePath, + eagerModulePaths, + imports, + hasRuntime }); if (includeSourceMapInstructions) { header = SOURCE_MAP_INSTRUCTIONS_COMMENT + "\n\n" + header; } - // Bias the source map by the length of the header without - // (fully) parsing and re-serializing it. (We used to do this - // with the source-map library, but it was incredibly slow, - // accounting for over half of bundling time.) It would be nice - // if we could use "index maps" for this (the 'sections' key), - // as that would let us avoid even JSON-parsing the source map, - // but that doesn't seem to be supported by Firefox yet. - if (header.charAt(header.length - 1) !== "\n") { - // make sure it's a whole number of lines - header += "\n"; - } - var headerLines = header.split('\n').length - 1; - var headerContent = (new Array(headerLines + 1).join(';')); - - return _.map(prelinkedFiles, function (file) { - if (file.dynamic) { - return file; - } - - if (file.sourceMap) { - var sourceMap = file.sourceMap; - sourceMap.mappings = headerContent + sourceMap.mappings; - return { - source: header + file.source + footer, - sourcePath: file.sourcePath, - servePath: file.servePath, - sourceMap: sourceMap - }; - } else { - return { - source: header + file.source + footer, - sourcePath: file.sourcePath, - servePath: file.servePath - }; - } - }); + return wrapWithHeaderAndFooter(prelinkedFiles, header, footer); }); diff --git a/tools/isobuild/meteor-npm.js b/tools/isobuild/meteor-npm.js index dbee6386fc..d1ebe42341 100644 --- a/tools/isobuild/meteor-npm.js +++ b/tools/isobuild/meteor-npm.js @@ -13,7 +13,6 @@ var utils = require('../utils/utils.js'); var runLog = require('../runners/run-log.js'); var Profile = require('../tool-env/profile').Profile; import { parse } from "semver"; -import { version as npmVersion } from 'npm'; import { get as getRebuildArgs } from "../static-assets/server/npm-rebuild-args.js"; @@ -32,8 +31,12 @@ import { var meteorNpm = exports; +// change this will recreate the npm-shrinkwrap.json file +// and install all dependencies from scratch +const LOCK_FILE_VERSION = 4; + // Expose the version of npm in use from the dev bundle. -meteorNpm.npmVersion = npmVersion; +meteorNpm.npmVersion = "10.1.0"; // if a user exits meteor while we're trying to create a .npm // directory, we will have temporary directories that we clean up @@ -58,7 +61,7 @@ var NpmFailure = function () {}; // @param npmDependencies {Object} dependencies that should be // installed, eg {tar: '0.1.6', gcd: '0.0.0'}. If falsey or empty, // will remove the .npm directory instead. -meteorNpm.updateDependencies = function (packageName, +meteorNpm.updateDependencies = async function (packageName, packageNpmDir, npmDependencies, quiet) { @@ -76,7 +79,7 @@ meteorNpm.updateDependencies = function (packageName, // instances are trying to make this update in parallel, so we rename the // directory to something before doing the rm -rf. try { - files.rename(packageNpmDir, newPackageNpmDir); + await files.rename(packageNpmDir, newPackageNpmDir); } catch (e) { if (e.code !== 'ENOENT') { throw e; @@ -84,7 +87,7 @@ meteorNpm.updateDependencies = function (packageName, // It didn't exist, which is exactly what we wanted. return false; } - files.rm_recursive(newPackageNpmDir); + await files.rm_recursive_deferred(newPackageNpmDir); return false; } @@ -99,19 +102,33 @@ meteorNpm.updateDependencies = function (packageName, // proceed. if (files.exists(packageNpmDir) && ! files.exists(files.pathJoin(packageNpmDir, 'npm-shrinkwrap.json'))) { - files.rm_recursive(packageNpmDir); + await files.rm_recursive_deferred(packageNpmDir); + } + + // with the changes on npm 8, where there were changes to how the packages metadata is given + // we need to reinstall all packages from scratch + // and to do that we need to rewrite all the shrinkwrap files + if (files.exists(packageNpmDir)) { + try { + const shrinkwrap = JSON.parse(files.readFile( + files.pathJoin(packageNpmDir, 'npm-shrinkwrap.json') + )); + if (shrinkwrap.lockfileVersion !== LOCK_FILE_VERSION) { + await files.rm_recursive_deferred(packageNpmDir); + } + } catch (e) {} } if (files.exists(packageNpmDir)) { // we already nave a .npm directory. update it appropriately with some // ceremony involving: // `npm install`, `npm install name@version`, `npm shrinkwrap` - updateExistingNpmDirectory( + await updateExistingNpmDirectory( packageName, newPackageNpmDir, packageNpmDir, npmDependencies, quiet); } else { // create a fresh .npm directory with `npm install // name@version` and `npm shrinkwrap` - createFreshNpmDirectory( + await createFreshNpmDirectory( packageName, newPackageNpmDir, packageNpmDir, npmDependencies, quiet); } } catch (e) { @@ -126,7 +143,7 @@ meteorNpm.updateDependencies = function (packageName, throw e; } finally { if (files.exists(newPackageNpmDir)) { - files.rm_recursive(newPackageNpmDir); + await files.rm_recursive_deferred(newPackageNpmDir); } tmpDirs = _.without(tmpDirs, newPackageNpmDir); } @@ -280,7 +297,7 @@ function isDirectory(path) { // Rebuilds any binary dependencies in the given node_modules directory, // and returns true iff anything was rebuilt. meteorNpm.rebuildIfNonPortable = -Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { +Profile("meteorNpm.rebuildIfNonPortable", async function (nodeModulesDir) { const dirsToRebuild = []; function scan(dir, scoped) { @@ -339,10 +356,10 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // directory paths. const tempPkgDirs = {}; - dirsToRebuild.splice(0).forEach(pkgPath => { + for (const pkgPath of dirsToRebuild.splice(0)) { const tempPkgDir = tempPkgDirs[pkgPath] = files.pathJoin( - tempNodeModules, - files.pathRelative(nodeModulesDir, pkgPath) + tempNodeModules, + files.pathRelative(nodeModulesDir, pkgPath) ); // It's possible the pkgPath directory may have been deleted since we @@ -352,7 +369,7 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // original package will be left untouched if the rebuild fails. We // could just run files.cp_r(pkgPath, tempPkgDir) here, except that we // want to handle nested node_modules directories specially. - copyNpmPackageWithSymlinkedNodeModules(pkgPath, tempPkgDir); + await copyNpmPackageWithSymlinkedNodeModules(pkgPath, tempPkgDir); // Record the current process.versions so that we can avoid // copying/rebuilding/renaming next time. @@ -360,14 +377,14 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { dirsToRebuild.push(pkgPath); } - }); + } // The `npm rebuild` command must be run in the parent directory of the // relevant node_modules directory, which in this case is tempDir. - const rebuildResult = runNpmCommand(getRebuildArgs(), tempDir); + const rebuildResult = await runNpmCommand(getRebuildArgs(), tempDir); if (! rebuildResult.success) { buildmessage.error(rebuildResult.error); - files.rm_recursive(tempDir); + await files.rm_recursive_deferred(tempDir); return false; } @@ -375,12 +392,12 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // If the `npm rebuild` command succeeded, overwrite the original // package directories with the rebuilt package directories. - dirsToRebuild.forEach(function (pkgPath) { + for (const pkgPath of dirsToRebuild) { const actualNodeModulesDir = - files.pathJoin(pkgPath, "node_modules"); + files.pathJoin(pkgPath, "node_modules"); const actualNodeModulesStat = - files.statOrNull(actualNodeModulesDir); + files.statOrNull(actualNodeModulesDir); if (actualNodeModulesStat && actualNodeModulesStat.isDirectory()) { @@ -392,18 +409,18 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // directory that contains real packages rather than symlinks. const symlinkNodeModulesDir = - files.pathJoin(tempPkgDirs[pkgPath], "node_modules"); + files.pathJoin(tempPkgDirs[pkgPath], "node_modules"); - files.renameDirAlmostAtomically( - actualNodeModulesDir, - symlinkNodeModulesDir + await files.renameDirAlmostAtomically( + actualNodeModulesDir, + symlinkNodeModulesDir ); } - files.renameDirAlmostAtomically(tempPkgDirs[pkgPath], pkgPath); - }); + await files.renameDirAlmostAtomically(tempPkgDirs[pkgPath], pkgPath); + } - files.rm_recursive(tempDir); + await files.rm_recursive_deferred(tempDir); return true; }); @@ -411,23 +428,23 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // Copy an npm package directory to another location, but attempt to // symlink all of its node_modules rather than recursively copying them, // which potentially saves a lot of time. -function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { +async function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { files.mkdir_p(toPkgDir); let needToHandleNodeModules = false; - files.readdir(fromPkgDir).forEach(item => { + for (const item of files.readdir(fromPkgDir)) { if (item === "node_modules") { // We'll link or copy node_modules in a follow-up step. needToHandleNodeModules = true; - return; + continue; } - files.cp_r( - files.pathJoin(fromPkgDir, item), - files.pathJoin(toPkgDir, item) + await files.cp_r( + files.pathJoin(fromPkgDir, item), + files.pathJoin(toPkgDir, item) ); - }); + } if (! needToHandleNodeModules) { return; @@ -438,11 +455,11 @@ function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { files.mkdir(nodeModulesToPath); - files.readdir(nodeModulesFromPath).forEach(depPath => { + for (const depPath of files.readdir(nodeModulesFromPath)) { if (depPath === ".bin") { // Avoid copying node_modules/.bin because commands like // .bin/node-gyp and .bin/node-pre-gyp tend to cause problems. - return; + continue; } const absDepFromPath = files.pathJoin(nodeModulesFromPath, depPath); @@ -450,7 +467,7 @@ function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { if (! files.stat(absDepFromPath).isDirectory()) { // Only copy package directories, even though there might be other // kinds of files in node_modules. - return; + continue; } const absDepToPath = files.pathJoin(nodeModulesToPath, depPath); @@ -460,9 +477,9 @@ function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { try { files.symlink(absDepFromPath, absDepToPath, "junction"); } catch (e) { - files.cp_r(absDepFromPath, absDepToPath); + await files.cp_r(absDepFromPath, absDepToPath); } - }); + } } const portableCache = Object.create(null); @@ -594,7 +611,7 @@ var makeNewPackageNpmDir = function (newPackageNpmDir) { ''/*git diff complains without trailing newline*/].join('\n')); }; -var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, +var updateExistingNpmDirectory = async function (packageName, newPackageNpmDir, packageNpmDir, npmDependencies, quiet) { // sanity check on contents of .npm directory @@ -627,7 +644,7 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, } if (oldNodeVersion !== currentNodeCompatibilityVersion()) { - files.rm_recursive(nodeModulesDir); + await files.rm_recursive_deferred(nodeModulesDir); } } @@ -649,8 +666,16 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, npmTree.dependencies[name] = { version }; }); - const minInstalledTree = - minimizeDependencyTree(installedDependenciesTree); + let minInstalledTree; + try { + minInstalledTree = minimizeDependencyTree(installedDependenciesTree); + } catch (e) { + console.error( + "Failed to minimize installed dependencies tree for ", + packageNpmDir + ); + throw e; + } const minShrinkwrapTree = minimizeDependencyTree(shrinkwrappedDependenciesTree); @@ -679,7 +704,7 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, } else { // Otherwise install npmTree.dependencies as if we were creating a new // .npm/package directory, and leave preservedShrinkwrap empty. - installNpmDependencies(npmDependencies, newPackageNpmDir); + await installNpmDependencies(npmDependencies, newPackageNpmDir); // Note: as of npm@4.0.0, npm-shrinkwrap.json files are regarded as // "canonical," meaning `npm install` (without a package argument) @@ -699,10 +724,28 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, 'npm-shrinkwrap.json' ); + // Starting from Npm 8, it's expected to have + // node_modules/ for the package name + const mappedDependencies = Object.entries( + preservedShrinkwrap.dependencies + ).reduce((acc, [name, info]) => { + return { + ...acc, + [`node_modules/${name}`]: info, + }; + }, {}); + // There are some unchanged packages here. Install from shrinkwrap. files.writeFile( newShrinkwrapFile, - JSON.stringify(preservedShrinkwrap, null, 2) + JSON.stringify( + { + ...preservedShrinkwrap, + dependencies: mappedDependencies, + }, + null, + 2 + ) ); const newPackageJsonFile = files.pathJoin( @@ -720,13 +763,13 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, ); // `npm install` - installFromShrinkwrap(newPackageNpmDir); + await installFromShrinkwrap(newPackageNpmDir); files.unlink(newShrinkwrapFile); files.unlink(newPackageJsonFile); } - completeNpmDirectory(packageName, newPackageNpmDir, packageNpmDir, + await completeNpmDirectory(packageName, newPackageNpmDir, packageNpmDir, npmDependencies); }; @@ -752,7 +795,7 @@ function isSubtreeOf(subsetTree, supersetTree, predicate) { return false; } -var createFreshNpmDirectory = function (packageName, newPackageNpmDir, +var createFreshNpmDirectory = async function (packageName, newPackageNpmDir, packageNpmDir, npmDependencies, quiet) { if (! quiet) { logUpdateDependencies(packageName, npmDependencies); @@ -760,13 +803,13 @@ var createFreshNpmDirectory = function (packageName, newPackageNpmDir, makeNewPackageNpmDir(newPackageNpmDir); - installNpmDependencies(npmDependencies, newPackageNpmDir); + await installNpmDependencies(npmDependencies, newPackageNpmDir); - completeNpmDirectory(packageName, newPackageNpmDir, packageNpmDir, + await completeNpmDirectory(packageName, newPackageNpmDir, packageNpmDir, npmDependencies); }; -function installNpmDependencies(dependencies, dir) { +async function installNpmDependencies(dependencies, dir) { const packageJsonPath = files.pathJoin(dir, "package.json"); const packageJsonExisted = files.exists(packageJsonPath); @@ -776,10 +819,10 @@ function installNpmDependencies(dependencies, dir) { ); try { - Object.keys(dependencies).forEach(name => { + for (const name of Object.keys(dependencies)) { const version = dependencies[name]; - installNpmModule(name, version, dir); - }); + await installNpmModule(name, version, dir); + } } finally { if (! packageJsonExisted) { files.unlink(packageJsonPath); @@ -788,7 +831,7 @@ function installNpmDependencies(dependencies, dir) { } // Shared code for updateExistingNpmDirectory and createFreshNpmDirectory. -function completeNpmDirectory( +async function completeNpmDirectory( packageName, newPackageNpmDir, packageNpmDir, @@ -805,7 +848,7 @@ function completeNpmDirectory( createReadme(newPackageNpmDir); createNodeVersion(newPackageNpmDir); - files.renameDirAlmostAtomically(newPackageNpmDir, packageNpmDir); + await files.renameDirAlmostAtomically(newPackageNpmDir, packageNpmDir); dirtyNodeModulesDirectory(files.pathJoin(packageNpmDir, "node_modules")); } @@ -850,7 +893,7 @@ const npmUserConfigFile = files.pathJoin( ); var runNpmCommand = meteorNpm.runNpmCommand = -Profile("meteorNpm.runNpmCommand", function (args, cwd) { +Profile("meteorNpm.runNpmCommand", async function (args, cwd) { import { getEnv } from "../cli/dev-bundle-bin-helpers.js"; const devBundleDir = files.getDevBundle(); @@ -879,23 +922,22 @@ Profile("meteorNpm.runNpmCommand", function (args, cwd) { args.join(' ') + ' ...\n'); } - return getEnv({ - devBundle: devBundleDir - }).then(env => { - const opts = { - env: env, - maxBuffer: 10 * 1024 * 1024 - }; + const env = await getEnv({devBundle: devBundleDir}); - if (cwd) { - opts.cwd = files.convertToOSPath(cwd); - } + const opts = { + env: env, + maxBuffer: 10 * 1024 * 1024 + }; - // Make sure we don't honor any user-provided configuration files. - env.npm_config_userconfig = npmUserConfigFile; + if (cwd) { + opts.cwd = files.convertToOSPath(cwd); + } - return new Promise(function (resolve) { - require('child_process').execFile( + // Make sure we don't honor any user-provided configuration files. + env.npm_config_userconfig = npmUserConfigFile; + + return new Promise(function (resolve) { + require('child_process').execFile( commandToRun, args, opts, function (err, stdout, stderr) { if (meteorNpm._printNpmCalls) { process.stdout.write(err ? 'failed\n' : 'done\n'); @@ -908,12 +950,70 @@ Profile("meteorNpm.runNpmCommand", function (args, cwd) { stderr: stderr }); } - ); - }).await(); - - }).await(); + ); + }); }); +function pathMatches(path, test) { + // Normalize path and test to avoid trailing slash discrepancies + path = path.replace(/\/+$/, ""); + test = test.replace(/\/+$/, ""); + + // pathMatches('node_modules/', 'node_modules/@babel/core/'); // Expected: true + // pathMatches('node_modules/', 'node_modules/@babel/core/node_modules/json5'); // Expected: false + // pathMatches('node_modules/@babel/core', 'node_modules/@babel/core/node_modules/json5'); // Expected: true + // pathMatches('node_modules/@babel/core', 'node_modules/@babel/core/'); // Expected: false + const regex = new RegExp(`^${path}(\/[^/]+)+$`); + + if (!regex.test(test)) return false; + + // Check if the path occurs again after the initial match + return test.indexOf(path, path.length) === -1; +} + +const getPackageName = (pkgPath) => { + const split = pkgPath.split("node_modules/"); + return split[split.length - 1]; +}; + +function getInstalledDependenciesTreeFromPackageLock({ + packages, + dependencies, + prefix, + mappedDependencies = {}, +}) { + const result = {}; + + Object.keys(dependencies || packages).forEach((pkgName) => { + if (prefix && !pathMatches(prefix, pkgName)) { + return; + } + const pkg = packages[pkgName]; + + const name = getPackageName(pkgName); + + if (!pkg || mappedDependencies[name]) return; + + const deps = + pkg.dependencies && + getInstalledDependenciesTreeFromPackageLock({ + packages, + prefix: pkgName, + mappedDependencies, + }); + + const hasDependencies = deps && Object.keys(deps).length > 0; + + result[name] = { + version: pkg.version, + resolved: pkg.resolved, + integrity: pkg.integrity, + ...(hasDependencies ? { dependencies: deps } : {}), + }; + }); + return result; +} + // Gets a JSON object from `npm ls --json` (getInstalledDependenciesTree) or // `npm-shrinkwrap.json` (getShrinkwrappedDependenciesTree). // @@ -931,80 +1031,58 @@ Profile("meteorNpm.runNpmCommand", function (args, cwd) { // } // } // } + +function getPackageLockFromPath(dir, path) { + // As per Npm 8, now the metadata is no longer inside .npm/package/node_modules/PACKAGE_NAME/package.json + // now you have every metadata of every package inside .npm/package/node_modules/ at .npm/package/node_modules/.package-lock.json + let packageLock = {}; + try { + const nodeModulesPath = files.pathJoin(dir, "node_modules"); + const packageLockPath = files.pathJoin(nodeModulesPath, path); + packageLock = JSON.parse(files.readFile(packageLockPath)); + } catch (e) {} + return packageLock; +} + function getInstalledDependenciesTree(dir) { - function ls(nodeModulesDir) { - let contents; - try { - contents = files.readdir(nodeModulesDir).sort(); - } finally { - if (! contents) return; - } + const defaultReturn = { + lockfileVersion: LOCK_FILE_VERSION, + }; + const pkgs = getPackageLockFromPath(dir, ".package-lock.json").packages; - const result = {}; + if (!pkgs) return defaultReturn; - contents.forEach(item => { - if (item.startsWith(".")) { - return; - } + let dependencies = + getInstalledDependenciesTreeFromPackageLock({ + packages: pkgs, + prefix: "node_modules", + }) || {}; - const pkgDir = files.pathJoin(nodeModulesDir, item); - const pkgJsonPath = files.pathJoin(pkgDir, "package.json"); + Object.keys(dependencies).forEach((packageName) => { + if (!packageName.startsWith("@")) return; + const deps = getPackageLockFromPath( + dir, + `${packageName}/package.json` + ).dependencies; + const packages = getPackageLockFromPath( + dir, + `${packageName}/package-lock.json` + ).dependencies; + if (!deps || !packages) return; - if (item.startsWith("@")) { - Object.assign(result, ls(pkgDir)); - return; - } - - let pkg; - try { - pkg = JSON.parse(files.readFile(pkgJsonPath)); - } finally { - if (! pkg) return; - } - - const name = pkg.name || item; - - const info = result[name] = { - version: pkg.version - }; - - const from = pkg._from || pkg.from; - if (from) { - // Fix for https://github.com/meteor/meteor/issues/9477: - const prefix = name + "@"; - let fromUrl = from; - if (fromUrl.startsWith(prefix)) { - fromUrl = fromUrl.slice(prefix.length); - } - - if (utils.isNpmUrl(fromUrl) && - ! utils.isNpmUrl(info.version)) { - info.version = fromUrl; - } - } - - const resolved = pkg._resolved || pkg.resolved; - if (resolved && resolved !== info.version) { - info.resolved = resolved; - } - - const integrity = pkg._integrity || pkg.integrity; - if (integrity) { - info.integrity = integrity; - } - - const deps = ls(files.pathJoin(pkgDir, "node_modules")); - if (deps && ! _.isEmpty(deps)) { - info.dependencies = deps; - } - }); - - return result; - } + dependencies = { + ...dependencies, + ...getInstalledDependenciesTreeFromPackageLock({ + packages, + dependencies: deps, + mappedDependencies: dependencies, + }), + }; + }); return { - lockfileVersion: 1, - dependencies: ls(files.pathJoin(dir, "node_modules")) + ...defaultReturn, + dependencies, }; } @@ -1012,7 +1090,7 @@ function getShrinkwrappedDependenciesTree(dir) { const shrinkwrap = JSON.parse(files.readFile( files.pathJoin(dir, 'npm-shrinkwrap.json') )); - shrinkwrap.lockfileVersion = 1; + shrinkwrap.lockfileVersion = LOCK_FILE_VERSION; return shrinkwrap; }; @@ -1050,7 +1128,7 @@ var getShrinkwrappedDependencies = function (dir) { return treeToDependencies(getShrinkwrappedDependenciesTree(dir)); }; -const installNpmModule = meteorNpm.installNpmModule = (name, version, dir) => { +const installNpmModule = meteorNpm.installNpmModule = async (name, version, dir) => { const installArg = utils.isNpmUrl(version) ? version : `${name}@${version}`; @@ -1058,7 +1136,7 @@ const installNpmModule = meteorNpm.installNpmModule = (name, version, dir) => { // We don't use npm.commands.install since we couldn't figure out // how to silence all output (specifically the installed tree which // is printed out with `console.log`) - const result = runNpmCommand(["install", installArg], dir); + const result = await runNpmCommand(["install", installArg], dir); if (! result.success) { const pkgNotFound = @@ -1080,7 +1158,7 @@ const installNpmModule = meteorNpm.installNpmModule = (name, version, dir) => { } // Recover by returning false from updateDependencies - throw new NpmFailure; + throw new NpmFailure(); } const pkgDir = files.pathJoin(dir, "node_modules", name); @@ -1107,19 +1185,19 @@ const installNpmModule = meteorNpm.installNpmModule = (name, version, dir) => { "The following file paths in the NPM module '" + name + "' have colons, ':', which won't work on Windows:\n" + firstTen.join("\n")); - throw new NpmFailure; + throw new NpmFailure(); } } }; -var installFromShrinkwrap = function (dir) { +var installFromShrinkwrap = async function (dir) { if (! files.exists(files.pathJoin(dir, "npm-shrinkwrap.json"))) { throw new Error( "Can't call `npm install` without a npm-shrinkwrap.json file present"); } // `npm install`, which reads npm-shrinkwrap.json. - var result = runNpmCommand(["install"], dir); + var result = await runNpmCommand(["install"], dir); if (! result.success) { buildmessage.error( @@ -1128,7 +1206,7 @@ var installFromShrinkwrap = function (dir) { ); // Recover by returning false from updateDependencies - throw new NpmFailure; + throw new NpmFailure(); } const nodeModulesDir = files.pathJoin(dir, "node_modules"); diff --git a/tools/isobuild/package-api.js b/tools/isobuild/package-api.js index 1571ba5b34..f5ae94029a 100644 --- a/tools/isobuild/package-api.js +++ b/tools/isobuild/package-api.js @@ -103,6 +103,7 @@ export class PackageAPI { }); this.releaseRecords = []; + this.pendingPromises = []; } // Called when this package wants to make another package be @@ -548,17 +549,29 @@ export class PackageAPI { { useMyCaller: true }); return; } - var releaseRecord = catalog.official.getReleaseVersion( - relInf[0], relInf[1]); - if (!releaseRecord) { - buildmessage.error("Unknown release "+ release, - { tags: { refreshCouldHelp: true } }); - } else { - self.releaseRecords.push(releaseRecord); - } + + let promise = catalog.official.getReleaseVersion(relInf[0], relInf[1]) + .then(releaseRecord => { + if (!releaseRecord) { + buildmessage.error("Unknown release "+ release, + { tags: { refreshCouldHelp: true } }); + } else { + self.releaseRecords.push(releaseRecord); + } + }); + + this.pendingPromises.push(promise); } } + // Internal method used by the meteor-tool + _waitForAsyncWork() { + let promises = this.pendingPromises; + this.pendingPromises = []; + + return Promise.all(promises); + } + // Export symbols from this package. // // @param symbols String (eg "Foo") or array of String diff --git a/tools/isobuild/package-cordova.js b/tools/isobuild/package-cordova.js index 98fcdc7dff..2af89154dd 100644 --- a/tools/isobuild/package-cordova.js +++ b/tools/isobuild/package-cordova.js @@ -1,13 +1,13 @@ import { ensureOnlyValidVersions } from "../utils/utils.js"; import buildmessage from "../utils/buildmessage.js"; -export class PackageCordova { /** * @summary Class of the 'Cordova' object visible in package.js * @locus package.js * @instanceName Cordova * @showInstanceName true */ +export class PackageCordova { constructor() { this._dependencies = null; } diff --git a/tools/isobuild/package-namespace.js b/tools/isobuild/package-namespace.js index 55222da02a..dc5bf7be9a 100644 --- a/tools/isobuild/package-namespace.js +++ b/tools/isobuild/package-namespace.js @@ -3,13 +3,13 @@ import { inCheckout } from "../fs/files"; import buildmessage from "../utils/buildmessage.js"; import packageVersionParser from "../packaging/package-version-parser.js"; -export class PackageNamespace { /** * @summary Class of the 'Package' object visible in package.js * @locus package.js * @instanceName Package * @showInstanceName true */ +export class PackageNamespace { constructor(packageSource) { this._packageSource = packageSource; this._fileAndDepLoader = null; diff --git a/tools/isobuild/package-npm.js b/tools/isobuild/package-npm.js index a2dd10d32c..0f4ca8e8e6 100644 --- a/tools/isobuild/package-npm.js +++ b/tools/isobuild/package-npm.js @@ -4,13 +4,13 @@ import NpmDiscards from "./npm-discards"; const nodeRequire = require; -export class PackageNpm { /** * @summary Class of the 'Npm' object visible in package.js * @locus package.js * @instanceName Npm * @showInstanceName true */ +export class PackageNpm { constructor() { // Files to be stripped from the installed NPM dependency tree. See // the Npm.strip comment below for further usage information. diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index 69279202b6..560d5341b7 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -485,7 +485,7 @@ Object.assign(PackageSource.prototype, { // Initialize a PackageSource from a package.js-style package directory. Uses // the name field provided and the name/test fields in the package.js file to - // figre out if this is a test package (load from onTest) or a use package + // figure out if this is a test package (load from onTest) or a use package // (load from onUse). // // name: name of the package. @@ -498,7 +498,7 @@ Object.assign(PackageSource.prototype, { return `PackageSource#initFromPackageDir for ${ options?.name || dir.split(files.pathSep).pop() }`; - }, function (dir, options) { + }, async function (dir, options) { var self = this; buildmessage.assertInCapture(); var isPortable = true; @@ -588,7 +588,7 @@ Object.assign(PackageSource.prototype, { const Cordova = new PackageCordova(); try { - files.runJavaScript(packageJsCode.toString('utf8'), { + await files.runJavaScript(packageJsCode.toString('utf8'), { filename: 'package.js', symbols: { Package, Npm, Cordova } }); @@ -663,7 +663,9 @@ Object.assign(PackageSource.prototype, { if (Package._fileAndDepLoader) { try { - buildmessage.markBoundary(Package._fileAndDepLoader)(api); + const marked = buildmessage.markBoundary(Package._fileAndDepLoader) + await marked(api); + await api._waitForAsyncWork(); } catch (e) { console.log(e.stack); // XXX should we keep this here -- or do we want broken // packages to fail silently? @@ -962,7 +964,7 @@ Object.assign(PackageSource.prototype, { // then sources will not be the same files used to bundle the app. let missingMainModule = !! mainModule && !sourceProcessorSet.isConflictsAllowed(); - + // Similar to the main module, when conflicts are allowed // these sources won't be used to build the app so the order // isn't important, and is difficult to accurately create when diff --git a/tools/isobuild/unibuild.js b/tools/isobuild/unibuild.js index fafb7a8543..b6cbc1e7de 100644 --- a/tools/isobuild/unibuild.js +++ b/tools/isobuild/unibuild.js @@ -93,7 +93,7 @@ export class Unibuild { }); } - static fromJSON(unibuildJson, { + static async fromJSON(unibuildJson, { isopack, // At some point we stopped writing 'kind's to the metadata file, so // default to main. @@ -209,7 +209,7 @@ export class Unibuild { } const nodeModulesDirectories = - NodeModulesDirectory.readDirsFromJSON(unibuildJson.node_modules, { + await NodeModulesDirectory.readDirsFromJSON(unibuildJson.node_modules, { packageName: isopack.name, sourceRoot: unibuildBasePath, // Rebuild binary npm packages if unibuild arch matches host arch. @@ -228,7 +228,7 @@ export class Unibuild { }); } - toJSON({ + async toJSON({ builder, unibuildDir, usesModules, @@ -252,14 +252,14 @@ export class Unibuild { // Figure out where the npm dependencies go. let node_modules = {}; - _.each(unibuild.nodeModulesDirectories, nmd => { + for (const nmd of Object.values(unibuild.nodeModulesDirectories)) { const bundlePath = _.has(npmDirsToCopy, nmd.sourcePath) - // We already have this npm directory from another unibuild. - ? npmDirsToCopy[nmd.sourcePath] - : npmDirsToCopy[nmd.sourcePath] = - nmd.getPreferredBundlePath("isopack"); - node_modules[bundlePath] = nmd.toJSON(); - }); + // We already have this npm directory from another unibuild. + ? npmDirsToCopy[nmd.sourcePath] + : npmDirsToCopy[nmd.sourcePath] = + nmd.getPreferredBundlePath("isopack"); + node_modules[bundlePath] = await nmd.toJSON(); + } const preferredPaths = Object.keys(node_modules); if (preferredPaths.length === 1) { @@ -307,19 +307,19 @@ export class Unibuild { } }); - _.each(concat, function (parts, type) { + for (const [type, parts] of Object.entries(concat)) { if (parts.length) { - builder.write(files.pathJoin(unibuildDir, type), { + await builder.write(files.pathJoin(unibuildDir, type), { data: Buffer.concat(concat[type], offset[type]) }); } - }); + } // Output other resources each to their own file - _.each(unibuild.resources, function (resource) { + for (const resource of unibuild.resources) { if (["head", "body"].includes(resource.type)) { // already did this one - return; + continue; } let data; @@ -330,20 +330,20 @@ export class Unibuild { } const generatedFilename = - builder.writeToGeneratedFilename( - files.pathJoin( - unibuildDir, - resource.servePath || resource.path, - ), - { data } - ); + await builder.writeToGeneratedFilename( + files.pathJoin( + unibuildDir, + resource.servePath || resource.path, + ), + { data } + ); if (! usesModules && resource.fileOptions && resource.fileOptions.lazy) { // Omit lazy resources from the unibuild JSON file, but only after // they are copied into the bundle (immediately above). - return; + continue; } unibuildJson.resources.push({ @@ -353,13 +353,13 @@ export class Unibuild { length: data.length, offset: 0, usesDefaultSourceProcessor: - resource.usesDefaultSourceProcessor || undefined, + resource.usesDefaultSourceProcessor || undefined, servePath: resource.servePath || undefined, path: resource.path || undefined, hash: resource._hash || resource.hash || undefined, fileOptions: resource.fileOptions || undefined }); - }); + } return unibuildJson; } diff --git a/tools/meteor-services/auth-client.js b/tools/meteor-services/auth-client.js index e9ee8bc411..382645f387 100644 --- a/tools/meteor-services/auth-client.js +++ b/tools/meteor-services/auth-client.js @@ -8,11 +8,14 @@ exports.AlreadyPrintedMessageError = function () {}; // Opens a DDP connection to a package server. Loads the packages needed for a // DDP connection, then calls DDP connect to the package server URL in config, // using a current user-agent header composed by http-helpers.js. -exports.openServiceConnection = function (serverUrl) { - return new ServiceConnection( - serverUrl, - {headers: {"User-Agent": httpHelpers.getUserAgent()}, - _dontPrintErrors: true}); +exports.openServiceConnection = async function (serverUrl) { + const connection = new ServiceConnection( + serverUrl, + {headers: {"User-Agent": httpHelpers.getUserAgent()}, + _dontPrintErrors: true}); + + await connection.init(); + return connection; }; @@ -47,10 +50,10 @@ exports.handleConnectionError = function (error, label) { // domain: the domain (ex: packages.meteor.com) // sessionType: the name of the connection (ex: "package-server") // -exports.loggedInConnection = function (url, domain, sessionType) { +exports.loggedInConnection = async function (url, domain, sessionType) { // Make sure that we are logged in with Meteor Accounts so that we can // do an OAuth flow. - if (auth.maybePrintRegistrationLink({onlyAllowIfRegistered: true})) { + if (await auth.maybePrintRegistrationLink({ onlyAllowIfRegistered: true })) { // Oops, we're logged in but with a deferred-registration account. // Message has already been printed. throw new exports.AlreadyPrintedMessageError; @@ -62,13 +65,13 @@ exports.loggedInConnection = function (url, domain, sessionType) { "Please log in with your Meteor developer account.", "If you don't have one,", "you can quickly create one at www.meteor.com."); - auth.doUsernamePasswordLogin({ retry: true }); + await auth.doUsernamePasswordLogin({ retry: true }); } - var conn = exports.openServiceConnection(url); - var accountsConfiguration = auth.getAccountsConfiguration(conn); + var conn = await exports.openServiceConnection(url); + var accountsConfiguration = await auth.getAccountsConfiguration(conn); try { - auth.loginWithTokenOrOAuth( + await auth.loginWithTokenOrOAuth( conn, accountsConfiguration, url, @@ -83,8 +86,8 @@ exports.loggedInConnection = function (url, domain, sessionType) { "It looks like you have been logged out!", "Please log in with your Meteor developer account. If you don't have", "one, you can quickly create one at www.meteor.com."); - auth.doUsernamePasswordLogin({ retry: true }); - auth.loginWithTokenOrOAuth( + await auth.doUsernamePasswordLogin({ retry: true }); + await auth.loginWithTokenOrOAuth( conn, accountsConfiguration, url, diff --git a/tools/meteor-services/auth.js b/tools/meteor-services/auth.js index 2ae814965c..dd593583ba 100644 --- a/tools/meteor-services/auth.js +++ b/tools/meteor-services/auth.js @@ -10,16 +10,16 @@ var Console = require('../console/console.js').Console; var auth = exports; -function loadDDP() { - return require("../tool-env/isopackets.js") - .loadIsopackage("ddp-client") - .DDP; +async function loadDDP() { + const isopackage = require("../tool-env/isopackets.js"); + const { DDP } = await isopackage.loadIsopackage("ddp-client"); + return DDP; } // Opens and returns a DDP connection to the accounts server. Remember // to close it when you're done with it! -var openAccountsConnection = function () { - return loadDDP().connect(config.getAuthDDPUrl(), { +var openAccountsConnection = async function () { + return (await loadDDP()).connect(config.getAuthDDPUrl(), { headers: { 'User-Agent': httpHelpers.getUserAgent() } }); }; @@ -28,12 +28,12 @@ var openAccountsConnection = function () { // that is a connection to the accounts server, which gets closed when // `f` returns or throws. var withAccountsConnection = function (f) { - return function (...args) { + return async function (...args) { var self = this; - var conn = openAccountsConnection(); + var conn = await openAccountsConnection(); args.push(conn); try { - var result = f.apply(self, args); + var result = await f.apply(self, args); } finally { conn.close(); } @@ -46,12 +46,17 @@ var withAccountsConnection = function (f) { // // XXX if we reconnect we won't reauthenticate. Fix that before using // this for long-lived connections. -var loggedInAccountsConnection = function (token) { - var connection = loadDDP().connect( +/** + * + * @param token + * @return {Promise<*>} + */ +var loggedInAccountsConnection = async function (token) { + var connection = (await loadDDP()).connect( config.getAuthDDPUrl() ); - return new Promise(function (resolve, reject) { + return await new Promise(function (resolve, reject) { connection.apply( 'login', [{ resume: token }], @@ -74,7 +79,7 @@ var loggedInAccountsConnection = function (token) { // Something else went wrong throw err; - }).await(); + }); }; // The accounts server has some wrapped methods that take and return @@ -91,13 +96,13 @@ var loggedInAccountsConnection = function (token) { // provided, one will be opened and then closed before returning. var sessionMethodCaller = function (methodName, options) { options = options || {}; - return function (...args) { + return async function (...args) { args.push({ session: auth.getSessionId(config.getAccountsDomain()) || null }); var timer; - var conn = options.connection || openAccountsConnection(); + var conn = options.connection || await openAccountsConnection(); function cleanUp() { timer && clearTimeout(timer); @@ -133,7 +138,7 @@ var sessionMethodCaller = function (methodName, options) { cleanUp(); throw err; - }).await(); + }); }; }; @@ -178,8 +183,7 @@ var writeSessionData = function (data) { // Atomically remove the old file (if any) and replace it with // the temporary file we just created. - files.rename(tempPath, sessionPath); - return; + return files.rename(tempPath, sessionPath); } }; @@ -216,7 +220,7 @@ var writeMeteorAccountsUsername = function (username) { var data = readSessionData(); var session = getSession(data, config.getAccountsDomain()); session.username = username; - writeSessionData(data); + return writeSessionData(data); }; // Given an object 'data' in the format returned by readSessionData, @@ -274,7 +278,7 @@ var removePendingRevoke = function (domain, tokenIds) { if (! session.pendingRevoke.length) { delete session.pendingRevoke; } - writeSessionData(data); + return writeSessionData(data); }; // If there are any logged out (pendingRevoke) tokens that haven't @@ -289,7 +293,7 @@ var removePendingRevoke = function (domain, tokenIds) { // session. just changes the error message. // - connection: an open connection to the accounts server. If not // provided, this function will open one itself. -var tryRevokeOldTokens = function (options) { +var tryRevokeOldTokens = async function (options) { options = Object.assign({ timeout: 5000 }, options || {}); @@ -313,8 +317,7 @@ var tryRevokeOldTokens = function (options) { warned = true; } }; - - _.each(domainsWithRevokedTokens, function (domain) { + for (const domain in domainsWithRevokedTokens) { var data = readSessionData(); var session = data.sessions[domain] || {}; var tokenIds = session.pendingRevoke || []; @@ -327,11 +330,11 @@ var tryRevokeOldTokens = function (options) { if (session.type === "meteor-account") { try { - sessionMethodCaller('revoke', { + await sessionMethodCaller('revoke', { timeout: options.timeout, connection: options.connection })(tokenIds); - removePendingRevoke(domain, tokenIds); + await removePendingRevoke(domain, tokenIds); } catch (err) { logoutFailWarning(domain); } @@ -340,16 +343,16 @@ var tryRevokeOldTokens = function (options) { // These are tokens from a legacy Galaxy prototype, which cannot be // revoked (because the prototype no longer exists), but we can at least // remove them from the file. - removePendingRevoke(domain, tokenIds); + await removePendingRevoke(domain, tokenIds); } else { // don't know how to revoke tokens of this type logoutFailWarning(domain); return; } - }); + } }; -var sendAuthorizeRequest = function (clientId, redirectUri, state) { +var sendAuthorizeRequest = async function (clientId, redirectUri, state) { var authCodeUrl = config.getOauthUrl() + "/authorize?" + querystring.stringify({ state: state, @@ -362,7 +365,7 @@ var sendAuthorizeRequest = function (clientId, redirectUri, state) { // redirect for us, but instead issue the second request ourselves, // since request would pass our credentials along to the redirected // URL. See comments in http-helpers.js. - var codeResult = httpHelpers.request({ + var codeResult = await httpHelpers.request({ url: authCodeUrl, method: 'POST', strictSSL: true, @@ -398,11 +401,11 @@ var sendAuthorizeRequest = function (clientId, redirectUri, state) { // All options are required. // // Throws an error if the login is not successful. -var oauthFlow = function (conn, options) { +var oauthFlow = async function (conn, options) { var crypto = require('crypto'); var credentialToken = crypto.randomBytes(16).toString('hex'); - var authorizeResult = sendAuthorizeRequest( + var authorizeResult = await sendAuthorizeRequest( options.clientId, options.redirectUri, credentialToken @@ -412,7 +415,7 @@ var oauthFlow = function (conn, options) { // credential secret (instead of a bunch of code that communicates the // credential secret somewhere else); this should be temporary until // we give this a nicer name and make it not just test only. - var redirectResult = httpHelpers.request({ + var redirectResult = await httpHelpers.request({ url: authorizeResult.location + '&only_credential_secret_for_test=1', method: 'GET', strictSSL: true @@ -427,7 +430,7 @@ var oauthFlow = function (conn, options) { } // XXX tokenId??? - var loginResult = conn.apply('login', [{ + var loginResult = await conn.apply('login', [{ oauth: { credentialToken: credentialToken, credentialSecret: response.body @@ -439,7 +442,7 @@ var oauthFlow = function (conn, options) { var session = getSession(data, options.domain); ensureSessionType(session, options.sessionType); session.token = loginResult.token; - writeSessionData(data); + await writeSessionData(data); return true; } else { throw new Error('login-failed'); @@ -457,7 +460,7 @@ var oauthFlow = function (conn, options) { // error message to stderr if the login fails // - connection: an open connection to the accounts server. If not // provided, this function will open its own connection. -var doInteractivePasswordLogin = function (options) { +var doInteractivePasswordLogin = async function (options) { var loginData = {}; if (_.has(options, 'username')) { @@ -478,7 +481,7 @@ var doInteractivePasswordLogin = function (options) { } }; - var conn = options.connection || openAccountsConnection(); + var conn = options.connection || await openAccountsConnection(); var maybeCloseConnection = function () { if (! options.connection) { @@ -488,7 +491,7 @@ var doInteractivePasswordLogin = function (options) { while (true) { if (! _.has(loginData, 'password')) { - loginData.password = Console.readLine({ + loginData.password = await Console.readLine({ echo: false, prompt: "Password: ", stream: process.stderr @@ -496,11 +499,14 @@ var doInteractivePasswordLogin = function (options) { } try { - var result = conn.call('login', { - session: auth.getSessionId(config.getAccountsDomain()), - meteorAccountsLoginInfo: loginData, - clientInfo: utils.getAgentInfo() - }); + var result = await conn.callAsync( + "login", + { + session: auth.getSessionId(config.getAccountsDomain()), + meteorAccountsLoginInfo: loginData, + clientInfo: await utils.getAgentInfo(), + } + ); } catch (err) { } if (result && result.token) { @@ -530,21 +536,21 @@ var doInteractivePasswordLogin = function (options) { session.userId = result.id; session.token = result.token; session.tokenId = result.tokenId; - writeSessionData(data); + await writeSessionData(data); maybeCloseConnection(); return true; }; // options are the same as for doInteractivePasswordLogin, except without // username and email. -exports.doUsernamePasswordLogin = function (options) { +exports.doUsernamePasswordLogin = async function (options) { var username; do { - username = Console.readLine({ + username = (await Console.readLine({ prompt: "Username: ", stream: process.stderr - }).trim(); + })).trim(); } while (username.length === 0); return doInteractivePasswordLogin(Object.assign({}, options, { @@ -554,7 +560,7 @@ exports.doUsernamePasswordLogin = function (options) { exports.doInteractivePasswordLogin = doInteractivePasswordLogin; -exports.loginCommand = withAccountsConnection(function (options, +exports.loginCommand = withAccountsConnection(async function (options, connection) { var data = readSessionData(); @@ -563,12 +569,12 @@ exports.loginCommand = withAccountsConnection(function (options, var loginOptions = {}; if (options.email) { - loginOptions.email = Console.readLine({ + loginOptions.email = await Console.readLine({ prompt: "Email: ", stream: process.stderr }); } else { - loginOptions.username = Console.readLine({ + loginOptions.username = await Console.readLine({ prompt: "Username: ", stream: process.stderr }); @@ -576,12 +582,12 @@ exports.loginCommand = withAccountsConnection(function (options, loginOptions.connection = connection; - if (! doInteractivePasswordLogin(loginOptions)) { + if (! await doInteractivePasswordLogin(loginOptions)) { return 1; } } - tryRevokeOldTokens({ firstTry: true, connection: connection }); + await tryRevokeOldTokens({ firstTry: true, connection: connection }); data = readSessionData(); Console.error(); @@ -591,13 +597,13 @@ exports.loginCommand = withAccountsConnection(function (options, return 0; }); -exports.logoutCommand = function (options) { +exports.logoutCommand = async function (options) { var data = readSessionData(); var wasLoggedIn = !! loggedIn(data); logOutAllSessions(data); - writeSessionData(data); + await writeSessionData(data); - tryRevokeOldTokens({ firstTry: true }); + await tryRevokeOldTokens({ firstTry: true }); if (wasLoggedIn) { Console.error("Logged out."); @@ -618,7 +624,7 @@ exports.logoutCommand = function (options) { // if a caller wants to do its own error handling for invalid // credentials). Defaults to false. var alreadyPolledForRegistration = false; -exports.pollForRegistrationCompletion = function (options) { +exports.pollForRegistrationCompletion = async function (options) { if (alreadyPolledForRegistration) { return; } @@ -635,7 +641,7 @@ exports.pollForRegistrationCompletion = function (options) { // We are logged in but we don't yet have a username. Ask the server // if a username was chosen since we last checked. var username = null; - var connection = loggedInAccountsConnection(session.token); + var connection = await loggedInAccountsConnection(session.token); var timer; if (! connection) { @@ -645,12 +651,12 @@ exports.pollForRegistrationCompletion = function (options) { // will try to explicitly revoke the credential ourselves). if (! options.noLogout) { logOutSession(session); - writeSessionData(data); + await writeSessionData(data); } return; } - new Promise(function (resolve) { + return new Promise(function (resolve) { connection.call('getUsername', function (err, username) { // If anything went wrong, return null just as we would have if we // hadn't bothered to ask the server. @@ -663,17 +669,17 @@ exports.pollForRegistrationCompletion = function (options) { // Intentionally calling bindEnvironment on the .then callback rather // than the function that calls resolve. - }).then(fiberHelpers.bindEnvironment(function (username) { + }).then(fiberHelpers.bindEnvironment(async function (username) { connection.close(); clearTimeout(timer); if (username) { - writeMeteorAccountsUsername(username); + await writeMeteorAccountsUsername(username); } // We don't actually care about the result, just that the side-effects // of writeMeteorAccountsUsername happen. - })).await(); + })); }; exports.registrationUrl = function () { @@ -682,8 +688,8 @@ exports.registrationUrl = function () { return url; }; -exports.whoAmICommand = function (options) { - auth.pollForRegistrationCompletion(); +exports.whoAmICommand = async function (options) { + await auth.pollForRegistrationCompletion(); var data = readSessionData(); if (! loggedIn(data)) { @@ -716,11 +722,11 @@ exports.whoAmICommand = function (options) { // try to log the user into it. Returns true on success (user is now // logged in) or false on failure (user gave up, can't talk to // network..) -exports.registerOrLogIn = withAccountsConnection(function (connection) { +exports.registerOrLogIn = withAccountsConnection(async function (connection) { var result; // Get their email while (true) { - var email = Console.readLine({ + var email = await Console.readLine({ prompt: "Email: ", stream: process.stderr }); @@ -731,7 +737,7 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) { 'tryRegister', { connection: connection } ); - result = methodCaller(email, utils.getAgentInfo()); + result = await methodCaller(email, await utils.getAgentInfo()); break; } catch (err) { if (err.error === 400 && ! utils.validEmail(email)) { @@ -758,7 +764,7 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) { session.tokenId = result.tokenId; session.userId = result.userId; session.registrationUrl = result.registrationUrl; - writeSessionData(data); + await writeSessionData(data); return true; } else if (result.alreadyExisted && result.sentRegistrationEmail) { Console.error(); @@ -800,7 +806,7 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) { stopSpinner(); Console.error("Username: " + waitForRegistrationResult.username); - loginResult = doInteractivePasswordLogin({ + loginResult = await doInteractivePasswordLogin({ username: waitForRegistrationResult.username, retry: true, connection: connection @@ -809,7 +815,7 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) { } else if (result.alreadyExisted && result.username) { Console.error("\nLogging in as " + Console.command(result.username) + "."); - loginResult = doInteractivePasswordLogin({ + loginResult = await doInteractivePasswordLogin({ username: result.username, retry: true, connection: connection @@ -826,10 +832,10 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) { // options: firstTime, leadingNewline // returns true if it printed something -exports.maybePrintRegistrationLink = function (options) { +exports.maybePrintRegistrationLink = async function (options) { options = options || {}; - auth.pollForRegistrationCompletion(); + await auth.pollForRegistrationCompletion(); var data = readSessionData(); var session = getSession(data, config.getAccountsDomain()); @@ -895,7 +901,7 @@ exports.loggedInUsername = function () { return loggedIn(data) ? currentUsername(data) : false; }; -exports.getAccountsConfiguration = function (conn) { +exports.getAccountsConfiguration = async function (conn) { // Subscribe to the package server's service configurations so that we // can get the OAuth client ID to kick off the OAuth flow. var accountsConfiguration = null; @@ -903,7 +909,7 @@ exports.getAccountsConfiguration = function (conn) { // We avoid the overhead of creating a 'ddp-and-mongo' isopacket (or // always loading mongo whenever we load ddp) by just using the low-level // DDP client API here. - conn.connection.registerStore('meteor_accounts_loginServiceConfiguration', { + await conn.connection.registerStoreServer('meteor_accounts_loginServiceConfiguration', { update: function (msg) { if (msg.msg === 'added' && msg.fields && msg.fields.service === 'meteor-developer') { @@ -914,7 +920,7 @@ exports.getAccountsConfiguration = function (conn) { } }); - var serviceConfigurationsSub = conn.subscribeAndWait( + var serviceConfigurationsSub = await conn.subscribeAndWait( 'meteor.loginServiceConfiguration'); if (! accountsConfiguration || ! accountsConfiguration.clientId) { throw new Error('no-accounts-configuration'); @@ -926,11 +932,11 @@ exports.getAccountsConfiguration = function (conn) { // Given a ServiceConnection, log in with OAuth using Meteor developer // accounts. Assumes the user is already logged in to the developer // accounts server. -exports.loginWithTokenOrOAuth = function (conn, accountsConfiguration, +exports.loginWithTokenOrOAuth = async function (conn, accountsConfiguration, url, domain, sessionType) { var setUpOnReconnect = function () { conn.onReconnect = function () { - conn.apply('login', [{ + return conn.apply('login', [{ resume: auth.getSessionToken(domain) }], { wait: true }, function () { }); }; @@ -943,7 +949,7 @@ exports.loginWithTokenOrOAuth = function (conn, accountsConfiguration, var existingToken = auth.getSessionToken(domain); if (existingToken) { try { - loginResult = conn.apply('login', [{ + loginResult = await conn.apply('login', [{ resume: existingToken }], { wait: true }); } catch (err) { @@ -957,7 +963,7 @@ exports.loginWithTokenOrOAuth = function (conn, accountsConfiguration, if (loginResult && loginResult.token && loginResult.id) { // Success! - setUpOnReconnect(); + await setUpOnReconnect(); return; } } @@ -978,14 +984,14 @@ exports.loginWithTokenOrOAuth = function (conn, accountsConfiguration, if (! accountsConfiguration.loginStyle) { redirectUri = redirectUri + "?close"; } - loginResult = oauthFlow(conn, { + loginResult = await oauthFlow(conn, { clientId: clientId, redirectUri: redirectUri, domain: domain, sessionType: sessionType }); - setUpOnReconnect(); + await setUpOnReconnect(); }; exports.loggedInAccountsConnection = loggedInAccountsConnection; diff --git a/tools/meteor-services/deploy.js b/tools/meteor-services/deploy.js index 104c7f9427..f5b0454c58 100644 --- a/tools/meteor-services/deploy.js +++ b/tools/meteor-services/deploy.js @@ -82,7 +82,7 @@ const CAPABILITIES = ['showDeployMessages', 'canTransferAuthorization']; // derived from either a transport-level exception, the response // body, or a generic 'try again later' message, as appropriate -function deployRpc(options) { +async function deployRpc(options) { options = Object.assign({}, options); options.headers = Object.assign({}, options.headers || {}); if (options.headers.cookie) { @@ -100,7 +100,7 @@ function deployRpc(options) { options.qs.capabilities.push('willPollVersionStatus'); } - const deployURLBase = getDeployURL(options.site).await(); + const deployURLBase = await getDeployURL(options.site); if (options.printDeployURL) { Console.info("Talking to Galaxy servers at " + deployURLBase); @@ -115,7 +115,7 @@ function deployRpc(options) { // XXX: Reintroduce progress for upload try { - var result = request(Object.assign(options, { + var result = await request(Object.assign(options, { url: deployURLBase + '/' + options.operation + operand, method: options.method || 'GET', @@ -193,13 +193,13 @@ function deployRpc(options) { // accounts server but our authentication actually fails, then prompt // the user to log in with a username and password and then resend the // RPC. -function authedRpc(options) { +async function authedRpc(options) { var rpcOptions = Object.assign({}, options); var preflight = rpcOptions.preflight; delete rpcOptions.preflight; // Fetch auth info - var infoResult = deployRpc({ + var infoResult = await deployRpc({ operation: 'info', site: rpcOptions.site, expectPayload: [], @@ -221,7 +221,7 @@ function authedRpc(options) { // Our authentication didn't validate, so prompt the user to log in // again, and resend the RPC if the login succeeds. - var username = Console.readLine({ + var username = await Console.readLine({ prompt: "Username: ", stream: process.stderr }); @@ -229,8 +229,8 @@ function authedRpc(options) { username: username, suppressErrorMessage: true }; - if (doInteractivePasswordLogin(loginOptions)) { - return authedRpc(options); + if (await doInteractivePasswordLogin(loginOptions)) { + return await authedRpc(options); } else { return { statusCode: 403, @@ -241,7 +241,7 @@ function authedRpc(options) { if (infoResult.statusCode === 404) { // Doesn't exist, therefore not protected. - return preflight ? { } : deployRpc(rpcOptions); + return preflight ? { } : await deployRpc(rpcOptions); } if (infoResult.errorMessage) { @@ -253,7 +253,7 @@ function authedRpc(options) { // Not protected. // // XXX should prompt the user to claim the app (only if deploying?) - return preflight ? { } : deployRpc(rpcOptions); + return preflight ? { } : await deployRpc(rpcOptions); } if (info.protection === "account") { @@ -281,7 +281,7 @@ function authedRpc(options) { authorized: info.authorized }; } else { - return deployRpc(rpcOptions); + return await deployRpc(rpcOptions); } } @@ -409,7 +409,7 @@ async function pollForDeploy(pollingState, versionId, site, deployWithTokenProps } = pollingState; // Do a call to the version-status endpoint for the specified versionId - const versionStatusResult = deployRpc({ + const versionStatusResult = await deployRpc({ method: 'GET', operation: 'version-status', site, @@ -509,14 +509,14 @@ export async function bundleAndDeploy(options) { // they'll get an email prompt instead of a username prompt because // the command-line tool didn't have time to learn about their // username before the credential was expired. - pollForRegistrationCompletion({ + await pollForRegistrationCompletion({ noLogout: true }); const promptIfAuthFails = (loggedInUsername() !== null); // Check auth up front, rather than after the (potentially lengthy) // bundling process. - const preflight = authedRpc({ + const preflight = await authedRpc({ site: site, preflight: true, promptIfAuthFails: promptIfAuthFails, @@ -546,7 +546,7 @@ export async function bundleAndDeploy(options) { } const projectDir = options.projectContext.getProjectLocalDirectory(''); - const gitCommitHash = process.env.METEOR_GIT_COMMIT_HASH || findGitCommitHash(projectDir); + const gitCommitHash = process.env.METEOR_GIT_COMMIT_HASH || await findGitCommitHash(projectDir); const buildCache = options.projectContext.getBuildCache(); let isCacheBuildValid = options.isCacheBuildEnabled; @@ -580,7 +580,7 @@ export async function bundleAndDeploy(options) { if (options.isCacheBuildEnabled) { Console.info('Saving build in cache (--cache-build)...'); - options.projectContext.saveBuildCache({ + await options.projectContext.saveBuildCache({ buildDir, bundlePath, gitCommitHash @@ -590,10 +590,10 @@ export async function bundleAndDeploy(options) { Console.info('Preparing to build your app...'); var settings = null; - var messages = buildmessage.capture({ + var messages = await buildmessage.capture({ title: "preparing to deploy", rootPath: process.cwd() - }, function () { + }, async function () { if (options.settingsFile) { settings = getSettings(options.settingsFile); } @@ -606,7 +606,7 @@ export async function bundleAndDeploy(options) { } else { const bundler = require('../isobuild/bundler.js'); - const bundleResult = bundler.bundle({ + const bundleResult = await bundler.bundle({ projectContext: options.projectContext, outputPath: bundlePath, buildOptions: options.buildOptions, @@ -625,7 +625,7 @@ export async function bundleAndDeploy(options) { } if (options.recordPackageUsage) { - recordPackages({ + await recordPackages({ what: "sdk.deploy", projectContext: options.projectContext, site: site @@ -645,10 +645,10 @@ export async function bundleAndDeploy(options) { }; Console.info('Preparing to upload your app...'); - const result = buildmessage.enterJob({ + const result = await buildmessage.enterJob({ title: "uploading" - }, Profile("upload bundle", function () { - return authedRpc({ + }, Profile("upload bundle", async function () { + return await authedRpc({ method: 'POST', operation: 'deploy', site: site, @@ -701,13 +701,13 @@ export async function bundleAndDeploy(options) { return 0; }; -export function deleteApp(site) { +export async function deleteApp(site) { site = canonicalizeSite(site); if (! site) { return 1; } - var result = authedRpc({ + var result = await authedRpc({ method: 'DELETE', operation: 'deploy', site: site, @@ -732,8 +732,8 @@ export function deleteApp(site) { // messages. Returns the result of the RPC if successful, or null // otherwise (including if auth failed or if the user is not authorized // for this site). -function checkAuthThenSendRpc(site, operation, what) { - var preflight = authedRpc({ +async function checkAuthThenSendRpc(site, operation, what) { + var preflight = await authedRpc({ operation: operation, site: site, preflight: true, @@ -751,7 +751,7 @@ function checkAuthThenSendRpc(site, operation, what) { if (! isLoggedIn()) { // Maybe the user is authorized for this app but not logged in // yet, so give them a login prompt. - var loginResult = doUsernamePasswordLogin({ retry: true }); + var loginResult = await doUsernamePasswordLogin({ retry: true }); if (loginResult) { // Once we've logged in, retry the whole operation. We need to // do the preflight request again instead of immediately moving @@ -759,7 +759,7 @@ function checkAuthThenSendRpc(site, operation, what) { // logged-in user is authorized for this app, and if they // aren't, then we want to print the nice unauthorized error // message. - return checkAuthThenSendRpc(site, operation, what); + return await checkAuthThenSendRpc(site, operation, what); } else { // Shouldn't ever get here because we set the retry flag on the // login, but just in case. @@ -781,7 +781,7 @@ function checkAuthThenSendRpc(site, operation, what) { // User is authorized for the app; go ahead and do the actual RPC. - var result = authedRpc({ + var result = await authedRpc({ operation: operation, site: site, expectMessage: true, @@ -799,14 +799,14 @@ function checkAuthThenSendRpc(site, operation, what) { // On failure, prints a message to stderr and returns null. Otherwise, // returns a temporary authenticated Mongo URL allowing access to this // site's database. -export function temporaryMongoUrl(site) { +export async function temporaryMongoUrl(site) { site = canonicalizeSite(site); if (! site) { // canonicalizeSite printed an error return null; } - var result = checkAuthThenSendRpc(site, 'mongo', 'open a mongo connection'); + var result = await checkAuthThenSendRpc(site, 'mongo', 'open a mongo connection'); if (result !== null) { return result.message; @@ -815,13 +815,13 @@ export function temporaryMongoUrl(site) { } }; -export function listAuthorized(site) { +export async function listAuthorized(site) { site = canonicalizeSite(site); if (! site) { return 1; } - var result = deployRpc({ + var result = await deployRpc({ operation: 'info', site: site, expectPayload: [], @@ -859,14 +859,14 @@ export function listAuthorized(site) { }; // action is "add", "transfer" or "remove" -export function changeAuthorized(site, action, username) { +export async function changeAuthorized(site, action, username) { site = canonicalizeSite(site); if (! site) { // canonicalizeSite will have already printed an error return 1; } - var result = authedRpc({ + var result = await authedRpc({ method: 'POST', operation: 'authorized', site: site, @@ -889,8 +889,8 @@ export function changeAuthorized(site, action, username) { return 0; }; -export function listSites() { - var result = deployRpc({ +export async function listSites() { + var result = await deployRpc({ method: "GET", operation: "authorized-apps", promptIfAuthFails: true, @@ -932,7 +932,7 @@ const galaxyDiscoveryCache = new Map; // getDeployURL returns the a Promise for the base deploy URL for the given app. // "app" may be falsey for certain RPCs (eg meteor list-sites). -function getDeployURL(site) { +async function getDeployURL(site) { // Always trust explicitly configuration via env. if (process.env.DEPLOY_HOSTNAME) { return Promise.resolve(addScheme(process.env.DEPLOY_HOSTNAME.trim())); @@ -953,8 +953,8 @@ function getDeployURL(site) { } // Otherwise, try https first, then http, then just use the default. - const p = discoverGalaxy(site, "https") - .catch(() => discoverGalaxy(site, "http")) + const p = await discoverGalaxy(site, "https") + .catch(async () => await discoverGalaxy(site, "http")) .catch(() => defaultURL); galaxyDiscoveryCache.set(site, p); return p; @@ -967,7 +967,7 @@ async function discoverGalaxy(site, scheme) { scheme + "://" + site + "/.well-known/meteor/deploy-url"; // If httpHelpers.request throws, the returned Promise will reject, which is // fine. - const { response, body } = request({ + const { response, body } = await request({ url: discoveryURL, json: true, strictSSL: true, diff --git a/tools/meteor-services/service-connection.js b/tools/meteor-services/service-connection.js index 6fe7cd0096..d942e5d268 100644 --- a/tools/meteor-services/service-connection.js +++ b/tools/meteor-services/service-connection.js @@ -1,4 +1,5 @@ import { loadIsopackage } from '../tool-env/isopackets.js'; +import {clearScreenDown} from "readline"; var files = require('../fs/files'); var fiberHelpers = require("../utils/fiber-helpers.js"); @@ -24,86 +25,93 @@ var fiberHelpers = require("../utils/fiber-helpers.js"); // var ServiceConnection = function (endpointUrl, options) { const self = this; - const ddpClient = loadIsopackage('ddp-client'); // ServiceConnection never should retry connections: just one TCP connection - // is enough, and any errors on it should be detected promptly. - options = Object.assign({}, options, { - // We found that this was likely to time out with the DDP default of 10s, - // especially if the CPU is churning on bundling (eg, for the stats - // connection which we start in parallel with bundling). - connectTimeoutMs: 30000, - // Disable client->server heartbeats for service connections. Users with - // slow internet connections were seeing heartbeat timeouts because the - // heartbeats were buried behind large responses (eg - // https://github.com/meteor/meteor/issues/2777). - heartbeatInterval: 0, - retry: false, - onConnected: function () { - self.connected = true; - if (! self.currentPromise) { - throw Error("nobody waiting for connection?"); - } - if (self.currentPromise !== connectPromise) { - throw Error("waiting for something that isn't connection?"); - } - self.currentPromise = null; - connectPromise.resolve(); - connectPromise.resolve = null; - } - }); + // is enough, and any errors on it should be detected promptly.] + self.options = options; + self.endpointUrl = endpointUrl; + if (process.env.CAFILE) { options.npmFayeOptions = { ca: files.readFile(process.env.CAFILE) - } + }; } - - self.connection = ddpClient.DDP.connect(endpointUrl, options); - - // Wait until we have some sort of initial connection or error (including the - // 10-second timeout built into our DDP client). - - var connectPromise = self.currentPromise = - fiberHelpers.makeFulfillablePromise(); - - self.connection._stream.on('disconnect', function (error) { - self.connected = false; - if (error && error.errorType === "DDP.ForcedReconnectError") { - // OK, we requested this, probably due to version negotiation failure. - // - // This ought to have happened before we successfully connect, unless - // somebody adds other calls to forced reconnect to Meteor... - if (! connectPromise.resolve) { - throw Error("disconnect before connect?"); - } - // Otherwise, ignore this error. We're going to reconnect! - return; - } - // Are we waiting to connect or for the result of a method apply or a - // subscribeAndWait? If so, disconnecting is a problem. - if (self.currentPromise) { - var promise = self.currentPromise; - self.currentPromise = null; - promise.reject( - error || new ddpClient.DDP.ConnectionError( - "DDP disconnected while connection in progress") - ); - } else if (error) { - // We got some sort of error with nobody listening for it; handle it. - // XXX probably have a better way to handle it than this - throw error; - } - }); - - connectPromise.await(); }; Object.assign(ServiceConnection.prototype, { + init: async function() { + const self = this; + const ddpClient = await loadIsopackage('ddp-client'); + + const options = Object.assign({}, self.options, { + // We found that this was likely to time out with the DDP default of 10s, + // especially if the CPU is churning on bundling (eg, for the stats + // connection which we start in parallel with bundling). + connectTimeoutMs: 30000, + // Disable client->server heartbeats for service connections. Users with + // slow internet connections were seeing heartbeat timeouts because the + // heartbeats were buried behind large responses (eg + // https://github.com/meteor/meteor/issues/2777). + heartbeatInterval: 0, + retry: false, + onConnected: function () { + self.connected = true; + if (! self.currentPromise) { + throw Error("nobody waiting for connection?"); + } + if (self.currentPromise !== connectPromise) { + throw Error("waiting for something that isn't connection?"); + } + self.currentPromise = null; + connectPromise.resolve(); + connectPromise.resolve = null; + } + }); + + self.connection = ddpClient.DDP.connect(self.endpointUrl, options); + + // Wait until we have some sort of initial connection or error (including the + // 10-second timeout built into our DDP client). + + var connectPromise = self.currentPromise = + fiberHelpers.makeFulfillablePromise(); + + self.connection._stream.on('disconnect', function (error) { + self.connected = false; + if (error && error.errorType === "DDP.ForcedReconnectError") { + // OK, we requested this, probably due to version negotiation failure. + // + // This ought to have happened before we successfully connect, unless + // somebody adds other calls to forced reconnect to Meteor... + if (! connectPromise.resolve) { + throw Error("disconnect before connect?"); + } + // Otherwise, ignore this error. We're going to reconnect! + return; + } + // Are we waiting to connect or for the result of a method apply or a + // subscribeAndWait? If so, disconnecting is a problem. + if (self.currentPromise) { + var promise = self.currentPromise; + self.currentPromise = null; + promise.reject( + error || new ddpClient.DDP.ConnectionError( + "DDP disconnected while connection in progress") + ); + } else if (error) { + // We got some sort of error with nobody listening for it; handle it. + // XXX probably have a better way to handle it than this + throw error; + } + }); + + await connectPromise; + }, call: function (name, ...args) { return this.apply(name, args); }, - apply: function (...args) { + apply: async function (...args) { var self = this; if (self.currentPromise) { @@ -128,12 +136,12 @@ Object.assign(ServiceConnection.prototype, { self.connection.apply(...args); - return self.currentPromise.await(); + return await self.currentPromise; }, // XXX derived from _subscribeAndWait in ddp_connection.js // -- but with a different signature.. - subscribeAndWait: function (...args) { + subscribeAndWait: async function (...args) { var self = this; if (self.currentPromise) { @@ -165,7 +173,7 @@ Object.assign(ServiceConnection.prototype, { }); var sub = self.connection.subscribe(...args); - subPromise.await(); + await subPromise; return sub; }, diff --git a/tools/meteor-services/stats.js b/tools/meteor-services/stats.js index bf02f116eb..c9c8439d72 100644 --- a/tools/meteor-services/stats.js +++ b/tools/meteor-services/stats.js @@ -1,4 +1,3 @@ -var Fiber = require("fibers"); var _ = require("underscore"); var config = require('./config.js'); @@ -23,7 +22,7 @@ var packageList = function (projectContext) { name: name, version: info.version, local: info.kind === 'local', - direct: !! projectContext.projectConstraintsFile.getConstraint(name) + direct: !!projectContext.projectConstraintsFile.getConstraint(name) }); }); return versions; @@ -36,11 +35,12 @@ var packageList = function (projectContext) { // from this before yielding. // - site: If it's a deploy, the name of the site ("foo.meteor.com") that we're // deploying to. -var recordPackages = function (options) { +var recordPackages = async function (options) { // Before doing anything, look at the app's dependencies to see if the // opt-out package is there; if present, we don't record any stats. var packages = packageList(options.projectContext); - if (_.findWhere(packages, { name: OPT_OUT_PACKAGE_NAME })) { + if (_.findWhere(packages, { name: OPT_OUT_PACKAGE_NAME }) || + process.env.DO_NOT_TRACK) { // Print some output for the 'report-stats' self-test. if (process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) { process.stdout.write("PACKAGE STATS NOT SENT\n"); @@ -56,67 +56,64 @@ var recordPackages = function (options) { // This also gives it its own buildmessage state. // However, we do make sure to have already extracted the package list from // projectContext, since it might mutate out from under us otherwise. - Fiber(function () { + var details = { + what: options.what, + userAgent: httpHelpers.getUserAgent(), + sessionId: auth.getSessionId(config.getAccountsDomain()), + site: options.site + }; - var details = { - what: options.what, - userAgent: httpHelpers.getUserAgent(), - sessionId: auth.getSessionId(config.getAccountsDomain()), - site: options.site - }; + try { + var conn = await connectToPackagesStatsServer(); + var accountsConfiguration = await auth.getAccountsConfiguration(conn); - try { - var conn = connectToPackagesStatsServer(); - var accountsConfiguration = auth.getAccountsConfiguration(conn); - - if (auth.isLoggedIn()) { - try { - auth.loginWithTokenOrOAuth( - conn, - accountsConfiguration, - config.getPackageStatsServerUrl(), - config.getPackageStatsServerDomain(), - "package-stats-server" - ); - } catch (err) { - // Do nothing. If we can't log in, we should continue and report - // stats anonymously. - // - // We log other errors with `logErrorIfInCheckout`, but login - // errors can happen in normal operation when nothing is wrong - // (e.g. login token expired or revoked) so we don't log them. - } + if (auth.isLoggedIn()) { + try { + await auth.loginWithTokenOrOAuth( + conn, + accountsConfiguration, + config.getPackageStatsServerUrl(), + config.getPackageStatsServerDomain(), + "package-stats-server" + ); + } catch (err) { + // Do nothing. If we can't log in, we should continue and report + // stats anonymously. + // + // We log other errors with `logErrorIfInCheckout`, but login + // errors can happen in normal operation when nothing is wrong + // (e.g. login token expired or revoked) so we don't log them. } - - var result = conn.call("recordAppPackages", - appIdentifier, - packages, - details); - - // If the stats server sent us a new session, save it for use on - // subsequent requests. - if (result && result.newSessionId) { - auth.setSessionId(config.getAccountsDomain(), result.newSessionId); - } - - if (process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) { - // Print some output for the 'report-stats' self-test. - process.stdout.write("PACKAGE STATS SENT\n"); - } - } catch (err) { - logErrorIfInCheckout(err); - // Do nothing. A failure to record package stats shouldn't be - // visible to the end user and shouldn't affect whatever command - // they are running. - } finally { - conn && conn.close(); } - }).run(); + + var result = await conn.call("recordAppPackages", + appIdentifier, + packages, + details); + + // If the stats server sent us a new session, save it for use on + // subsequent requests. + if (result && result.newSessionId) { + auth.setSessionId(config.getAccountsDomain(), result.newSessionId); + } + + if (process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) { + // Print some output for the 'report-stats' self-test. + process.stdout.write("PACKAGE STATS SENT\n"); + } + } catch (err) { + logErrorIfInCheckout(err); + // Do nothing. A failure to record package stats shouldn't be + // visible to the end user and shouldn't affect whatever command + // they are running. + } finally { + conn && conn.close(); + } }; var logErrorIfInCheckout = function (err) { if ((Console.isInteractive() && files.inCheckout()) - || process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) { + || process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) { Console.warn("Failed to record package usage."); Console.warn( "(This error is hidden when you are not running Meteor from a", @@ -147,11 +144,14 @@ var getPackagesForAppIdInTest = function (projectContext) { return result; }; -var connectToPackagesStatsServer = function () { - return new ServiceConnection( +var connectToPackagesStatsServer = async function () { + const sc = new ServiceConnection( config.getPackageStatsServerUrl(), - {_dontPrintErrors: true} + { _dontPrintErrors: true } ); + + await sc.init(); + return sc; }; exports.recordPackages = recordPackages; diff --git a/tools/node-process-warnings.js b/tools/node-process-warnings.js new file mode 100644 index 0000000000..9dbc7919dd --- /dev/null +++ b/tools/node-process-warnings.js @@ -0,0 +1,22 @@ +const originalEmitWarning = process.emitWarning; + +process.emitWarning = function (message) { + /* + * A warning was introduced in Node 22: + * + * "The `punycode` module is deprecated. Please use a userland alternative instead." + * + * The problem is that punycode is deeply integrated in the Node system. It's not a + * simple direct dependency. + * + * Check these issues for more details: + * https://github.com/mathiasbynens/punycode.js/issues/137 + * https://stackoverflow.com/questions/68774489/punycode-is-deprecated-in-npm-what-should-i-replace-it-with/78946745 + * + * This warning was, besides being annoying, breaking our tests. + */ + if (message.includes("punycode")) { + return; + } + return originalEmitWarning(message); +}; diff --git a/tools/packaging/catalog/catalog-local.js b/tools/packaging/catalog/catalog-local.js index dda1ba5baa..d56335652a 100644 --- a/tools/packaging/catalog/catalog-local.js +++ b/tools/packaging/catalog/catalog-local.js @@ -1,4 +1,3 @@ - var _ = require('underscore'); var buildmessage = require('../../utils/buildmessage.js'); var files = require('../../fs/files'); @@ -71,6 +70,10 @@ const KNOWN_ISOBUILD_FEATURE_PACKAGES = { // allowed to return a Promise instead of having to await async // compilation using fibers and/or futures. 'isobuild:async-plugins': ['1.6.1'], + + // This package requires functionality introduced in meteor-tools@3.0 + // to enable using top level await + 'isobuild:top-level-await': ['3.0.0'], } // LocalCatalog represents packages located in the application's @@ -135,7 +138,7 @@ Object.assign(LocalCatalog.prototype, { // are package source trees. Takes precedence over packages found // via localPackageSearchDirs. // - buildingIsopackets: true if we are building isopackets - initialize(options) { + async initialize(options) { var self = this; buildmessage.assertInCapture(); @@ -168,8 +171,8 @@ Object.assign(LocalCatalog.prototype, { self.explicitlyAddedLocalPackageDirs = [], ); - self._computeEffectiveLocalPackages(); - self._loadLocalPackages(options.buildingIsopackets); + await self._computeEffectiveLocalPackages(); + await self._loadLocalPackages(options.buildingIsopackets); self.initialized = true; }, @@ -313,7 +316,7 @@ Object.assign(LocalCatalog.prototype, { self.effectiveLocalPackageDirs = []; - buildmessage.enterJob("looking for packages", function () { + return buildmessage.enterJob("looking for packages", function () { _.each(self.explicitlyAddedLocalPackageDirs, (explicitDir) => { const packageJsPath = files.pathJoin(explicitDir, "package.js"); const packageJsHash = optimisticHashOrNull(packageJsPath); @@ -375,7 +378,7 @@ Object.assign(LocalCatalog.prototype, { }); }, - _loadLocalPackages(buildingIsopackets) { + async _loadLocalPackages(buildingIsopackets) { var self = this; buildmessage.assertInCapture(); @@ -389,12 +392,12 @@ Object.assign(LocalCatalog.prototype, { // (note: this is the behavior that we want for overriding things in // checkout. It is not clear that you get good UX if you have two packages // with the same name in your app. We don't check that.) - var initSourceFromDir = function (packageDir, definiteName) { - var packageSource = new PackageSource; - buildmessage.enterJob({ + var initSourceFromDir = async function (packageDir, definiteName) { + var packageSource = new PackageSource(); + await buildmessage.enterJob({ title: "reading package from `" + packageDir + "`", rootPath: packageDir - }, function () { + }, async function () { var initFromPackageDirOptions = { buildingIsopackets: !! buildingIsopackets }; @@ -404,7 +407,7 @@ Object.assign(LocalCatalog.prototype, { if (definiteName) { initFromPackageDirOptions.name = definiteName; } - packageSource.initFromPackageDir(packageDir, initFromPackageDirOptions); + await packageSource.initFromPackageDir(packageDir, initFromPackageDirOptions); if (buildmessage.jobHasMessages()) return; // recover by ignoring @@ -418,6 +421,12 @@ Object.assign(LocalCatalog.prototype, { if (_.has(self.packages, name)) return; + const dependencies = packageSource.getDependencyMetadata({ logError: true }); + + if (buildmessage.jobHasMessages()) { + return; // recover by ignoring + } + self.packages[name] = { packageSource: packageSource, packageRecord: { @@ -434,7 +443,7 @@ Object.assign(LocalCatalog.prototype, { publishedBy: null, description: packageSource.metadata.summary, git: packageSource.metadata.git, - dependencies: packageSource.getDependencyMetadata(), + dependencies, source: null, lastUpdated: null, published: null, @@ -454,17 +463,17 @@ Object.assign(LocalCatalog.prototype, { // marked as test packages by package source, so we will not recurse // infinitely), then process that too. if (!packageSource.isTest && packageSource.testName) { - initSourceFromDir(packageSource.sourceRoot, packageSource.testName); + await initSourceFromDir(packageSource.sourceRoot, packageSource.testName); } }); }; // Load the package sources for packages and their tests into // self.packages. - buildmessage.enterJob('initializing packages', function() { - _.each(self.effectiveLocalPackageDirs, function (dir) { - initSourceFromDir(dir); - }); + await buildmessage.enterJob('initializing packages', async function() { + for (const dir of self.effectiveLocalPackageDirs) { + await initSourceFromDir(dir); + } }); }, diff --git a/tools/packaging/catalog/catalog-remote.js b/tools/packaging/catalog/catalog-remote.js index 5ad6af79a3..85b0fefc12 100644 --- a/tools/packaging/catalog/catalog-remote.js +++ b/tools/packaging/catalog/catalog-remote.js @@ -39,7 +39,7 @@ var Mutex = function () { }; Object.assign(Mutex.prototype, { - lock: function () { + lock: async function () { var self = this; while (true) { @@ -48,13 +48,13 @@ Object.assign(Mutex.prototype, { return; } - new Promise(function (resolve) { + await new Promise(function (resolve) { self._resolvers.push(resolve); - }).await(); + }); } }, - unlock: function () { + unlock: async function () { var self = this; if (!self._locked) { @@ -64,7 +64,7 @@ Object.assign(Mutex.prototype, { self._locked = false; var resolve = self._resolvers.shift(); if (resolve) { - resolve(); + await resolve(); } } }); @@ -91,7 +91,7 @@ Object.assign(Txn.prototype, { }, // Start a transaction - begin: function (mode) { + begin: async function (mode) { var self = this; // XXX: Use DEFERRED mode? @@ -101,12 +101,12 @@ Object.assign(Txn.prototype, { throw new Error("Transaction already started"); } - self.db._execute("BEGIN " + mode + " TRANSACTION"); + await self.db._execute("BEGIN " + mode + " TRANSACTION"); self.started = true; }, // Releases resources from the transaction; Rollback if commit not already called. - close: function () { + close: async function () { var self = this; if (self.closed) { @@ -117,16 +117,16 @@ Object.assign(Txn.prototype, { return; } - self.db._execute("ROLLBACK TRANSACTION"); + await self.db._execute("ROLLBACK TRANSACTION"); self.committed = false; self.closed = true; }, // Commits the transaction. close() will then be a no-op - commit: function () { + commit: async function () { var self = this; - self.db._execute("END TRANSACTION"); + await self.db._execute("END TRANSACTION"); self.committed = true; self.closed = true; } @@ -141,25 +141,26 @@ var Db = function (dbFile, options) { self._prepared = {}; self._transactionMutex = new Mutex(); - - self._db = self._retry(function () { - return self.open(dbFile); - }); - - self._retry(function () { - self._execute(`PRAGMA journal_mode=${JOURNAL_MODE}`); - }); }; Object.assign(Db.prototype, { + init: async function() { + const self = this; + self._db = await self._retry(function () { + return self.open(self._dbFile); + }); + await self._retry(function () { + return self._execute(`PRAGMA journal_mode=${JOURNAL_MODE}`); + }); + }, // TODO: Move to utils? - _retry: function (f, options) { + _retry: async function (f, options) { options = Object.assign({ maxAttempts: 3, delay: 500}, options || {}); for (var attempt = 1; attempt <= options.maxAttempts; attempt++) { try { - return f(); + return await f(); } catch (err) { if (attempt < options.maxAttempts) { Console.warn("Retrying after error", err); @@ -169,40 +170,40 @@ Object.assign(Db.prototype, { } if (options.delay) { - utils.sleepMs(options.delay); + await utils.sleepMs(options.delay); } } }, // Runs functions serially, in a mutex - _serialize: function (f) { + _serialize: async function (f) { var self = this; try { - self._transactionMutex.lock(); - return f(); + await self._transactionMutex.lock(); + return await f(); } finally { - self._transactionMutex.unlock(); + await self._transactionMutex.unlock(); } }, // Do not call any other methods on this object after calling this one. // This yields. - closePermanently: function () { + closePermanently: async function () { var self = this; - self._closePreparedStatements(); + await self._closePreparedStatements(); var db = self._db; self._db = null; - new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.close(err => err ? reject(err) : resolve()); - }).await(); + }); }, // Runs the function inside a transaction block - runInTransaction: function (action) { + runInTransaction: async function (action) { var self = this; - var runOnce = Profile("sqlite query", function () { + var runOnce = Profile("sqlite query", async function () { var txn = new Txn(self); var t1 = Date.now(); @@ -211,15 +212,15 @@ Object.assign(Db.prototype, { var result = null; var resultError = null; - txn.begin(); + await txn.begin(); try { - result = action(txn); - txn.commit(); + result = await action(txn); + await txn.commit(); } catch (err) { resultError = err; } finally { try { - txn.close(); + await txn.close(); } catch (e) { // We don't have a lot of options here... Console.warn("Error closing transaction", e); @@ -243,7 +244,7 @@ Object.assign(Db.prototype, { for (var attempt = 0; ; attempt++) { try { - return self._serialize(runOnce); + return await self._serialize(runOnce); } catch (err) { var retry = false; // Grr... doesn't expose error code; must string-match @@ -261,7 +262,7 @@ Object.assign(Db.prototype, { // Wait on average BUSY_RETRY_INTERVAL, but randomize to avoid thundering herd var t = (Math.random() + 0.5) * BUSY_RETRY_INTERVAL; - utils.sleepMs(t); + await utils.sleepMs(t); } }, @@ -282,13 +283,13 @@ Object.assign(Db.prototype, { // Runs a query synchronously, returning all rows // Hidden to enforce transaction usage - _query: function (sql, params) { + _query: async function (sql, params) { var self = this; var prepared = null; var prepare = self._autoPrepare && !_.isEmpty(params); if (prepare) { - prepared = self._prepareWithCache(sql); + prepared = await self._prepareWithCache(sql); } if (DEBUG_SQL) { @@ -297,7 +298,7 @@ Object.assign(Db.prototype, { //Console.debug("Executing SQL ", sql, params); - var rows = new Promise((resolve, reject) => { + var rows = await new Promise((resolve, reject) => { function callback(err, rows) { err ? reject(err) : resolve(rows); } @@ -307,7 +308,7 @@ Object.assign(Db.prototype, { } else { self._db.all(sql, params, callback); } - }).await(); + }); if (DEBUG_SQL) { var t2 = Date.now(); @@ -320,9 +321,9 @@ Object.assign(Db.prototype, { return rows; }, - // Runs a query synchronously, returning no rows + // Runs a query, returning no rows // Hidden to enforce transaction usage - _execute: function (sql, params) { + _execute: async function (sql, params) { var self = this; var prepared = null; @@ -335,7 +336,7 @@ Object.assign(Db.prototype, { // entirely.) var prepare = self._autoPrepare && !_.isEmpty(params); if (prepare) { - prepared = self._prepareWithCache(sql); + prepared = await self._prepareWithCache(sql); } if (DEBUG_SQL) { @@ -344,7 +345,7 @@ Object.assign(Db.prototype, { //Console.debug("Executing SQL ", sql, params); - var ret = new Promise(function (resolve, reject) { + var ret = await new Promise(function (resolve, reject) { function callback(err) { err ? reject(err) : resolve({ // Yes, lastID & changes are on this(!) @@ -358,7 +359,7 @@ Object.assign(Db.prototype, { } else { self._db.run(sql, params, callback); } - }).await(); + }); if (DEBUG_SQL) { var t2 = Date.now(); @@ -371,17 +372,17 @@ Object.assign(Db.prototype, { }, // Prepares the statement, caching the result - _prepareWithCache: function (sql) { + _prepareWithCache: async function (sql) { var self = this; var prepared = self._prepared[sql]; if (!prepared) { //Console.debug("Preparing statement: ", sql); - new Promise(function (resolve, reject) { + await new Promise(function (resolve, reject) { prepared = self._db.prepare(sql, function (err) { err ? reject(err) : resolve(); }); - }).await(); + }); self._prepared[sql] = prepared; } @@ -391,25 +392,24 @@ Object.assign(Db.prototype, { // Close any cached prepared statements - _closePreparedStatements: function () { + _closePreparedStatements: async function () { var self = this; var prepared = self._prepared; self._prepared = {}; - _.each(prepared, function (statement) { - var err = new Promise(function (resolve) { + for (const statement of Object.values(prepared)) { + var err = await new Promise(function (resolve) { // We resolve the promise with an error instead of rejecting it, // because we don't want to throw. statement.finalize(resolve); - }).await(); + }); if (err) { Console.warn("Error finalizing statement ", err); } - }); + } } - }); @@ -441,9 +441,9 @@ Object.assign(Table.prototype, { return "(" + _.times(n, function () { return "?" }).join(",") + ")"; }, - find: function (txn, id) { + find: async function (db, id) { var self = this; - var rows = txn.query(self._selectQuery, [ id ]); + var rows = await db._query(self._selectQuery, [ id ]); if (rows.length !== 0) { if (rows.length !== 1) { throw new Error("Corrupt database (PK violation)"); @@ -453,17 +453,17 @@ Object.assign(Table.prototype, { return undefined; }, - upsert: function (txn, objects) { + upsert: async function (txn, objects) { var self = this; // XXX: Use sqlite upsert // XXX: Speculative insert // XXX: Fix transaction logic so we always roll back - _.each(objects, function (o) { + for (const o of objects) { var id = o._id; - var rows = txn.query(self._selectQuery, [ id ]); + var rows = await txn.query(self._selectQuery, [ id ]); if (rows.length !== 0) { - var deleteResults = txn.execute(self._deleteQuery, [ id ]); + var deleteResults = await txn.execute(self._deleteQuery, [ id ]); if (deleteResults.changes !== 1) { throw new Error("Unable to delete row: " + id); } @@ -475,11 +475,11 @@ Object.assign(Table.prototype, { if (! self.noContentColumn) { row.push(JSON.stringify(o)); } - txn.execute(self._insertQuery, row); - }); + await txn.execute(self._insertQuery, row); + } }, - createTable: function (txn) { + createTable: async function (txn) { var self = this; var sql = 'CREATE TABLE IF NOT EXISTS ' + self.name + '('; @@ -496,7 +496,7 @@ Object.assign(Table.prototype, { sql += ", content STRING"; } sql += ")"; - txn.execute(sql); + await txn.execute(sql); //sql = "CREATE INDEX IF NOT EXISTS idx_" + self.name + "_id ON " + self.name + "(_id)"; //txn.execute(sql); @@ -530,14 +530,14 @@ Object.assign(RemoteCatalog.prototype, { // are closed (eg to ensure that all writes have been flushed from the '-wal' // file to the main DB file). Most methods on this class will stop working // after you call this method. Note that this yields. - closePermanently: function () { + closePermanently: async function () { var self = this; - self.db.closePermanently(); + await self.db.closePermanently(); self.db = null; }, - getVersion: function (packageName, version) { - var result = this._contentQuery( + getVersion: async function (packageName, version) { + var result = await this._contentQuery( "SELECT content FROM versions WHERE packageName=? AND version=?", [packageName, version]); return filterExactRows(result, { packageName, version }); @@ -545,16 +545,16 @@ Object.assign(RemoteCatalog.prototype, { // As getVersion, but returns info on the latest version of the // package, or null if the package doesn't exist or has no versions. - getLatestVersion: function (name) { + getLatestVersion: async function (name) { var self = this; - var versions = self.getSortedVersions(name); - return self.getVersion(name, _.last(versions)); + var versions = await self.getSortedVersions(name); + return await self.getVersion(name, _.last(versions)); }, - getSortedVersions: function (name) { + getSortedVersions: async function (name) { var self = this; - var match = this._columnsQuery( + var match = await this._columnsQuery( "SELECT version FROM versions WHERE packageName=?", name); if (match === null) return []; @@ -566,9 +566,9 @@ Object.assign(RemoteCatalog.prototype, { // Just getVersion mapped over getSortedVersions, but only makes one round // trip to sqlite. - getSortedVersionRecords: function (name) { + getSortedVersionRecords: async function (name) { var self = this; - var versionRecords = this._contentQuery( + var versionRecords = await this._contentQuery( "SELECT content FROM versions WHERE packageName=?", [name]); if (! versionRecords) return []; @@ -581,20 +581,20 @@ Object.assign(RemoteCatalog.prototype, { return versionRecords; }, - getLatestMainlineVersion: function (name) { + getLatestMainlineVersion: async function (name) { var self = this; - var versions = self.getSortedVersions(name); + var versions = await self.getSortedVersions(name); versions.reverse(); var latest = _.find(versions, function (version) { return !/-/.test(version); }); if (!latest) return null; - return self.getVersion(name, latest); + return await self.getVersion(name, latest); }, - getPackage: function (name, options) { - var result = this._contentQuery( + getPackage: async function (name) { + var result = await this._contentQuery( "SELECT content FROM packages WHERE name=?", name); if (!result || result.length === 0) return null; @@ -604,8 +604,8 @@ Object.assign(RemoteCatalog.prototype, { return result[0]; }, - getAllBuilds: function (name, version) { - var result = this._contentQuery( + getAllBuilds: async function (name, version) { + var result = await this._contentQuery( "SELECT content FROM builds WHERE builds.versionId = " + "(SELECT _id FROM versions WHERE versions.packageName=? AND " + "versions.version=?)", @@ -619,11 +619,11 @@ Object.assign(RemoteCatalog.prototype, { // which cover all of the required arches, or null if it is impossible to // cover them all (or if the version does not exist). // Note that this method is specific to RemoteCatalog. - getBuildsForArches: function (name, version, arches) { + getBuildsForArches: async function (name, version, arches) { var self = this; var solution = null; - var allBuilds = self.getAllBuilds(name, version) || []; + var allBuilds = await self.getAllBuilds(name, version) || []; utils.generateSubsetsOfIncreasingSize(allBuilds, function (buildSubset) { // This build subset works if for all the arches we need, at least one @@ -643,24 +643,29 @@ Object.assign(RemoteCatalog.prototype, { return solution; // might be null! }, - filterArchesWithBuilds: function (name, version, arches) { - return arches.filter(arch => { - return !! this.getBuildsForArches(name, version, [arch]); - }); + filterArchesWithBuilds: async function (name, version, arches) { + const buildArches = []; + + for (const arch of arches) { + if (await this.getBuildsForArches(name, version, [arch])) { + buildArches.push(arch); + } + } + return buildArches; }, // Returns general (non-version-specific) information about a // release track, or null if there is no such release track. - getReleaseTrack: function (name) { + getReleaseTrack: async function (name) { var self = this; - var result = self._contentQuery( + var result = await self._contentQuery( "SELECT content FROM releaseTracks WHERE name=?", name); return filterExactRows(result, { name }); }, - getReleaseVersion: function (track, version) { + getReleaseVersion: async function (track, version) { var self = this; - var result = self._contentQuery( + var result = await self._contentQuery( "SELECT content FROM releaseVersions WHERE track=? AND version=?", [track, version]); return filterExactRows(result, { track, version }); @@ -668,27 +673,30 @@ Object.assign(RemoteCatalog.prototype, { // Used by make-bootstrap-tarballs. Only should be used on catalogs that are // specially constructed for bootstrap tarballs. - forceRecommendRelease: function (track, version) { + forceRecommendRelease: async function (track, version) { var self = this; - var releaseVersionData = self.getReleaseVersion(track, version); + var releaseVersionData = await self.getReleaseVersion(track, version); if (!releaseVersionData) { throw Error("Can't force-recommend unknown release " + track + "@" + version); } releaseVersionData.recommended = true; - self._insertReleaseVersions([releaseVersionData]); + await self._insertReleaseVersions([releaseVersionData]); }, - getAllReleaseTracks: function () { - return _.pluck(this._columnsQuery("SELECT name FROM releaseTracks"), - 'name'); + getAllReleaseTracks: async function () { + const result = await this._columnsQuery("SELECT name FROM releaseTracks"); + + return result.map(({name}) => name); }, - getAllPackageNames: function () { - return _.pluck(this._columnsQuery("SELECT name FROM packages"), 'name'); + getAllPackageNames: async function () { + const results = await this._columnsQuery("SELECT name FROM packages"); + + return results.map(({name}) => name); }, - initialize: function (options) { + initialize: async function (options) { var self = this; options = options || {}; @@ -698,6 +706,8 @@ Object.assign(RemoteCatalog.prototype, { var dbFile = options.packageStorage || config.getPackageStorage(); self.db = new Db(dbFile); + await self.db.init(); + self.tableVersions = new Table('versions', ['packageName', 'version', '_id']); self.tableBuilds = new Table('builds', ['versionId', '_id']); self.tableReleaseTracks = new Table('releaseTracks', ['name', '_id']); @@ -718,24 +728,24 @@ Object.assign(RemoteCatalog.prototype, { self.tableMetadata, self.tableBannersShown ]; - return self.db.runInTransaction(function(txn) { - _.each(self.allTables, function (table) { - table.createTable(txn); - }); + return self.db.runInTransaction(async function(txn) { + for (const table of self.allTables) { + await table.createTable(txn); + } // Extra indexes for the most expensive queries // These are non-unique indexes // XXX We used to have a versionsNamesIdx here on versions(packageName); // we no longer create it but we don't waste time dropping it either. - txn.execute("CREATE INDEX IF NOT EXISTS versionsIdx ON " + + await txn.execute("CREATE INDEX IF NOT EXISTS versionsIdx ON " + "versions(packageName, version)"); - txn.execute("CREATE INDEX IF NOT EXISTS buildsVersionsIdx ON " + + await txn.execute("CREATE INDEX IF NOT EXISTS buildsVersionsIdx ON " + "builds(versionId)"); - txn.execute("CREATE INDEX IF NOT EXISTS packagesIdx ON " + + await txn.execute("CREATE INDEX IF NOT EXISTS packagesIdx ON " + "packages(name)"); - txn.execute("CREATE INDEX IF NOT EXISTS releaseTracksIdx ON " + + await txn.execute("CREATE INDEX IF NOT EXISTS releaseTracksIdx ON " + "releaseTracks(name)"); - txn.execute("CREATE INDEX IF NOT EXISTS releaseVersionsIdx ON " + + await txn.execute("CREATE INDEX IF NOT EXISTS releaseVersionsIdx ON " + "releaseVersions(track, version)"); }); }, @@ -750,7 +760,7 @@ Object.assign(RemoteCatalog.prototype, { }); }, - refresh: function (options) { + refresh: async function (options) { var self = this; options = options || {}; @@ -766,7 +776,7 @@ Object.assign(RemoteCatalog.prototype, { return false; if (options.maxAge) { - var lastSync = self.getMetadata(METADATA_LAST_SYNC); + var lastSync = await self.getMetadata(METADATA_LAST_SYNC); Console.debug("lastSync = ", lastSync); if (lastSync && lastSync.timestamp) { if ((Date.now() - lastSync.timestamp) < options.maxAge) { @@ -778,12 +788,12 @@ Object.assign(RemoteCatalog.prototype, { var updateResult = {}; // XXX This buildmessage.enterJob only exists for showing progress. - buildmessage.enterJob({ title: 'updating package catalog' }, function () { - updateResult = packageClient.updateServerPackageData(self); + await buildmessage.enterJob({ title: 'updating package catalog' }, async function () { + updateResult = await packageClient.updateServerPackageData(self); }); if (updateResult.resetData) { - tropohouse.default.wipeAllPackages(); + await tropohouse.default.wipeAllPackages(); } return true; @@ -792,58 +802,58 @@ Object.assign(RemoteCatalog.prototype, { // Given a release track, returns all recommended versions for this track, // sorted by their orderKey. Returns the empty array if the release track does // not exist or does not have any recommended versions. - getSortedRecommendedReleaseVersions: function (track, laterThanOrderKey) { + getSortedRecommendedReleaseVersions: async function (track, laterThanOrderKey) { var self = this; var versions = - self.getSortedRecommendedReleaseRecords(track, laterThanOrderKey); + await self.getSortedRecommendedReleaseRecords(track, laterThanOrderKey); return _.pluck(versions, "version"); }, // Given a release track, returns all recommended version *records* for this // track, sorted by their orderKey. Returns the empty array if the release // track does not exist or does not have any recommended versions. - getSortedRecommendedReleaseRecords: function (track, laterThanOrderKey) { - var self = this; - // XXX releaseVersions content objects are kinda big; if we put - // 'recommended' and 'orderKey' in their own columns this could be faster - var result = self._contentQuery( - "SELECT content FROM releaseVersions WHERE track=?", track); + getSortedRecommendedReleaseRecords: async function (track, laterThanOrderKey) { + const hasMinKey = laterThanOrderKey != null; - var recommended = _.filter(result, function (v) { - if (!v.recommended) - return false; - return !laterThanOrderKey || v.orderKey > laterThanOrderKey; - }); + // Always use JSON1 to filter & sort directly in SQL + const sql = ` + SELECT content + FROM releaseVersions + WHERE track = ? + AND json_extract(content, '$.recommended') = 1 + ${hasMinKey ? "AND json_extract(content, '$.orderKey') > ?" : ""} + ORDER BY json_extract(content, '$.orderKey') DESC + `; + const params = hasMinKey + ? [track, laterThanOrderKey] + : [track]; - var recSort = _.sortBy(recommended, function (rec) { - return rec.orderKey; - }); - recSort.reverse(); - return recSort; + // _contentQuery will JSON.parse(content) for you + return this._contentQuery(sql, params); }, // Given a release track, returns all version records for this track. - getReleaseVersionRecords: function (track) { + getReleaseVersionRecords: async function (track) { var self = this; - var result = self._contentQuery( + var result = await self._contentQuery( "SELECT content FROM releaseVersions WHERE track=?", track); return result; }, // For a given track, returns the total number of release versions on that // track. - getNumReleaseVersions: function (track) { + getNumReleaseVersions: async function (track) { var self = this; - var result = self._columnsQuery( + var result = await self._columnsQuery( "SELECT count(*) FROM releaseVersions WHERE track=?", track); return result[0]["count(*)"]; }, // Returns the default release version on the DEFAULT_TRACK, or for a // given release track. - getDefaultReleaseVersion: function (track) { + getDefaultReleaseVersion: async function (track) { var self = this; - var versionRecord = self.getDefaultReleaseVersionRecord(track); + var versionRecord = await self.getDefaultReleaseVersionRecord(track); if (! versionRecord) throw new Error("Can't get default release version for track " + track); return _.pick(versionRecord, ["track", "version" ]); @@ -851,29 +861,29 @@ Object.assign(RemoteCatalog.prototype, { // Returns the default release version record for the DEFAULT_TRACK, or for a // given release track. - getDefaultReleaseVersionRecord: function (track) { + getDefaultReleaseVersionRecord: async function (track) { var self = this; if (!track) track = exports.DEFAULT_TRACK; - var versions = self.getSortedRecommendedReleaseRecords(track); + var versions = await self.getSortedRecommendedReleaseRecords(track); if (!versions.length) return null; return versions[0]; }, - getBuildWithPreciseBuildArchitectures: function (versionRecord, buildArchitectures) { + getBuildWithPreciseBuildArchitectures: async function (versionRecord, buildArchitectures) { var self = this; - var matchingBuilds = this._contentQuery( + var matchingBuilds = await this._contentQuery( "SELECT content FROM builds WHERE versionId=?", versionRecord._id); return _.findWhere(matchingBuilds, { buildArchitectures: buildArchitectures }); }, // Executes a query, returning an array of each content column parsed as JSON - _contentQuery: function (query, params) { + _contentQuery: async function (query, params) { var self = this; - var rows = self._columnsQuery(query, params); + var rows = await self._columnsQuery(query, params); return _.map(rows, function(entity) { return JSON.parse(entity.content); }); @@ -881,46 +891,44 @@ Object.assign(RemoteCatalog.prototype, { // Executes a query, returning an array of maps from column name to data. // No JSON parsing is performed. - _columnsQuery: function (query, params) { + _columnsQuery: async function (query, params) { var self = this; - var rows = self.db.runInTransaction(function (txn) { - return txn.query(query, params); - }); + var rows = await self.db._query(query, params); return rows; }, _insertReleaseVersions: function(releaseVersions) { var self = this; return self.db.runInTransaction(function (txn) { - self.tableReleaseVersions.upsert(txn, releaseVersions); + return self.tableReleaseVersions.upsert(txn, releaseVersions); }); }, //Given data from troposphere, add it into the local store insertData: function(serverData, syncComplete) { var self = this; - return self.db.runInTransaction(function (txn) { - self.tablePackages.upsert(txn, serverData.collections.packages); - self.tableBuilds.upsert(txn, serverData.collections.builds); - self.tableVersions.upsert(txn, serverData.collections.versions); - self.tableReleaseTracks.upsert(txn, serverData.collections.releaseTracks); - self.tableReleaseVersions.upsert(txn, serverData.collections.releaseVersions); + return self.db.runInTransaction(async function (txn) { + await self.tablePackages.upsert(txn, serverData.collections.packages); + await self.tableBuilds.upsert(txn, serverData.collections.builds); + await self.tableVersions.upsert(txn, serverData.collections.versions); + await self.tableReleaseTracks.upsert(txn, serverData.collections.releaseTracks); + await self.tableReleaseVersions.upsert(txn, serverData.collections.releaseVersions); var syncToken = serverData.syncToken; Console.debug("Adding syncToken: ", JSON.stringify(syncToken)); syncToken._id = SYNCTOKEN_ID; //Add fake _id so it fits the pattern - self.tableSyncToken.upsert(txn, [syncToken]); + await self.tableSyncToken.upsert(txn, [syncToken]); if (syncComplete) { var lastSync = {timestamp: Date.now()}; - self._setMetadata(txn, METADATA_LAST_SYNC, lastSync); + await self._setMetadata(txn, METADATA_LAST_SYNC, lastSync); } }); }, - getSyncToken: function() { + getSyncToken: async function() { var self = this; - var result = self._contentQuery("SELECT content FROM syncToken WHERE _id=?", + var result = await self._contentQuery("SELECT content FROM syncToken WHERE _id=?", [ SYNCTOKEN_ID ]); if (!result || result.length === 0) { Console.debug("No sync token found"); @@ -934,35 +942,31 @@ Object.assign(RemoteCatalog.prototype, { return result[0]; }, - getMetadata: function(key) { + getMetadata: async function(key) { var self = this; - var row = self.db.runInTransaction(function (txn) { - return self.tableMetadata.find(txn, key); - }); + var row = await self.tableMetadata.find(self.db, key); if (row) { return JSON.parse(row['content']); } return undefined; }, - setMetadata: function(key, value) { + setMetadata: async function(key, value) { var self = this; - self.db.runInTransaction(function (txn) { - self._setMetadata(txn, key, value); + await self.db.runInTransaction(function (txn) { + return self._setMetadata(txn, key, value); }); }, - _setMetadata: function(txn, key, value) { + _setMetadata: async function(txn, key, value) { var self = this; value._id = key; - self.tableMetadata.upsert(txn, [value]); + await self.tableMetadata.upsert(txn, [value]); }, - shouldShowBanner: function (releaseName, bannerDate) { + shouldShowBanner: async function (releaseName, bannerDate) { var self = this; - var row = self.db.runInTransaction(function (txn) { - return self.tableBannersShown.find(txn, releaseName); - }); + var row = await self.tableBannersShown.find(self.db, releaseName); // We've never printed a banner for this release. if (! row) return true; @@ -975,10 +979,10 @@ Object.assign(RemoteCatalog.prototype, { } }, - setBannerShownDate: function (releaseName, bannerShownDate) { + setBannerShownDate: async function (releaseName, bannerShownDate) { var self = this; - self.db.runInTransaction(function (txn) { - self.tableBannersShown.upsert(txn, [{ + return self.db.runInTransaction(function (txn) { + return self.tableBannersShown.upsert(txn, [{ _id: releaseName, // XXX For now, there's no way to tell this file to make a non-string // column in a sqlite table, but this should probably change to a diff --git a/tools/packaging/catalog/catalog.js b/tools/packaging/catalog/catalog.js index d60df551ae..46f2363446 100644 --- a/tools/packaging/catalog/catalog.js +++ b/tools/packaging/catalog/catalog.js @@ -16,9 +16,9 @@ catalog.Refresh.OnceAtStart = function (options) { self.options = Object.assign({}, options); }; -catalog.Refresh.OnceAtStart.prototype.beforeCommand = function () { +catalog.Refresh.OnceAtStart.prototype.beforeCommand = async function () { var self = this; - if (!catalog.refreshOrWarn(self.options)) { + if (!await catalog.refreshOrWarn(self.options)) { if (self.options.ignoreErrors) { Console.debug("Failed to update package catalog, but will continue."); } else { @@ -42,10 +42,10 @@ catalog.Refresh.Never = function (options) { // // THIS IS A HIGH-LEVEL UI COMMAND. DO NOT CALL IT FROM LOW-LEVEL CODE (ie, call // it only from main.js or command implementations). -catalog.refreshOrWarn = function (options) { +catalog.refreshOrWarn = async function (options) { catalog.triedToRefreshRecently = true; try { - catalog.official.refresh(options); + await catalog.official.refresh(options); catalog.refreshFailed = false; return true; } catch (err) { @@ -89,15 +89,15 @@ catalog.refreshOrWarn = function (options) { // Runs 'attempt'; if it fails in a way that can be fixed by refreshing the // official catalog, does that and tries again. -catalog.runAndRetryWithRefreshIfHelpful = function (attempt) { +catalog.runAndRetryWithRefreshIfHelpful = async function (attempt) { buildmessage.assertInJob(); var canRetry = ! (catalog.triedToRefreshRecently || catalog.official.offline); // Run `attempt` in a nested buildmessage context. - var messages = buildmessage.capture(function () { - attempt(canRetry); + var messages = await buildmessage.capture(async function () { + await attempt(canRetry); }); // Did it work? Great. @@ -120,7 +120,7 @@ catalog.runAndRetryWithRefreshIfHelpful = function (attempt) { // log. catalog.triedToRefreshRecently = true; try { - catalog.official.refresh(); + await catalog.official.refresh(); catalog.refreshFailed = false; } catch (err) { if (err.errorType !== 'DDP.ConnectionError') @@ -128,17 +128,17 @@ catalog.runAndRetryWithRefreshIfHelpful = function (attempt) { // First place the previous errors in the capture. buildmessage.mergeMessagesIntoCurrentJob(messages); // Then put an error representing this DDP error. - buildmessage.enterJob( + await buildmessage.enterJob( "refreshing package catalog to resolve previous errors", function () { - buildmessage.error(err.message); + return buildmessage.error(err.message); } ); return; } // Try again, this time directly in the current buildmessage job. - attempt(false); // canRetry = false + await attempt(false); // canRetry = false }; // As a work-around for [] !== [], we use a function to check whether values are acceptable @@ -203,14 +203,14 @@ Object.assign(LayeredCatalog.prototype, { "getSortedVersionRecords", args, ACCEPT_NON_EMPTY); }, - getVersion: function (name, version) { + getVersion: async function (name, version) { var self = this; var result = self.localCatalog.getVersion(name, version); if (!result) { if (/\+/.test(version)) { return null; } - result = self.otherCatalog.getVersion(name, version); + result = await self.otherCatalog.getVersion(name, version); } return result; }, @@ -218,17 +218,17 @@ Object.assign(LayeredCatalog.prototype, { // As getVersion, but returns info on the latest version of the // package, or null if the package doesn't exist or has no versions. // It does not include prereleases (with dashes in the version); - getLatestMainlineVersion: function (name) { + getLatestMainlineVersion: async function (name) { var self = this; - var versions = self.getSortedVersions(name); + var versions = await self.getSortedVersions(name); versions.reverse(); var latest = versions.find(function (version) { return !/-/.test(version); }); if (!latest) return null; - return self.getVersion(name, latest); + return await self.getVersion(name, latest); } }); diff --git a/tools/packaging/package-client.js b/tools/packaging/package-client.js index 3075970647..c79a2463df 100644 --- a/tools/packaging/package-client.js +++ b/tools/packaging/package-client.js @@ -39,27 +39,27 @@ var generateBlankReadme = function () { }; // Save a readme file to a temporary path. -var saveReadmeToTmp = function (readmeInfo) { +var saveReadmeToTmp = async function (readmeInfo) { var tempReadmeDir = files.mkdtemp('readme'); var readmePath = files.pathJoin(tempReadmeDir, "Readme.md"); - files.writeFileAtomically(readmePath, readmeInfo.contents); + await files.writeFileAtomically(readmePath, readmeInfo.contents); return readmePath; }; // Given a connection, makes a call to the package server. (Checks to see if // the connection is connected, and reconnects if needed -- a workaround for // the fact that connections in the tool do not reconnect) -exports.callPackageServer = function (conn, ...args) { +exports.callPackageServer = async function (conn, ...args) { // XXX This is broken since it doesn't actually replace the conn in the // caller, so it'll happen on every subsequent call if (!conn.connected) { conn.close(); - conn = exports.loggedInPackagesConnection(); + conn = await exports.loggedInPackagesConnection(); } return conn.call(...args); }; -var callPackageServerBM = exports.callPackageServerBM = function (...args) { +var callPackageServerBM = exports.callPackageServerBM = async function (...args) { buildmessage.assertInJob(); try { return exports.callPackageServer.apply(null, args); @@ -84,7 +84,7 @@ var callPackageServerBM = exports.callPackageServerBM = function (...args) { // - syncToken: a new syncToken object, that we can pass to the server in the future. // - collections: an object keyed by the name of server collections, with the // records as an array of javascript objects. -var loadRemotePackageData = function (conn, syncToken, options) { +var loadRemotePackageData = async function (conn, syncToken, options) { options = options || {}; // Did we get disconnected between retries somehow? Then we should open a new @@ -92,7 +92,7 @@ var loadRemotePackageData = function (conn, syncToken, options) { // since we don't need to authenticate. if (!conn.connected) { conn.close(); - conn = openPackageServerConnection(); + conn = await openPackageServerConnection(); } var syncOpts = {}; @@ -102,7 +102,7 @@ var loadRemotePackageData = function (conn, syncToken, options) { if (options && options.compressCollections) { syncOpts.compressCollections = options.compressCollections; } - return conn.call('syncNewPackageData', syncToken, syncOpts); + return await conn.call('syncNewPackageData', syncToken, syncOpts); }; // Contacts the package server to get the latest diff and writes changes to @@ -124,13 +124,13 @@ var loadRemotePackageData = function (conn, syncToken, options) { // `config.getPackageServerUrl()`) // - useShortPages: Boolean. Request short pages of ~3 records from the // server, instead of ~100 that it would send otherwise -exports.updateServerPackageData = function (dataStore, options) { - return buildmessage.enterJob('updating package catalog', function () { - return _updateServerPackageData(dataStore, options); +exports.updateServerPackageData = async function (dataStore, options) { + return await buildmessage.enterJob('updating package catalog', async function () { + return await _updateServerPackageData(dataStore, options); }); }; -var _updateServerPackageData = function (dataStore, options) { +var _updateServerPackageData = async function (dataStore, options) { var self = this; options = options || {}; if (dataStore === null) { @@ -148,15 +148,14 @@ var _updateServerPackageData = function (dataStore, options) { var state = { current: 0, end: 60 * 60 * 1000, done: false}; useProgressbar && buildmessage.reportProgress(state); - var conn = openPackageServerConnection(options.packageServerUrl); - + var conn = await openPackageServerConnection(options.packageServerUrl); // Provide some progress indication for connection // XXX though it is just a hack state.current = 1; useProgressbar && buildmessage.reportProgress(state); - var getSomeData = function () { - var syncToken = dataStore.getSyncToken() || {format: "1.1"}; + var getSomeData = async function () { + var syncToken = (await dataStore.getSyncToken()) || {format: "1.1"}; if (!start) { start = {}; @@ -173,11 +172,12 @@ var _updateServerPackageData = function (dataStore, options) { var compress = !!process.env.METEOR_CATALOG_COMPRESS_RPCS; // (loadRemotePackageData may throw) - var remoteData = loadRemotePackageData(conn, syncToken, { + var remoteData = await loadRemotePackageData(conn, syncToken, { useShortPages: options.useShortPages, compressCollections: compress }); + // Is the remote server telling us to ignore everything we've heard before? // OK, we can do that. if (remoteData.resetData) { @@ -191,11 +191,11 @@ var _updateServerPackageData = function (dataStore, options) { var zlib = require('zlib'); var colsGzippedBuffer = Buffer.from( remoteData.collectionsCompressed, 'base64'); - var colsJSON = new Promise((resolve, reject) => { + var colsJSON = await new Promise((resolve, reject) => { zlib.gunzip(colsGzippedBuffer, (err, res) => { err ? reject(err) : resolve(res); }); - }).await(); + }); remoteData.collections = JSON.parse(colsJSON); delete remoteData.collectionsCompressed; } @@ -204,7 +204,7 @@ var _updateServerPackageData = function (dataStore, options) { // data! e.g. the last-refresh timestamp var syncComplete = _.isEqual(remoteData.collections, {}) || remoteData.upToDate; - dataStore.insertData(remoteData, syncComplete); + await dataStore.insertData(remoteData, syncComplete); // If there is no new data from the server, don't bother writing things to // disk (unless we were just told to reset everything). @@ -220,7 +220,7 @@ var _updateServerPackageData = function (dataStore, options) { try { while (!done) { - getSomeData(); + await getSomeData(); requestGarbageCollection(); } } finally { @@ -230,15 +230,19 @@ var _updateServerPackageData = function (dataStore, options) { return ret; }; -_updateServerPackageData = Profile('package-client _updateServerPackageData', - _updateServerPackageData); +_updateServerPackageData = + Profile('package-client _updateServerPackageData', _updateServerPackageData); // Returns a logged-in DDP connection to the package server, or null if // we cannot log in. If an error unrelated to login occurs // (e.g. connection to package server times out), then it will be // thrown. -exports.loggedInPackagesConnection = function () { - return authClient.loggedInConnection( +/** + * + * @return {Promise<*>} + */ +exports.loggedInPackagesConnection = async function () { + return await authClient.loggedInConnection( config.getPackageServerUrl(), config.getPackageServerDomain(), "package-server" @@ -248,7 +252,7 @@ exports.loggedInPackagesConnection = function () { // XXX this is missing a few things. In retrospect a better approach here might // be to actually make "save source somewhere else" or perhaps "add source // to tarball" be part of the package build itself... -var bundleSource = function (isopack, includeSources, packageDir) { +var bundleSource = async function (isopack, includeSources, packageDir) { buildmessage.assertInJob(); var name = isopack.name; @@ -299,14 +303,14 @@ var bundleSource = function (isopack, includeSources, packageDir) { var packageMapFile = new projectContextModule.PackageMapFile({ filename: packageMapFilename }); - packageMapFile.write(pluginProviderPackageMap); + await packageMapFile.write(pluginProviderPackageMap); // We put this inside the temp dir because mkdtemp makes sure that the // temp dir gets cleaned up on process exit, so we don't have to worry // about cleaning up our tarball (or our copied source files) // ourselves. var sourceTarball = files.pathJoin(tempDir, packageTarName + '.tgz'); - files.createTarball(dirToTar, sourceTarball); + await files.createTarball(dirToTar, sourceTarball); var tarballHash = files.fileHash(sourceTarball); var treeHash = files.treeHash(dirToTar); @@ -321,13 +325,13 @@ var bundleSource = function (isopack, includeSources, packageDir) { // Uploads a file at a filepath to the HTTP put URL. // // Returns true on success and false on failure. -var uploadFile = function (putUrl, filepath) { +var uploadFile = async function (putUrl, filepath) { buildmessage.assertInJob(); var size = files.stat(filepath).size; var rs = files.createReadStream(filepath); try { // Use getUrl instead of request, to throw on 4xx/5xx. - httpHelpers.getUrl({ + await httpHelpers.getUrl({ method: 'PUT', url: putUrl, headers: { @@ -350,7 +354,7 @@ var uploadFile = function (putUrl, filepath) { exports.uploadFile = uploadFile; -export function bundleBuild(isopack, isopackCache) { +export async function bundleBuild(isopack, isopackCache) { buildmessage.assertInJob(); var tempDir = files.mkdtemp('bp-'); @@ -361,7 +365,7 @@ export function bundleBuild(isopack, isopackCache) { // disk in an IsopackCache, because we don't want to include // isopack-buildinfo.json. (We don't include it because we're not passing // includeIsopackBuildInfo to saveToPath here.) - isopack.saveToPath(tarInputDir, { + await isopack.saveToPath(tarInputDir, { // When publishing packages that don't use new registerCompiler plugins, // make sure that old Meteors can use it too includePreCompilerPluginIsopackVersions: true, @@ -369,11 +373,10 @@ export function bundleBuild(isopack, isopackCache) { }); var buildTarball = files.pathJoin(tempDir, packageTarName + '.tgz'); + await files.createTarball(tarInputDir, buildTarball); - files.createTarball(tarInputDir, buildTarball); - - var tarballHash = files.fileHash(buildTarball); - var treeHash = files.treeHash(tarInputDir, { + var tarballHash = files.fileHash(buildTarball); + var treeHash = files.treeHash(tarInputDir, { // We don't include any package.json from an npm module in the tree hash, // because npm isn't super consistent about what it puts in there (eg, does // it include the "readme" field)? This ends up leading to spurious @@ -393,15 +396,15 @@ export function bundleBuild(isopack, isopackCache) { }; } -function createBuiltPackage(isopack, isopackCache) { +async function createBuiltPackage(isopack, isopackCache) { buildmessage.assertInJob(); var name = isopack.name; // Note: we really want to do this before createPackageBuild, because the URL // we get from createPackageBuild will expire! var bundleResult; - buildmessage.enterJob("bundling build for " + name, function () { - bundleResult = bundleBuild(isopack, isopackCache); + await buildmessage.enterJob("bundling build for " + name, async function () { + bundleResult = await bundleBuild(isopack, isopackCache); }); if (buildmessage.jobHasMessages()) { return; @@ -410,13 +413,13 @@ function createBuiltPackage(isopack, isopackCache) { return bundleResult; } -var publishBuiltPackage = function (conn, isopack, bundleResult) { +var publishBuiltPackage = async function (conn, isopack, bundleResult) { buildmessage.assertInJob(); var name = isopack.name; var uploadInfo; - buildmessage.enterJob('creating package build for ' + name, function () { - uploadInfo = callPackageServerBM(conn, 'createPackageBuild', { + await buildmessage.enterJob('creating package build for ' + name, async function () { + uploadInfo = await callPackageServerBM(conn, 'createPackageBuild', { packageName: isopack.name, version: isopack.version, buildArchitectures: isopack.buildArchitectures() @@ -426,30 +429,34 @@ var publishBuiltPackage = function (conn, isopack, bundleResult) { return; } - buildmessage.enterJob("uploading build", function () { - uploadFile(uploadInfo.uploadUrl, - bundleResult.buildTarball); + await buildmessage.enterJob("uploading build", async function () { + await uploadFile(uploadInfo.uploadUrl, + bundleResult.buildTarball); }); if (buildmessage.jobHasMessages()) { return; } - buildmessage.enterJob('publishing package build for ' + name, function () { - callPackageServerBM(conn, 'publishPackageBuild', - uploadInfo.uploadToken, - bundleResult.tarballHash, - bundleResult.treeHash); + await buildmessage.enterJob('publishing package build for ' + name, async function () { + try { + await callPackageServerBM(conn, 'publishPackageBuild', + uploadInfo.uploadToken, + bundleResult.tarballHash, + bundleResult.treeHash); + } catch (e) { + buildmessage.error(e.message); + } }); if (buildmessage.jobHasMessages()) { return; } }; -export function createAndPublishBuiltPackage(conn, isopack, isopackCache) { - publishBuiltPackage( +export async function createAndPublishBuiltPackage(conn, isopack, isopackCache) { + await publishBuiltPackage( conn, isopack, - createBuiltPackage(isopack, isopackCache), + await createBuiltPackage(isopack, isopackCache), ); } @@ -459,7 +466,7 @@ exports.handlePackageServerConnectionError = function (error) { }; -// Update the package metdata in the server catalog. Chane the docs, +// Update the package metadata in the server catalog. Change the docs, // descriptions and the Git URL to new values. // // options: @@ -469,7 +476,7 @@ exports.handlePackageServerConnectionError = function (error) { // package server. DO NOT CLOSE this connection here. // // Return true on success and an error code otherwise. -exports.updatePackageMetadata = function (options) { +exports.updatePackageMetadata = async function (options) { buildmessage.assertInJob(); var packageSource = options.packageSource; @@ -520,8 +527,8 @@ exports.updatePackageMetadata = function (options) { // Update the general metadata. var versionIdentifier = { packageName: name, version: version }; - buildmessage.enterJob('updating metadata', function () { - callPackageServerBM( + await buildmessage.enterJob('updating metadata', async function () { + await callPackageServerBM( conn, "changeVersionMetadata", versionIdentifier, dataToUpdate); }); if (buildmessage.jobHasMessages()) { @@ -529,17 +536,17 @@ exports.updatePackageMetadata = function (options) { } // Upload the new Readme. - buildmessage.enterJob('uploading documentation', function () { - var readmePath = saveReadmeToTmp(readmeInfo); + await buildmessage.enterJob('uploading documentation', async function () { + var readmePath = await saveReadmeToTmp(readmeInfo); var uploadInfo = - callPackageServerBM(conn, "createReadme", versionIdentifier); - if (! uploadInfo) { + await callPackageServerBM(conn, "createReadme", versionIdentifier); + if (!uploadInfo) { return; } - if (! uploadFile(uploadInfo.url, readmePath)) { + if (!await uploadFile(uploadInfo.url, readmePath)) { return; } - callPackageServerBM( + await callPackageServerBM( conn, "publishReadme", uploadInfo.uploadToken, { hash: readmeInfo.hash }); }); if (buildmessage.jobHasMessages()) { @@ -566,7 +573,7 @@ exports.updatePackageMetadata = function (options) { // - doNotPublishBuild: do not publish the build of this package. // // Return true on success and an error code otherwise. -exports.publishPackage = function (options) { +exports.publishPackage = async function (options) { buildmessage.assertInJob(); var packageSource = options.packageSource; var conn = options.connection; @@ -609,15 +616,14 @@ exports.publishPackage = function (options) { // Check that we are an authorized maintainer of this package. if (!options['new']) { - var packRecord = catalog.official.getPackage(name); + var packRecord = await catalog.official.getPackage(name); if (! packRecord) { buildmessage.error( 'There is no package named ' + name + '. If you are creating a new package, use the --create flag.'); return; } - - if (!exports.amIAuthorized(name, conn, false)) { + if (!await exports.amIAuthorized(name, conn, false)) { buildmessage.error( 'You are not an authorized maintainer of ' + name + '. Only ' + 'authorized maintainers may publish new versions.'); @@ -626,7 +632,7 @@ exports.publishPackage = function (options) { // Check that our documentation exists (or we know that it doesn't) and has // been filled out. - var readmeInfo = buildmessage.enterJob( + var readmeInfo = await buildmessage.enterJob( "processing documentation", function () { return packageSource.processReadme(); @@ -657,10 +663,9 @@ exports.publishPackage = function (options) { if (! readmeInfo) { readmeInfo = generateBlankReadme(); } - var readmePath = saveReadmeToTmp(readmeInfo); + var readmePath = await saveReadmeToTmp(readmeInfo); var packageDeps = packageSource.getDependencyMetadata(); - // Check that the package does not have any unconstrained references. _.each(packageDeps, function(refs, label) { if (refs.constraint == null) { @@ -696,6 +701,7 @@ exports.publishPackage = function (options) { } var isopack = projectContext.isopackCache.getIsopack(name); + if (! isopack) { throw Error("no isopack " + name); } @@ -737,18 +743,18 @@ exports.publishPackage = function (options) { } var sourceBundleResult; - buildmessage.enterJob("bundling source for " + name, function () { - sourceBundleResult = bundleSource( + await buildmessage.enterJob("bundling source for " + name, async function () { + sourceBundleResult = await bundleSource( isopack, sourceFiles, packageSource.sourceRoot); }); + if (buildmessage.jobHasMessages()) { return; } - // Create the package. Check that the metadata exists. if (options.new) { - buildmessage.enterJob("creating package " + name, function () { - callPackageServerBM(conn, 'createPackage', { + await buildmessage.enterJob("creating package " + name, async function () { + await callPackageServerBM(conn, 'createPackage', { name: packageSource.name }); }); @@ -758,7 +764,7 @@ exports.publishPackage = function (options) { } if (options.existingVersion) { - var existingRecord = catalog.official.getVersion(name, version); + var existingRecord = await catalog.official.getVersion(name, version); if (! existingRecord) { buildmessage.error("Version does not exist."); return; @@ -769,7 +775,7 @@ exports.publishPackage = function (options) { } if (! options.doNotPublishBuild) { - createAndPublishBuiltPackage( + await createAndPublishBuiltPackage( conn, isopack, projectContext.isopackCache); if (buildmessage.jobHasMessages()) { @@ -780,7 +786,7 @@ exports.publishPackage = function (options) { // XXX check that we're actually providing something new? } else { var uploadInfo; - buildmessage.enterJob("pre-publishing package " + name, function () { + await buildmessage.enterJob("pre-publishing package " + name, async function () { var uploadRec = { packageName: packageSource.name, version: version, @@ -800,7 +806,7 @@ exports.publishPackage = function (options) { releaseName: release.current.name, dependencies: packageDeps }; - uploadInfo = callPackageServerBM(conn, 'createPackageVersion', uploadRec); + uploadInfo = await callPackageServerBM(conn, 'createPackageVersion', uploadRec); }); if (buildmessage.jobHasMessages()) { return; @@ -811,26 +817,28 @@ exports.publishPackage = function (options) { // publish a new build. // Documentation is smaller than the source. Upload it first, to minimize // the chances of PUT URLs expiring. (XXX: in the far future, parallelize this) - buildmessage.enterJob("uploading documentation", function () { - uploadFile(uploadInfo.readmeUrl, readmePath); + await buildmessage.enterJob("uploading documentation", async function () { + await uploadFile(uploadInfo.readmeUrl, readmePath); }); + if (buildmessage.jobHasMessages()) { return; } - buildmessage.enterJob("uploading source", function () { - uploadFile(uploadInfo.uploadUrl, sourceBundleResult.sourceTarball); + await buildmessage.enterJob("uploading source", async function () { + await uploadFile(uploadInfo.uploadUrl, sourceBundleResult.sourceTarball); }); + if (buildmessage.jobHasMessages()) { return; } if (! options.doNotPublishBuild) { - var bundleResult = createBuiltPackage( + + var bundleResult = await createBuiltPackage( isopack, projectContext.isopackCache, ); - if (buildmessage.jobHasMessages()) { return; } @@ -841,8 +849,8 @@ exports.publishPackage = function (options) { treeHash: sourceBundleResult.treeHash, readmeHash: readmeInfo.hash }; - buildmessage.enterJob("publishing package version", function () { - callPackageServerBM( + await buildmessage.enterJob("publishing package version", async function () { + await callPackageServerBM( conn, 'publishPackageVersion', uploadInfo.uploadToken, hashes); }); if (buildmessage.jobHasMessages()) { @@ -850,7 +858,7 @@ exports.publishPackage = function (options) { } if (! options.doNotPublishBuild) { - publishBuiltPackage(conn, isopack, bundleResult); + await publishBuiltPackage(conn, isopack, bundleResult); if (buildmessage.jobHasMessages()) { return; } @@ -867,12 +875,12 @@ exports.publishPackage = function (options) { // // If this returns FALSE, then we are NOT authorized. // Otherwise, return true. -exports.amIAuthorized = function (name, conn, isRelease) { +exports.amIAuthorized = async function (name, conn, isRelease) { var methodName = "amIAuthorized" + (isRelease ? "Release" : "Package"); try { - exports.callPackageServer(conn, methodName, name); + await exports.callPackageServer(conn, methodName, name); } catch (err) { if (err.error === 401) { return false; diff --git a/tools/packaging/package-map.js b/tools/packaging/package-map.js index 3074338dae..a00034ef66 100644 --- a/tools/packaging/package-map.js +++ b/tools/packaging/package-map.js @@ -44,9 +44,10 @@ exports.PackageMap = function (versions, options) { }; Object.assign(exports.PackageMap.prototype, { - eachPackage: function (iterator) { + eachPackage: async function (iterator) { var self = this; - _.each(self._map, function (info, packageName) { + + for (const [packageName, info] of Object.entries(self._map)) { // For reasons that are super unclear, if this `_.clone` is inlined into // the `iterator` call, the value produced can mysteriously turn into // undefined on the way into `iterator`. Presumably some sort of memory @@ -54,8 +55,8 @@ Object.assign(exports.PackageMap.prototype, { // exercise in nondeterminism. But this does seem to be a sure-fire way to // fix it, for now. Who knows why, and who knows when it will recur again. var infoClone = _.clone(info); - iterator(packageName, infoClone); - }); + await iterator(packageName, infoClone); + } }, getInfo: function (packageName) { var self = this; @@ -159,23 +160,27 @@ exports.PackageMap.fromReleaseVersion = function (releaseVersion) { exports.PackageMapDelta = function (options) { var self = this; self._changedPackages = {}; - - options.packageMap.eachPackage(function (packageName, info) { - var oldVersion = _.has(options.cachedVersions, packageName) - ? options.cachedVersions[packageName] : null; - self._storeAddOrChange( - packageName, info, oldVersion, options.anticipatedPrereleases, - options.neededToUseUnanticipatedPrereleases); - }); - - _.each(options.cachedVersions, function (oldVersion, packageName) { - if (! options.packageMap.getInfo(packageName)) { - self._storeRemove(packageName, oldVersion); - } - }); + self.options = options; }; Object.assign(exports.PackageMapDelta.prototype, { + init: async function() { + const self = this; + + await self.options.packageMap.eachPackage(function (packageName, info) { + var oldVersion = _.has(self.options.cachedVersions, packageName) + ? self.options.cachedVersions[packageName] : null; + self._storeAddOrChange( + packageName, info, oldVersion, self.options.anticipatedPrereleases, + self.options.neededToUseUnanticipatedPrereleases); + }); + + _.each(self.options.cachedVersions, function (oldVersion, packageName) { + if (! self.options.packageMap.getInfo(packageName)) { + self._storeRemove(packageName, oldVersion); + } + }); + }, _storeAddOrChange: function (packageName, newInfo, oldVersion, anticipatedPrereleases, neededToUseUnanticipatedPrereleases) { diff --git a/tools/packaging/release.js b/tools/packaging/release.js index 272302af54..ada8fa10d9 100644 --- a/tools/packaging/release.js +++ b/tools/packaging/release.js @@ -186,7 +186,7 @@ release.usingRightReleaseForApp = function (projectContext) { // Return the name of the latest release that is downloaded and ready // for use. May not be called when running from a checkout. // 'track' is optional (it defaults to the default track). -release.latestKnown = function (track) { +release.latestKnown = async function (track) { if (! files.usesWarehouse()) { throw new Error("called from checkout?"); } @@ -196,7 +196,7 @@ release.latestKnown = function (track) { } - var defaultRelease = catalog.official.getDefaultReleaseVersion(track); + var defaultRelease = await catalog.official.getDefaultReleaseVersion(track); if (!defaultRelease) { return null; @@ -222,7 +222,7 @@ release.latestKnown = function (track) { // release because it's not locally cached and we're not online. // - warehouse.NoSuchReleaseError if no release called 'name' exists // in the world (confirmed with server). -release.load = function (name, options) { +release.load = async function (name, options) { options = options || {}; if (! name) { @@ -244,7 +244,7 @@ release.load = function (name, options) { name = track + '@' + version; } - var releaseVersion = catalog.official.getReleaseVersion(track, version); + var releaseVersion = await catalog.official.getReleaseVersion(track, version); if (releaseVersion === null) { throw new release.NoSuchReleaseError; } diff --git a/tools/packaging/tropohouse.js b/tools/packaging/tropohouse.js index f63e3e30aa..8c001ed7c4 100644 --- a/tools/packaging/tropohouse.js +++ b/tools/packaging/tropohouse.js @@ -40,11 +40,11 @@ exports.default = new exports.Tropohouse(defaultWarehouseDir()); * Extract a package tarball, and on Windows convert file paths and metadata * @param {String} packageTarball path to tarball * @param {Boolean} forceConvert Convert paths even on unix, for testing - * @return {String} Temporary directory with contents of package + * @return {Promise} Temporary directory with contents of package */ -exports._extractAndConvert = function (packageTarball, forceConvert) { +exports._extractAndConvert = async function (packageTarball, forceConvert) { var targetDirectory = files.mkdtemp(); - files.extractTarGz(packageTarball, targetDirectory, { + await files.extractTarGz(packageTarball, targetDirectory, { forceConvert: forceConvert }); @@ -324,14 +324,14 @@ Object.assign(exports.Tropohouse.prototype, { return downloadedArches; }, - _saveIsopack: function (isopack, packageName) { + _saveIsopack: async function (isopack, packageName) { // XXX does this actually need the name as an argument or can we just get // it from isopack? var self = this; if (self.platform === "win32") { - isopack.saveToPath(self.packagePath(packageName, isopack.version), { + await isopack.saveToPath(self.packagePath(packageName, isopack.version), { includePreCompilerPluginIsopackVersions: true }); } else { @@ -347,11 +347,11 @@ Object.assign(exports.Tropohouse.prototype, { var combinedDirectory = self.packagePath( packageName, newPackageLinkTarget); - isopack.saveToPath(combinedDirectory, { + await isopack.saveToPath(combinedDirectory, { includePreCompilerPluginIsopackVersions: true }); - files.symlinkOverSync(newPackageLinkTarget, + await files.symlinkOverSync(newPackageLinkTarget, self.packagePath(packageName, isopack.version)); } }, @@ -367,7 +367,7 @@ Object.assign(exports.Tropohouse.prototype, { // and download; download is a method which should be called in a buildmessage // capture which actually downloads the package (registering any errors with // buildmessage). - _makeDownloader: function (options) { + _makeDownloader: async function (options) { var self = this; buildmessage.assertInJob(); @@ -404,7 +404,7 @@ Object.assign(exports.Tropohouse.prototype, { // local package check), we can use the official catalog here. (This is // important, since springboarding calls this function before the complete // catalog is ready!) - var buildsToDownload = catalog.official.getBuildsForArches( + var buildsToDownload = await catalog.official.getBuildsForArches( packageName, version, archesToDownload); if (! buildsToDownload) { buildmessage.error( @@ -415,15 +415,15 @@ Object.assign(exports.Tropohouse.prototype, { } var packagePath = self.packagePath(packageName, version); - var download = function download () { + var download = async function download () { buildmessage.assertInCapture(); Console.debug("Downloading missing local versions of package", packageName + "@" + version, ":", archesToDownload); - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "downloading " + packageName + "@" + version + "..." - }, function() { + }, async function() { var buildInputDirs = []; var buildTempDirs = []; var packageLinkTarget = null; @@ -463,21 +463,21 @@ Object.assign(exports.Tropohouse.prototype, { // XXX how does concurrency work here? we could just get errors if we // try to rename over the other thing? but that's the same as in // warehouse? - _.each(buildsToDownload, ({ build: { url }}) => { - const packageTarball = buildmessage.enterJob({ + for (const { build: { url }} of buildsToDownload) { + const packageTarball = await buildmessage.enterJob({ title: "downloading " + packageName + "@" + version + "..." - }, () => { + }, async function() { try { // Override the download domain name and protocol if METEOR_WAREHOUSE_URLBASE // provided. if (process.env.METEOR_WAREHOUSE_URLBASE) { url = url.replace( - /^[a-zA-Z]+:\/\/[^\/]+/, - process.env.METEOR_WAREHOUSE_URLBASE + /^[a-zA-Z]+:\/\/[^\/]+/, + process.env.METEOR_WAREHOUSE_URLBASE ); } - return httpHelpers.getUrlWithResuming({ + return await httpHelpers.getUrlWithResuming({ url: url, encoding: null, progress: buildmessage.getCurrentProgressTracker(), @@ -491,36 +491,36 @@ Object.assign(exports.Tropohouse.prototype, { buildmessage.error(e.error.message); } }); - if (buildmessage.jobHasMessages()) { return; } - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "extracting " + packageName + "@" + version + "..." - }, () => { - const buildTempDir = exports._extractAndConvert(packageTarball); + }, async function () { + const buildTempDir = await exports._extractAndConvert(packageTarball); buildInputDirs.push(buildTempDir); buildTempDirs.push(buildTempDir); }); - }); + } if (buildmessage.jobHasMessages()) { return; } - buildmessage.enterJob({ + await buildmessage.enterJob({ title: "loading " + packageName + "@" + version + "..." - }, () => { + }, async function () { // We need to turn our builds into a single isopack. var isopack = new Isopack(); - _.each(buildInputDirs, (buildTempDir, i) => { - isopack._loadUnibuildsFromPath(packageName, buildTempDir, { + for (let i = 0; i < buildInputDirs.length; i++) { + const buildTempDir = buildInputDirs[i]; + await isopack._loadUnibuildsFromPath(packageName, buildTempDir, { firstIsopack: i === 0, }); - }); + } - self._saveIsopack(isopack, packageName, version); + await self._saveIsopack(isopack, packageName, version); }); // Delete temp directories now (asynchronously). @@ -530,7 +530,7 @@ Object.assign(exports.Tropohouse.prototype, { // Clean up old version. if (packageLinkTarget) { - files.rm_recursive(self.packagePath(packageName, packageLinkTarget)); + await files.rm_recursive(self.packagePath(packageName, packageLinkTarget)); } }); }; @@ -547,7 +547,7 @@ Object.assign(exports.Tropohouse.prototype, { // already have. // // Reports errors via buildmessage. - downloadPackagesMissingFromMap: function (packageMap, options) { + downloadPackagesMissingFromMap: async function (packageMap, options) { var self = this; buildmessage.assertInCapture(); options = options || {}; @@ -555,14 +555,14 @@ Object.assign(exports.Tropohouse.prototype, { var downloader; var downloaders = []; - packageMap.eachPackage(function (packageName, info) { + await packageMap.eachPackage(async function (packageName, info) { if (info.kind !== 'versioned') { return; } - buildmessage.enterJob( + await buildmessage.enterJob( "checking for " + packageName + "@" + info.version, - function () { - downloader = self._makeDownloader({ + async function () { + downloader = await self._makeDownloader({ packageName: packageName, version: info.version, architectures: serverArchs @@ -591,10 +591,10 @@ Object.assign(exports.Tropohouse.prototype, { // Just one package to download? Use a good message. if (downloaders.length === 1) { downloader = downloaders[0]; - buildmessage.enterJob( + await buildmessage.enterJob( "downloading " + downloader.packageName + "@" + downloader.version, - function () { - downloader.download(); + async function () { + await downloader.download(); } ); return; @@ -603,11 +603,10 @@ Object.assign(exports.Tropohouse.prototype, { // Download multiple packages in parallel. // XXX use a better progress bar that shows how many you've // finished downloading. - buildmessage.forkJoin({ + await buildmessage.enterJob({ title: 'downloading ' + downloaders.length + ' packages', - parallel: true - }, downloaders, function (downloader) { - downloader.download(); + }, async function () { + return await Promise.all(downloaders.map(d => d.download())); }); }, @@ -617,10 +616,10 @@ Object.assign(exports.Tropohouse.prototype, { return files.readLinkToMeteorScript(linkPath, self.platform); }, - linkToLatestMeteor: function (scriptLocation) { + linkToLatestMeteor: async function (scriptLocation) { var self = this; var linkPath = files.pathJoin(self.root, 'meteor'); - files.linkToMeteorScript(scriptLocation, linkPath, self.platform); + await files.linkToMeteorScript(scriptLocation, linkPath, self.platform); }, _getPlatform: function () { diff --git a/tools/packaging/updater.js b/tools/packaging/updater.js index 5d9d11bd4c..650f470cf1 100644 --- a/tools/packaging/updater.js +++ b/tools/packaging/updater.js @@ -20,7 +20,7 @@ var packageMapModule = require('./package-map.js'); * options: showBanner */ var checkInProgress = false; -exports.tryToDownloadUpdate = function (options) { +exports.tryToDownloadUpdate = async function (options) { options = options || {}; // Don't run more than one check simultaneously. It should be // harmless but having two downloads happening simultaneously (and @@ -29,16 +29,16 @@ exports.tryToDownloadUpdate = function (options) { return; } checkInProgress = true; - checkForUpdate(!! options.showBanner, !! options.printErrors); + await checkForUpdate(!! options.showBanner, !! options.printErrors); checkInProgress = false; }; var firstCheck = true; -var checkForUpdate = function (showBanner, printErrors) { +var checkForUpdate = async function (showBanner, printErrors) { // While we're doing background stuff, try to revoke any old tokens in our // session file. - auth.tryRevokeOldTokens({ timeout: 15 * 1000 }); + await auth.tryRevokeOldTokens({ timeout: 15 * 1000 }); if (firstCheck) { // We want to avoid a potential race condition here, because we run an @@ -50,7 +50,7 @@ var checkForUpdate = function (showBanner, printErrors) { firstCheck = false; } else { try { - catalog.official.refresh(); + await catalog.official.refresh(); } catch (err) { Console.debug("Failed to refresh catalog, ignoring error", err); return; @@ -61,7 +61,7 @@ var checkForUpdate = function (showBanner, printErrors) { return; } - maybeShowBanners(); + await maybeShowBanners(); }; var lastShowTimes = {}; @@ -85,19 +85,19 @@ var shouldShow = function (key, maxAge) { return true; }; -var maybeShowBanners = function () { +var maybeShowBanners = async function () { var releaseData = release.current.getCatalogReleaseData(); var banner = releaseData.banner; if (banner) { var bannerDate = banner.lastUpdated ? new Date(banner.lastUpdated) : new Date; - if (catalog.official.shouldShowBanner(release.current.name, bannerDate)) { + if (await catalog.official.shouldShowBanner(release.current.name, bannerDate)) { // This banner is new; print it! runLog.log(""); runLog.log(banner.text); runLog.log(""); - catalog.official.setBannerShownDate(release.current.name, bannerDate); + await catalog.official.setBannerShownDate(release.current.name, bannerDate); return; } } @@ -112,10 +112,10 @@ var maybeShowBanners = function () { const catalogUtils = require('./catalog/catalog-utils.js'); // Didn't print a banner? Maybe we have a patch release to recommend. - var track = release.current.getReleaseTrack(); + var track = await release.current.getReleaseTrack(); var patchReleaseVersion = releaseData.patchReleaseVersion; if (patchReleaseVersion) { - var patchRelease = catalog.official.getReleaseVersion( + var patchRelease = await catalog.official.getReleaseVersion( track, patchReleaseVersion); if (patchRelease && patchRelease.recommended) { var patchKey = "patchrelease-" + track + "-" + patchReleaseVersion; @@ -124,7 +124,7 @@ var maybeShowBanners = function () { "=> A patch (" + catalogUtils.displayRelease(track, patchReleaseVersion) + ") for your current release is available!"); - runLog.log(" Check the changelog https://docs.meteor.com/changelog.html and update this project now with 'meteor update --patch'."); + runLog.log(" Check the changelog https://docs.meteor.com/history.html and update this project now with 'meteor update --patch'."); } return; } @@ -135,14 +135,14 @@ var maybeShowBanners = function () { // XXX maybe run constraint solver to change the message depending on whether // or not it will actually work? var currentReleaseOrderKey = releaseData.orderKey || null; - var futureReleases = catalog.official.getSortedRecommendedReleaseVersions( + var futureReleases = await catalog.official.getSortedRecommendedReleaseVersions( track, currentReleaseOrderKey); if (futureReleases.length) { var futureReleaseKey = "futurerelease-" + track + "-" + futureReleases[0]; if (shouldShow(futureReleaseKey)) { runLog.log( "=> " + catalogUtils.displayRelease(track, futureReleases[0]) + - " is available. Check the changelog https://docs.meteor.com/changelog.html and update this project with 'meteor update'."); + " is available. Check the changelog https://docs.meteor.com/history.html and update this project with 'meteor update'."); } return; } @@ -150,17 +150,17 @@ var maybeShowBanners = function () { // Update ~/.meteor/meteor to point to the tool binary from the tools of the // latest recommended release on the default release track. -export function updateMeteorToolSymlink(printErrors) { +export async function updateMeteorToolSymlink(printErrors) { // Get the latest release version of METEOR. (*Always* of the default // track, not of whatever we happen to be running: we always want the tool // symlink to go to the default track.) - var latestReleaseVersion = catalog.official.getDefaultReleaseVersion(); + var latestReleaseVersion = await catalog.official.getDefaultReleaseVersion(); // Maybe you're on some random track with nothing recommended. That's OK. if (!latestReleaseVersion) { return; } - var latestRelease = catalog.official.getReleaseVersion( + var latestRelease = await catalog.official.getReleaseVersion( latestReleaseVersion.track, latestReleaseVersion.version); if (!latestRelease) { throw Error("latest release doesn't exist?"); @@ -183,8 +183,8 @@ export function updateMeteorToolSymlink(printErrors) { // and then update the symlink. var packageMap = packageMapModule.PackageMap.fromReleaseVersion(latestRelease); - var messages = buildmessage.capture(function () { - tropohouse.default.downloadPackagesMissingFromMap(packageMap); + var messages = await buildmessage.capture(async function () { + await tropohouse.default.downloadPackagesMissingFromMap(packageMap); }); if (messages.hasMessages()) { // Ignore errors because we are running in the background, uness we @@ -197,7 +197,7 @@ export function updateMeteorToolSymlink(printErrors) { } var toolIsopack = new isopack.Isopack; - toolIsopack.initFromPath( + await toolIsopack.initFromPath( latestReleaseToolPackage, tropohouse.default.packagePath(latestReleaseToolPackage, latestReleaseToolVersion)); @@ -213,7 +213,7 @@ export function updateMeteorToolSymlink(printErrors) { throw Error("latest release has no tool?"); } - tropohouse.default.linkToLatestMeteor(files.pathJoin( + await tropohouse.default.linkToLatestMeteor(files.pathJoin( relativeToolPath, toolRecord.path, 'meteor')); } } diff --git a/tools/packaging/warehouse.js b/tools/packaging/warehouse.js index a8e42166e2..e31ab0f7c7 100644 --- a/tools/packaging/warehouse.js +++ b/tools/packaging/warehouse.js @@ -191,7 +191,7 @@ Object.assign(warehouse, { // fetches the manifest file for the given release version. also fetches // all of the missing versioned packages referenced from the release manifest // @param releaseVersion {String} eg "0.1" - _populateWarehouseForRelease: function (releaseVersion, showInstalling) { + _populateWarehouseForRelease: async function (releaseVersion, showInstalling) { var releasesDir = files.pathJoin(warehouse.getWarehouseDir(), 'releases'); files.mkdir_p(releasesDir, 0o755); var releaseManifestPath = files.pathJoin(releasesDir, @@ -221,7 +221,7 @@ Object.assign(warehouse, { } try { - var result = httpHelpers.request( + var result = await httpHelpers.request( WAREHOUSE_URLBASE + "/releases/" + releaseVersion + ".release.json"); } catch (e) { throw new files.OfflineError(e); diff --git a/tools/project-context.js b/tools/project-context.js index 97786ea20e..f114f3a38a 100644 --- a/tools/project-context.js +++ b/tools/project-context.js @@ -1,3 +1,4 @@ +import { normalizeModernConfig, setMeteorConfig } from "./tool-env/meteor-config"; var assert = require("assert"); var _ = require('underscore'); @@ -77,6 +78,10 @@ const KNOWN_ISOBUILD_FEATURE_PACKAGES = { // allowed to return a Promise instead of having to await async // compilation using fibers and/or futures. 'isobuild:async-plugins': ['1.6.1'], + + // This package requires functionality introduced in meteor-tools@3.0 + // to enable using top level await + 'isobuild:top-level-await': ['3.0.0'], } import { @@ -310,59 +315,92 @@ Object.assign(ProjectContext.prototype, { self._readResolverResultCache(); }, - readProjectMetadata: function () { + /** + * + * @return {Promise<*|undefined>} + */ + readProjectMetadata: async function () { // don't generate a profiling report for this stage (Profile.run), // because all we do here is read a handful of files. - this._completeStagesThrough(STAGE.READ_PROJECT_METADATA); + return this._completeStagesThrough(STAGE.READ_PROJECT_METADATA); }, + /** + * + * @return {Promise<*|undefined>} + */ initializeCatalog: function () { - Profile.run('ProjectContext initializeCatalog', () => { - this._completeStagesThrough(STAGE.INITIALIZE_CATALOG); + return Profile.run('ProjectContext initializeCatalog', async () => { + return this._completeStagesThrough(STAGE.INITIALIZE_CATALOG); }); }, + /** + * + * @return {Promise<*|undefined>} + */ resolveConstraints: function () { - Profile.run('ProjectContext resolveConstraints', () => { - this._completeStagesThrough(STAGE.RESOLVE_CONSTRAINTS); - }); - }, - downloadMissingPackages: function () { - Profile.run('ProjectContext downloadMissingPackages', () => { - this._completeStagesThrough(STAGE.DOWNLOAD_MISSING_PACKAGES); - }); - }, - buildLocalPackages: function () { - Profile.run('ProjectContext buildLocalPackages', () => { - this._completeStagesThrough(STAGE.BUILD_LOCAL_PACKAGES); - }); - }, - saveChangedMetadata: function () { - Profile.run('ProjectContext saveChangedMetadata', () => { - this._completeStagesThrough(STAGE.SAVE_CHANGED_METADATA); - }); - }, - prepareProjectForBuild: function () { - // This is the same as saveChangedMetadata, but if we insert stages after - // that one it will continue to mean "fully finished". - Profile.run('ProjectContext prepareProjectForBuild', () => { - this._completeStagesThrough(STAGE.SAVE_CHANGED_METADATA); + return Profile.run('ProjectContext resolveConstraints', async () => { + return this._completeStagesThrough(STAGE.RESOLVE_CONSTRAINTS); }); }, + /** + * + * @return {Promise<*|undefined>} + */ + downloadMissingPackages: function () { + return Profile.run('ProjectContext downloadMissingPackages', async () => { + return this._completeStagesThrough(STAGE.DOWNLOAD_MISSING_PACKAGES); + }); + }, + /** + * + * @return {Promise<*|undefined>} + */ + buildLocalPackages: function () { + return Profile.run('ProjectContext buildLocalPackages', async () => { + return this._completeStagesThrough(STAGE.BUILD_LOCAL_PACKAGES); + }); + }, + /** + * + * @return {Promise<*|undefined>} + */ + saveChangedMetadata: function () { + return Profile.run('ProjectContext saveChangedMetadata', async () => { + return this._completeStagesThrough(STAGE.SAVE_CHANGED_METADATA); + }); + }, + /** + * + * @return {Promise<*|undefined>} + */ + prepareProjectForBuild: function () { + // This is the same as saveChangedMetadata, but if we insert stages after + // that one it will continue to mean "fully finished". + return Profile.run('ProjectContext prepareProjectForBuild', async () => { + return this._completeStagesThrough(STAGE.SAVE_CHANGED_METADATA); + }); + }, + + /** + * + * @return {Promise<*|undefined>} + */ _completeStagesThrough: function (targetStage) { var self = this; buildmessage.assertInCapture(); - buildmessage.enterJob('preparing project', function () { + return buildmessage.enterJob('preparing project', async function () { while (self._completedStage !== targetStage) { // This error gets thrown if you request to go to a stage that's earlier // than where you started. Note that the error will be mildly confusing // because the key of STAGE does not match the value. - if (self.completedStage === STAGE.SAVE_CHANGED_METADATA) + if (self._completedStage === STAGE.SAVE_CHANGED_METADATA) throw Error("can't find requested stage " + targetStage); // The actual value of STAGE.FOO is the name of the method that takes // you to the next step after FOO. - self[self._completedStage](); + await self[self._completedStage](); if (buildmessage.jobHasMessages()) return; } @@ -384,13 +422,17 @@ Object.assign(ProjectContext.prototype, { // // This should be pretty fast --- for example, we shouldn't worry about // needing to wait for it to be done before we open the runner proxy. - _readProjectMetadata: Profile('_readProjectMetadata', function () { + /** + * + * @return {Promise} + */ + _readProjectMetadata: Profile('_readProjectMetadata', async function () { var self = this; buildmessage.assertInCapture(); - buildmessage.enterJob('reading project metadata', function () { + await buildmessage.enterJob('reading project metadata', async function () { // Ensure this is actually a project directory. - self._ensureProjectDir(); + await self._ensureProjectDir(); if (buildmessage.jobHasMessages()) return; @@ -399,6 +441,7 @@ Object.assign(ProjectContext.prototype, { projectDir: self.projectDir, catalog: self._officialCatalog, }); + await self.releaseFile.init(); if (buildmessage.jobHasMessages()) return; @@ -421,6 +464,7 @@ Object.assign(ProjectContext.prototype, { self.cordovaPluginsFile = new exports.CordovaPluginsFile({ projectDir: self.projectDir }); + await self.cordovaPluginsFile.init(); if (buildmessage.jobHasMessages()) return; @@ -428,11 +472,13 @@ Object.assign(ProjectContext.prototype, { self.platformList = new exports.PlatformList({ projectDir: self.projectDir }); + await self.platformList._init(); + if (buildmessage.jobHasMessages()) return; // Read .meteor/.id, creating it if necessary. - self._ensureAppIdentifier(); + await self._ensureAppIdentifier(); if (buildmessage.jobHasMessages()) return; @@ -447,6 +493,8 @@ Object.assign(ProjectContext.prototype, { self.meteorConfig = new MeteorConfig({ appDirectory: self.projectDir, }); + self.meteorConfig._ensureInitialized(); + if (buildmessage.jobHasMessages()) { return; } @@ -457,12 +505,12 @@ Object.assign(ProjectContext.prototype, { // Write the new release to .meteor/release and create a // .meteor/dev_bundle symlink to the corresponding dev_bundle. - writeReleaseFileAndDevBundleLink(releaseName) { + async writeReleaseFileAndDevBundleLink(releaseName) { assert.strictEqual(files.inCheckout(), false); - this.releaseFile.write(releaseName); + await this.releaseFile.write(releaseName); }, - _ensureProjectDir: function () { + _ensureProjectDir: async function () { var self = this; files.mkdir_p(files.pathJoin(self.projectDir, '.meteor')); @@ -470,13 +518,13 @@ Object.assign(ProjectContext.prototype, { // so let's make sure it exists! var constraintFilePath = files.pathJoin(self.projectDir, '.meteor', 'packages'); if (! files.exists(constraintFilePath)) { - files.writeFileAtomically(constraintFilePath, ''); + await files.writeFileAtomically(constraintFilePath, ''); } // Let's also make sure we have a minimal gitignore. var gitignorePath = files.pathJoin(self.projectDir, '.meteor', '.gitignore'); if (! files.exists(gitignorePath)) { - files.writeFileAtomically(gitignorePath, 'local\n'); + await files.writeFileAtomically(gitignorePath, 'local\n'); } }, @@ -523,7 +571,7 @@ Object.assign(ProjectContext.prototype, { return self.isopackCache.getLintingMessagesForLocalPackages(); }, - _ensureAppIdentifier: function () { + _ensureAppIdentifier: async function () { var self = this; var identifierFile = files.pathJoin(self.projectDir, '.meteor', '.id'); @@ -548,17 +596,16 @@ Object.assign(ProjectContext.prototype, { "# - ensuring you don't accidentally deploy one app on top of another\n" + "# - providing package authors with aggregated statistics\n" + "\n"); - files.writeFileAtomically(identifierFile, comment + appId + '\n'); + await files.writeFileAtomically(identifierFile, comment + appId + '\n'); } self.appIdentifier = appId; }, - _resolveConstraints: Profile('_resolveConstraints', function () { + _resolveConstraints: Profile('_resolveConstraints', async function () { var self = this; buildmessage.assertInJob(); - - var depsAndConstraints = self._getRootDepsAndConstraints(); + var depsAndConstraints = await self._getRootDepsAndConstraints(); // If this is in the runner and we have reset this ProjectContext for a // rebuild, use the versions we calculated last time in this process (which // may not have been written to disk if our release doesn't match the @@ -589,9 +636,9 @@ Object.assign(ProjectContext.prototype, { // Nothing before this point looked in the official or project catalog! // However, the resolver does, so it gets run in the retry context. - catalog.runAndRetryWithRefreshIfHelpful(function (canRetry) { - buildmessage.enterJob("selecting package versions", function () { - var resolver = self._buildResolver(); + await catalog.runAndRetryWithRefreshIfHelpful(function (canRetry) { + return buildmessage.enterJob("selecting package versions", async function () { + var resolver = await self._buildResolver(); var resolveOptions = { previousSolution: cachedVersions, @@ -618,11 +665,11 @@ Object.assign(ProjectContext.prototype, { var solution; try { - Profile.time( + await Profile.time( "Select Package Versions" + (resolverRunCount > 1 ? (" (Try " + resolverRunCount + ")") : ""), - function () { - solution = resolver.resolve( + async function () { + solution = await resolver.resolve( depsAndConstraints.deps, depsAndConstraints.constraints, resolveOptions); }); @@ -655,7 +702,9 @@ Object.assign(ProjectContext.prototype, { anticipatedPrereleases: anticipatedPrereleases }); - self._saveResolverResultCache(); + await self.packageMapDelta.init(); + + await self._saveResolverResultCache(); self._completedStage = STAGE.RESOLVE_CONSTRAINTS; }); @@ -679,8 +728,8 @@ Object.assign(ProjectContext.prototype, { return this._resolverResultCache; }, - _saveResolverResultCache() { - files.writeFileAtomically( + async _saveResolverResultCache() { + await files.writeFileAtomically( files.pathJoin( this.projectLocalDir, "resolver-result-cache.json" @@ -700,8 +749,8 @@ Object.assign(ProjectContext.prototype, { } }, - saveBuildCache(buildCache) { - files.writeFileAtomically( + async saveBuildCache(buildCache) { + await files.writeFileAtomically( files.pathJoin( this.projectLocalDir, "build-cache.json" @@ -777,20 +826,19 @@ Object.assign(ProjectContext.prototype, { // but does not compile the packages. // // Must be run in a buildmessage context. On build error, returns null. - _initializeCatalog: Profile('_initializeCatalog', function () { + _initializeCatalog: Profile('_initializeCatalog', async function () { var self = this; buildmessage.assertInJob(); - - catalog.runAndRetryWithRefreshIfHelpful(function () { - buildmessage.enterJob( + await catalog.runAndRetryWithRefreshIfHelpful(async function () { + return await buildmessage.enterJob( "scanning local packages", - function () { - self.localCatalog = new catalogLocal.LocalCatalog; + async function () { + self.localCatalog = new catalogLocal.LocalCatalog(); self.projectCatalog = new catalog.LayeredCatalog( self.localCatalog, self._officialCatalog); var searchDirs = self._localPackageSearchDirs(); - self.localCatalog.initialize({ + await self.localCatalog.initialize({ localPackageSearchDirs: searchDirs, explicitlyAddedLocalPackageDirs: self._explicitlyAddedLocalPackageDirs }); @@ -816,14 +864,14 @@ Object.assign(ProjectContext.prototype, { }); }), - _getRootDepsAndConstraints: function () { + _getRootDepsAndConstraints: async function () { const depsAndConstraints = { deps: [], constraints: [], }; this._addAppConstraints(depsAndConstraints); - this._addLocalPackageConstraints(depsAndConstraints); + await this._addLocalPackageConstraints(depsAndConstraints); this._addReleaseConstraints(depsAndConstraints); return depsAndConstraints; @@ -838,16 +886,17 @@ Object.assign(ProjectContext.prototype, { }); }, - _addLocalPackageConstraints: function (depsAndConstraints) { + _addLocalPackageConstraints: async function (depsAndConstraints) { var self = this; - _.each(self.localCatalog.getAllPackageNames(), function (packageName) { + const packageNames = await self.localCatalog.getAllPackageNames(); + packageNames.forEach((packageName) => { var versionRecord = self.localCatalog.getLatestVersion(packageName); var constraint = utils.parsePackageConstraint( - packageName + "@=" + versionRecord.version); + packageName + "@=" + versionRecord.version); // Add a constraint ("this is the only version available") but no // dependency (we don't automatically use all local packages!) depsAndConstraints.constraints.push(constraint); - }); + }) }, _addReleaseConstraints: function (depsAndConstraints) { @@ -898,27 +947,27 @@ Object.assign(ProjectContext.prototype, { return anticipatedPrereleases; }, - _buildResolver: function () { - const { ConstraintSolver } = loadIsopackage('constraint-solver'); + _buildResolver: async function () { + const { ConstraintSolver } = await loadIsopackage('constraint-solver'); return new ConstraintSolver.PackagesResolver(this.projectCatalog, { - nudge() { - Console.nudge(true); + yield() { + return Console.yield(); }, Profile: Profile, resultCache: this._resolverResultCache }); }, - _downloadMissingPackages: Profile('_downloadMissingPackages', function () { + _downloadMissingPackages: Profile('_downloadMissingPackages', async function () { var self = this; buildmessage.assertInJob(); if (!self.packageMap) throw Error("which packages to download?"); - catalog.runAndRetryWithRefreshIfHelpful(function () { - buildmessage.enterJob("downloading missing packages", function () { - self.tropohouse.downloadPackagesMissingFromMap(self.packageMap, { + await catalog.runAndRetryWithRefreshIfHelpful(function () { + return buildmessage.enterJob("downloading missing packages", async function () { + await self.tropohouse.downloadPackagesMissingFromMap(self.packageMap, { serverArchitectures: self._serverArchitectures }); if (buildmessage.jobHasMessages()) @@ -928,12 +977,12 @@ Object.assign(ProjectContext.prototype, { }); }), - _buildLocalPackages: Profile('_buildLocalPackages', function () { + _buildLocalPackages: Profile('_buildLocalPackages', async function () { var self = this; buildmessage.assertInCapture(); - self.packageMap.eachPackage((name, packageInfo) => { + await self.packageMap.eachPackage((name, packageInfo) => { if (packageInfo.kind === 'local') { addWatchRoot(packageInfo.packageSource.sourceRoot) } @@ -952,23 +1001,23 @@ Object.assign(ProjectContext.prototype, { }); if (self._forceRebuildPackages) { - self.isopackCache.wipeCachedPackages( + await self.isopackCache.wipeCachedPackages( self._forceRebuildPackages === true ? null : self._forceRebuildPackages); } - buildmessage.enterJob('building local packages', function () { - self.isopackCache.buildLocalPackages(); + await buildmessage.enterJob('building local packages', async function () { + return await self.isopackCache.buildLocalPackages(); }); self._completedStage = STAGE.BUILD_LOCAL_PACKAGES; }), - _saveChangedMetadata: Profile('_saveChangedMetadata', function () { + _saveChangedMetadata: Profile('_saveChangedMetadata', async function () { var self = this; // Save any changes to .meteor/packages. if (! self._neverWriteProjectConstraintsFile) - self.projectConstraintsFile.writeIfModified(); + await self.projectConstraintsFile.writeIfModified(); // Write .meteor/versions if the command always wants to (create/update), // or if the release of the app matches the release of the process. @@ -978,7 +1027,7 @@ Object.assign(ProjectContext.prototype, { (! release.current.isCheckout() && release.current.name === self.releaseFile.fullReleaseName))) { - self.packageMapFile.write(self.packageMap); + await self.packageMapFile.write(self.packageMap); } self._completedStage = STAGE.SAVE_CHANGED_METADATA; @@ -1093,12 +1142,12 @@ Object.assign(exports.ProjectConstraintsFile.prototype, { }); }, - writeIfModified: function () { + writeIfModified: async function () { var self = this; - self._modified && self._write(); + self._modified && (await self._write()); }, - _write: function () { + _write: async function () { var self = this; var lines = _.map(self._constraintLines, function (lineRecord) { // Don't write packages that were not loaded from .meteor/packages @@ -1114,11 +1163,11 @@ Object.assign(exports.ProjectConstraintsFile.prototype, { lineParts.push(lineRecord.trailingSpaceAndComment, '\n'); return lineParts.join(''); }); - files.writeFileAtomically(self.filename, lines.join('')); - var messages = buildmessage.capture( + await files.writeFileAtomically(self.filename, lines.join('')); + var messages = await buildmessage.capture( { title: 're-reading .meteor/packages' }, function () { - self._readFile(); + return self._readFile(); }); // We shouldn't choke on something we just wrote! if (messages.hasMessages()) @@ -1135,6 +1184,14 @@ Object.assign(exports.ProjectConstraintsFile.prototype, { }); }, + eachConstraintAsync: async function (iterator){ + const self = this; + for (const lineRecord of self._constraintLines) { + if (! lineRecord.skipOnRead && lineRecord.constraint) + await iterator(lineRecord.constraint); + } + }, + // Returns the constraint in the format returned by // utils.parsePackageConstraint, or null. getConstraint: function (name) { @@ -1163,7 +1220,16 @@ Object.assign(exports.ProjectConstraintsFile.prototype, { constraint: constraintToAdd, trailingSpaceAndComment: '' }; - self._constraintLines.push(lineRecord); + if (constraintToAdd.package === 'npm-mongo-legacy') { + const mongoIdx = self._constraintLines.findIndex(lr => lr.constraint && lr.constraint.package === 'mongo'); + if (mongoIdx > -1) { + self._constraintLines.splice(mongoIdx, 0, lineRecord); + } else { + self._constraintLines.push(lineRecord); + } + } else { + self._constraintLines.push(lineRecord); + } self._constraintMap[constraintToAdd.package] = lineRecord; self._modified = true; return; @@ -1294,7 +1360,7 @@ Object.assign(exports.PackageMapFile.prototype, { return _.clone(self._versions); }, - write: function (packageMap) { + write: async function (packageMap) { var self = this; var newVersions = packageMap.toVersionMap(); @@ -1311,7 +1377,7 @@ Object.assign(exports.PackageMapFile.prototype, { lines.push(packageName + "@" + self._versions[packageName] + "\n"); }); var fileContents = Buffer.from(lines.join('')); - files.writeFileAtomically(self.filename, fileContents); + await files.writeFileAtomically(self.filename, fileContents); // Replace our watchSet with one for the new contents of the file. var hash = watch.sha1(fileContents); @@ -1330,15 +1396,17 @@ exports.PlatformList = function (options) { self.filename = files.pathJoin(options.projectDir, '.meteor', 'platforms'); self.watchSet = null; self._platforms = null; - - self._readFile(); }; // These platforms are always present and can be neither added or removed exports.PlatformList.DEFAULT_PLATFORMS = ['browser', 'server']; Object.assign(exports.PlatformList.prototype, { - _readFile: function () { + _init: async function() { + const self = this; + await self._readFile(); + }, + _readFile: async function () { var self = this; // Reset the WatchSet. @@ -1358,7 +1426,7 @@ Object.assign(exports.PlatformList.prototype, { // Write the platforms to disk (automatically adding DEFAULT_PLATFORMS and // sorting), which automatically calls this function recursively to // re-reads them. - self.write(platforms); + await self.write(platforms); return; } @@ -1367,14 +1435,14 @@ Object.assign(exports.PlatformList.prototype, { // Replaces the current platform file with the given list and resets this // object (and its WatchSet) to track the new value. - write: function (platforms) { + write: async function (platforms) { var self = this; self._platforms = null; platforms = _.uniq( platforms.concat(exports.PlatformList.DEFAULT_PLATFORMS)); platforms.sort(); - files.writeFileAtomically(self.filename, platforms.join('\n') + '\n'); - self._readFile(); + await files.writeFileAtomically(self.filename, platforms.join('\n') + '\n'); + await self._readFile(); }, getPlatforms: function () { @@ -1421,11 +1489,13 @@ exports.CordovaPluginsFile = function (options) { self.watchSet = null; // Map from plugin name to version. self._plugins = null; - - self._readFile(); }; Object.assign(exports.CordovaPluginsFile.prototype, { + init: async function() { + const self = this; + await self._readFile(); + }, _readFile: function () { var self = this; buildmessage.assertInCapture(); @@ -1471,18 +1541,18 @@ Object.assign(exports.CordovaPluginsFile.prototype, { return _.clone(self._plugins); }, - write: function (plugins) { + write: async function (plugins) { var self = this; var pluginNames = Object.keys(plugins); pluginNames.sort(); var lines = _.map(pluginNames, function (pluginName) { return pluginName + '@' + plugins[pluginName] + '\n'; }); - files.writeFileAtomically(self.filename, lines.join('')); - var messages = buildmessage.capture( + await files.writeFileAtomically(self.filename, lines.join('')); + var messages = await buildmessage.capture( { title: 're-reading .meteor/cordova-plugins' }, - function () { - self._readFile(); + async function () { + await self._readFile(); }); // We shouldn't choke on something we just wrote! if (messages.hasMessages()) @@ -1511,10 +1581,13 @@ exports.ReleaseFile = function (options) { // Just the track. self.releaseTrack = null; self.releaseVersion = null; - self._readFile(); }; Object.assign(exports.ReleaseFile.prototype, { + init: async function() { + const self = this; + await self._readFile(); + }, fileMissing: function () { var self = this; return self.unnormalizedReleaseName === null; @@ -1533,7 +1606,7 @@ Object.assign(exports.ReleaseFile.prototype, { || self.isCheckout()); }, - _readFile: function () { + _readFile: async function () { var self = this; // Start a new watchSet, in case we just overwrote this. @@ -1561,18 +1634,18 @@ Object.assign(exports.ReleaseFile.prototype, { self.releaseTrack = parts[0]; self.releaseVersion = parts[1]; - self.ensureDevBundleLink(); + await self.ensureDevBundleLink(); }, // Returns an absolute path to the dev_bundle appropriate for the // release specified in the .meteor/release file. - getDevBundle() { + async getDevBundle() { let devBundle = files.getDevBundle(); const devBundleParts = devBundle.split(files.pathSep); const meteorToolIndex = devBundleParts.lastIndexOf("meteor-tool"); if (meteorToolIndex >= 0) { - const releaseVersion = this.catalog.getReleaseVersion( + const releaseVersion = await this.catalog.getReleaseVersion( this.releaseTrack, this.releaseVersion ); @@ -1593,7 +1666,7 @@ Object.assign(exports.ReleaseFile.prototype, { }, // Make a symlink from .meteor/local/dev_bundle to the actual dev_bundle. - ensureDevBundleLink() { + async ensureDevBundleLink() { import { makeLink, readLink } from "./cli/dev-bundle-links.js"; const dotMeteorDir = files.pathDirname(this.filename); @@ -1603,7 +1676,7 @@ Object.assign(exports.ReleaseFile.prototype, { if (this.isCheckout()) { // Only create .meteor/local/dev_bundle if .meteor/release refers to // an actual release, and remove it otherwise. - files.rm_recursive(devBundleLink); + await files.rm_recursive_deferred(devBundleLink); return; } @@ -1612,7 +1685,7 @@ Object.assign(exports.ReleaseFile.prototype, { return; } - const newTarget = this.getDevBundle(); + const newTarget = await this.getDevBundle(); if (! newTarget) { return; } @@ -1638,10 +1711,10 @@ Object.assign(exports.ReleaseFile.prototype, { } }, - write: function (releaseName) { + write: async function (releaseName) { var self = this; - files.writeFileAtomically(self.filename, releaseName + '\n'); - self._readFile(); + await files.writeFileAtomically(self.filename, releaseName + '\n'); + await self._readFile(); } }); @@ -1674,6 +1747,9 @@ Object.assign(exports.FinishedUpgraders.prototype, { appendUpgraders: function (upgraders) { var self = this; + /** + * @type {string} + */ var current = null; try { current = files.readFile(self.filename, 'utf8'); @@ -1718,27 +1794,57 @@ export class MeteorConfig { const json = optimisticReadJsonOrNull(this.packageJsonPath); this._config = json && json.meteor || null; this.watchSet.addFile( - this.packageJsonPath, - optimisticHashOrNull(this.packageJsonPath) + this.packageJsonPath, + optimisticHashOrNull(this.packageJsonPath) ); } + const customMeteorConfigClient = process.env.METEOR_CONFIG_CLIENT; + const customMeteorConfigServer = process.env.METEOR_CONFIG_SERVER; + const customMeteorConfigTest = process.env.METEOR_CONFIG_TEST; + const customMeteorConfigTestClient = process.env.METEOR_CONFIG_TEST_CLIENT; + const customMeteorConfigTestServer = process.env.METEOR_CONFIG_TEST_SERVER; + this._config = + customMeteorConfigClient != null || + customMeteorConfigServer != null || + customMeteorConfigTest != null || + customMeteorConfigTestClient != null || + customMeteorConfigTestServer != null ? { + ...this._config || {}, + mainModule: { + client: process.env.METEOR_CONFIG_CLIENT || this._config.mainModule.client, + server: process.env.METEOR_CONFIG_SERVER || this._config.mainModule.server, + }, + ...customMeteorConfigTest && {testModule: customMeteorConfigTest}, + ...((customMeteorConfigTestClient || customMeteorConfigTestServer) && { + testModule: { + client: customMeteorConfigTestClient || this._config.testModule.client, + server: customMeteorConfigTestServer || this._config.testModule.server, + }, + }), + } : this._config; + const modernForced = JSON.parse(process.env.METEOR_MODERN || "false"); + // Reinitialize meteorConfig globally for project context + // Updates config when package.json changes trigger rebuilds + setMeteorConfig({ + ...(this._config || {}), + modern: normalizeModernConfig(modernForced || this._config?.modern || false), + }); + return this._config; } // General utility for querying the "meteor" section of package.json. // TODO Implement an API for setting these values? get(...keys) { - let config = this._ensureInitialized(); - if (config) { - keys.every(key => { - if (config && _.has(config, key)) { - config = config[key]; - return true; - } - }); - return config; - } + const config = this._ensureInitialized(); + if (!config) return undefined; + + return keys.reduce((cur, key) => { + return (cur != null && _.has(cur, key)) + ? cur[key] + : undefined; + }, config); } getNodeModulesToRecompileByArch() { diff --git a/tools/runners/run-all.js b/tools/runners/run-all.js index 04fa462eff..594e20589c 100644 --- a/tools/runners/run-all.js +++ b/tools/runners/run-all.js @@ -17,28 +17,34 @@ const HMRServer = require('./run-hmr').HMRServer; const Updater = require('./run-updater').Updater; class Runner { - constructor({ - appHost, - appPort, - banner, - disableOplog, - cordovaRunner, - mongoUrl, - onFailure, - oplogUrl, - projectContext, - proxyHost, - proxyPort, - quiet, - rootUrl, - selenium, - seleniumBrowser, - noReleaseCheck, - cordovaServerPort, - ...optionsForAppRunner - }) { + constructor(options) { const self = this; - self.projectContext = projectContext; + self.options = options; + self.projectContext = options.projectContext; + } + + async init() { + const self = this; + let { + appHost, + appPort, + banner, + disableOplog, + cordovaRunner, + mongoUrl, + onFailure, + oplogUrl, + projectContext, + proxyHost, + proxyPort, + quiet, + rootUrl, + selenium, + seleniumBrowser, + noReleaseCheck, + cordovaServerPort, + ...optionsForAppRunner + } = self.options; if (typeof proxyPort === 'undefined') { throw new Error('no proxyPort?'); @@ -53,7 +59,7 @@ class Runner { self.noReleaseCheck = noReleaseCheck; self.quiet = quiet; self.banner = banner || files.convertToOSPath( - files.prettyPath(self.projectContext.projectDir) + files.prettyPath(self.projectContext.projectDir) ); if (rootUrl) { @@ -78,13 +84,13 @@ class Runner { ignoredUrls: [HMRPath] }); - buildmessage.capture(function () { - self.projectContext.resolveConstraints(); + await buildmessage.capture(async function () { + await self.projectContext.resolveConstraints(); }); const packageMap = self.projectContext.packageMap; const hasMongoDevServerPackage = - packageMap && packageMap.getInfo('mongo-dev-server') != null; + packageMap && packageMap.getInfo('mongo-dev-server') != null; self.mongoRunner = null; if (mongoUrl) { oplogUrl = disableOplog ? null : oplogUrl; @@ -113,7 +119,7 @@ class Runner { } const hasHotModuleReplacementPackage = packageMap && - packageMap.getInfo('hot-module-replacement') != null; + packageMap.getInfo('hot-module-replacement') != null; self.hmrServer = null; let hmrSecret = null; if (hasHotModuleReplacementPackage) { @@ -152,12 +158,11 @@ class Runner { }); } } - // XXX leave a pidfile and check if we are already running - start() { + async start() { const self = this; - self.proxy.start(); + await self.proxy.start(); // print the banner only once we've successfully bound the port if (! self.quiet && ! self.stopped) { @@ -168,23 +173,20 @@ class Runner { var unblockAppRunner = self.appRunner.makeBeforeStartPromise(); function startMongo(tries = 3) { - self._startMongoAsync().then( - ok => unblockAppRunner(), - error => { + self + ._startMongoAsync() + .then(() => unblockAppRunner()) + .catch(async (error) => { --tries; const left = tries + (tries === 1 ? " try" : " tries"); - Console.error( - `Error starting Mongo (${left} left): ${error.message}` - ); - + Console.error(`Error starting Mongo (${left} left): ${error.message}`); if (tries > 0) { self.mongoRunner.stop(); setTimeout(() => startMongo(tries), 1000); } else { - self.mongoRunner._fail(); + await self.mongoRunner._fail(); } - } - ); + }); } startMongo(); @@ -202,9 +204,7 @@ class Runner { } if (! self.stopped) { - buildmessage.enterJob({ title: "starting your app" }, function () { - self.appRunner.start(); - }); + await buildmessage.enterJob({ title: "starting your app" }, () => self.appRunner.start()); if (! self.quiet && ! self.stopped) { runLog.log("Started your app.", { arrow: true }); } @@ -228,8 +228,8 @@ class Runner { } if (self.selenium && ! self.stopped) { - buildmessage.enterJob({ title: "starting Selenium" }, function () { - self.selenium.start(); + await buildmessage.enterJob({ title: "starting Selenium" }, async function () { + return await self.selenium.start(); }); if (! self.quiet && ! self.stopped) { runLog.log("Started Selenium.", { arrow: true }); @@ -244,7 +244,7 @@ class Runner { async _startMongoAsync() { if (! this.stopped && this.mongoRunner) { - this.mongoRunner.start(); + await this.mongoRunner.start(); if (! this.stopped && ! this.quiet) { runLog.log("Started MongoDB.", { arrow: true }); } @@ -252,18 +252,18 @@ class Runner { } // Idempotent - stop() { + async stop() { const self = this; if (self.stopped) { return; } self.stopped = true; - self.proxy.stop(); - self.updater.stop(); - self.mongoRunner && self.mongoRunner.stop(); - self.appRunner.stop(); - self.selenium && self.selenium.stop(); + await self.proxy.stop(); + await self.updater.stop(); + await self.mongoRunner && self.mongoRunner.stop(); + await self.appRunner.stop(); + await (self.selenium && self.selenium.stop()); // XXX does calling this 'finish' still make sense now that runLog is a // singleton? runLog.finish(); @@ -317,6 +317,7 @@ class Runner { // - buildOptions: 'buildOptions' argument to bundler.bundle() // - settingsFile: path to file containing deploy-time settings // - once: see above +// - onBuilt: callback to call when the app bundle is built // - banner: replace the application path that is normally printed on // startup with an arbitrary string (eg, 'Tests') // - rootUrl: tell the app that traffic at this URL will be routed to @@ -331,18 +332,19 @@ class Runner { // - recordPackageUsage: (default true) if set to false, don't send // information about packages used by this app to the package stats // server. -exports.run = function (options) { +exports.run = async function (options) { var runOptions = _.clone(options); var once = runOptions.once; + var onBuilt = runOptions.onBuilt; var promise = new Promise(function (resolve) { - runOptions.onFailure = function () { + runOptions.onFailure = async function () { // Ensure that runner stops now. You might think this is unnecessary // because the runner is stopped immediately after promise.await(), but if // the failure happens while runner.start() is still running, we want the // rest of start to stop, and it's not like resolve() magically makes // us jump to a promise.await() that hasn't happened yet!. - runner.stop(); + await runner.stop(); resolve({ outcome: 'failure' }); }; @@ -395,9 +397,16 @@ exports.run = function (options) { } var runner = new Runner(runOptions); - runner.start(); - var result = promise.await(); - runner.stop(); + await runner.init(); + // don't wait this on to finish + if (runOptions.open) { + await runner.start(); + } else { + setTimeout(() => runner.start(), 0); + } + onBuilt && onBuilt(); + var result = await promise; + await runner.stop(); if (result.outcome === "conflicting-versions") { Console.error( diff --git a/tools/runners/run-app.js b/tools/runners/run-app.js index fbc3b03af5..9d92b57780 100644 --- a/tools/runners/run-app.js +++ b/tools/runners/run-app.js @@ -1,5 +1,3 @@ -var _ = require('underscore'); -var Fiber = require('fibers'); var files = require('../fs/files'); var watch = require('../fs/watch'); var bundler = require('../isobuild/bundler.js'); @@ -12,15 +10,15 @@ var Profile = require('../tool-env/profile').Profile; var release = require('../packaging/release.js'); import { pluginVersionsFromStarManifest } from '../cordova/index.js'; import { closeAllWatchers } from "../fs/safe-watcher"; -import { eachline } from "../utils/eachline"; import { loadIsopackage } from '../tool-env/isopackets.js'; +import { eachline } from "../utils/eachline"; // Parse out s as if it were a bash command line. var bashParse = function (s) { if (s.search("\"") !== -1 || s.search("'") !== -1) { throw new Error("Meteor cannot currently handle quoted SERVER_NODE_OPTIONS"); } - return _.without(s.split(/\s+/), ''); + return s.split(/\s+/).filter(Boolean); }; var getNodeOptionsFromEnvironment = function () { @@ -77,7 +75,7 @@ var AppProcess = function (options) { Object.assign(AppProcess.prototype, { // Call to start the process. - start: function () { + start: async function () { var self = this; if (self.proc) { @@ -85,28 +83,27 @@ Object.assign(AppProcess.prototype, { } // Start the app! - self.proc = self._spawn(); + self.proc = await self._spawn(); - eachline(self.proc.stdout, function (line) { + eachline(self.proc.stdout, async function (line) { if (line.match(/^LISTENING\s*$/)) { // This is the child process telling us that it's ready to receive // connections. (It does this because we told it to with // $METEOR_PRINT_ON_LISTEN.) - self.onListen && self.onListen(); - + self.onListen && await self.onListen(); } else { - runLog.logAppOutput(line); + await runLog.logAppOutput(line); } }); - eachline(self.proc.stderr, function (line) { - runLog.logAppOutput(line, true); + eachline(self.proc.stderr, async function (line) { + await runLog.logAppOutput(line, true); }); // Watch for exit and for stdio to be fully closed (so that we don't miss // log lines). self.proc.on('close', async function (code, signal) { - self._maybeCallOnExit(code, signal); + await self._maybeCallOnExit(code, signal); }); self.proc.on('error', async function (err) { @@ -115,7 +112,7 @@ Object.assign(AppProcess.prototype, { // node docs say that it might make both an 'error' and a // 'close' callback, so we use a guard to make sure we only call // onExit once. - self._maybeCallOnExit(); + await self._maybeCallOnExit(); }); // This happens sometimes when we write a keepalive after the app @@ -125,13 +122,13 @@ Object.assign(AppProcess.prototype, { self.proc.stdin.on('error', function () {}); }, - _maybeCallOnExit: function (code, signal) { + _maybeCallOnExit: async function (code, signal) { var self = this; if (self.madeExitCallback) { return; } self.madeExitCallback = true; - self.onExit && self.onExit(code, signal); + self.onExit && await self.onExit(code, signal); }, // Idempotent. Once stop() returns it is guaranteed that you will @@ -232,7 +229,7 @@ Object.assign(AppProcess.prototype, { }, // Spawn the server process and return the handle from child_process.spawn. - _spawn: function () { + _spawn: async function () { var self = this; // Path conversions @@ -240,7 +237,7 @@ Object.assign(AppProcess.prototype, { files.pathJoin(self.bundlePath, 'main.js')); // Setting options - var opts = _.clone(self.nodeOptions); + var opts = JSON.parse(JSON.stringify(self.nodeOptions)); if (self.inspect) { // Always use --inspect rather than --inspect-brk, even when @@ -253,6 +250,8 @@ Object.assign(AppProcess.prototype, { opts.push("--inspect=" + self.inspect.port); } + opts.push(`--require=${files.convertToOSPath(files.pathJoin(__dirname, '../node-process-warnings.js'))}`) + opts.push(entryPoint); // Call node @@ -266,7 +265,8 @@ Object.assign(AppProcess.prototype, { // Add a child.sendMessage(topic, payload) method to this child // process object. - loadIsopackage("inter-process-messaging").enable(child); + const interProcessMessaging = await loadIsopackage("inter-process-messaging"); + interProcessMessaging.enable(child); return child; } @@ -373,7 +373,7 @@ var AppRunner = function (options) { self.omitPackageMapDeltaDisplayOnFirstRun = options.omitPackageMapDeltaDisplayOnFirstRun; - self.fiber = null; + self.isRunning = null; self.startPromise = null; self.runPromise = null; self.exitPromise = null; @@ -395,33 +395,41 @@ var AppRunner = function (options) { Object.assign(AppRunner.prototype, { // Start the app running, and restart it as necessary. Returns // immediately. - start: function () { + start: async function () { var self = this; - if (self.fiber) { + if (self.isRunning) { throw new Error("already started?"); } self.startPromise = self._makePromise("start"); - self.fiber = Fiber(function () { - self._fiber(); - }); - self.fiber.run(); - - self.startPromise.await(); + self.isRunning = true; + global.__METEOR_ASYNC_LOCAL_STORAGE.run({}, () => + self._runApp() + .catch((e) => { + // There was an unexpected error when building the app + // This is not recoverable, so we turn it into an unhandled exception + // and crash. + setTimeout(() => { + throw e; + }); + }) + ); + await self.startPromise; self.startPromise = null; }, - _makePromise: function (name) { - var self = this; - return new Promise(function (resolve) { - self._promiseResolvers[name] = resolve; + // Creates a promise that can be resolved later by calling _resolvePromise + _makePromise (name) { + return new Promise((resolve) => { + this._promiseResolvers[name] = resolve; }); }, - _resolvePromise: function (name, value) { - var resolve = this._promiseResolvers[name]; + // Resolves a promise already created by _makePromise + _resolvePromise (name, value) { + const resolve = this._promiseResolvers[name]; if (resolve) { this._promiseResolvers[name] = null; resolve(value); @@ -430,7 +438,7 @@ Object.assign(AppRunner.prototype, { _cleanUpPromises: function () { if (this._promiseResolvers) { - _.each(this._promiseResolvers, function (resolve) { + Object.values(this._promiseResolvers).forEach(resolve => { resolve && resolve(); }); this._promiseResolvers = null; @@ -441,10 +449,10 @@ Object.assign(AppRunner.prototype, { // down. This may involve waiting for bundling to // finish. Idempotent, however only one thread may be in stop() at a // time. - stop: function () { + stop: async function () { var self = this; - if (! self.fiber) { + if (! self.isRunning) { // nothing to do return; } @@ -465,7 +473,7 @@ Object.assign(AppRunner.prototype, { self._resolvePromise("beforeStart", true); } - self.exitPromise.await(); + await self.exitPromise; self.exitPromise = null; }, @@ -475,12 +483,12 @@ Object.assign(AppRunner.prototype, { throw new Error("makeBeforeStartPromise called twice?"); } this._beforeStartPromise = this._makePromise("beforeStart"); - return this._promiseResolvers["beforeStart"]; + return () => this._resolvePromise("beforeStart"); }, // Run the program once, wait for it to exit, and then return. The // return value is same as onRunEnd. - _runOnce: function (options) { + _runOnce: async function (options) { var self = this; options = options || {}; var firstRun = options.firstRun; @@ -497,7 +505,7 @@ Object.assign(AppRunner.prototype, { // a single invocation of _runOnce(). var cachedServerWatchSet; - var bundleApp = function () { + var bundleApp = async function () { if (! firstRun) { // If the build fails in a way that could be fixed by a refresh, allow // it even if we refreshed previously, since that might have been a @@ -524,8 +532,8 @@ Object.assign(AppRunner.prototype, { // shown from the previous solution. preservePackageMap: true }); - var messages = buildmessage.capture(function () { - self.projectContext.readProjectMetadata(); + var messages = await buildmessage.capture(() => { + return self.projectContext.readProjectMetadata() }); if (messages.hasMessages()) { return { @@ -550,9 +558,7 @@ Object.assign(AppRunner.prototype, { }; } - messages = buildmessage.capture(function () { - self.projectContext.prepareProjectForBuild(); - }); + messages = await buildmessage.capture(() => self.projectContext.prepareProjectForBuild()); if (messages.hasMessages()) { return { runResult: { @@ -569,14 +575,15 @@ Object.assign(AppRunner.prototype, { } if (self.recordPackageUsage) { + // Maybe this doesn't need to be awaited for? stats.recordPackages({ what: "sdk.run", projectContext: self.projectContext }); } - var bundleResult = Profile.run((firstRun?"B":"Reb")+"uild App", () => { - return bundler.bundle({ + var bundleResult = await Profile.run((firstRun?"B":"Reb")+"uild App", async () => + bundler.bundle({ projectContext: self.projectContext, outputPath: bundlePath, includeNodeModules: "symlink", @@ -591,8 +598,7 @@ Object.assign(AppRunner.prototype, { // None of the targets are used during full rebuilds // so we can safely build in place on Windows forceInPlaceBuild: !cachedServerWatchSet - }); - }); + })); // Keep the server watch set from the initial bundle, because subsequent // bundles will not contain a server target. @@ -620,9 +626,8 @@ Object.assign(AppRunner.prototype, { watchSet.merge(br.clientWatchSet); return watchSet; }; - var bundleResult; - var bundleResultOrRunResult = bundleApp(); + var bundleResultOrRunResult = await bundleApp(); if (bundleResultOrRunResult.runResult) { return bundleResultOrRunResult.runResult; } @@ -633,10 +638,10 @@ Object.assign(AppRunner.prototype, { // Read the settings file, if any var settings = null; var settingsWatchSet = new watch.WatchSet; - var settingsMessages = buildmessage.capture({ + var settingsMessages = await buildmessage.capture({ title: "preparing to run", rootPath: process.cwd() - }, function () { + }, async function () { if (self.settingsFile) { settings = files.getSettings(self.settingsFile, settingsWatchSet); } @@ -669,8 +674,8 @@ Object.assign(AppRunner.prototype, { if (!cordovaRunner.started) { const { settingsFile, mobileServerUrl } = self; - const messages = buildmessage.capture(() => { - cordovaRunner.prepareProject(bundlePath, pluginVersions, + const messages = await buildmessage.capture(async () => { + await cordovaRunner.prepareProject(bundlePath, pluginVersions, { settingsFile, mobileServerUrl }); }); @@ -706,13 +711,13 @@ Object.assign(AppRunner.prototype, { // We should have reset self.runPromise to null by now, but await it // just in case it's still defined. - Promise.await(self.runPromise); - - var runPromise = self.runPromise = self._makePromise("run"); + await self.runPromise; + self.runPromise = self._makePromise("run"); + var runPromise = self.runPromise; var listenPromise = self._makePromise("listen"); // Run the program - options.beforeRun && options.beforeRun(); + options.beforeRun && await options.beforeRun(); var appProcess = new AppProcess({ projectContext: self.projectContext, bundlePath: bundlePath, @@ -748,13 +753,14 @@ Object.assign(AppRunner.prototype, { }); if (options.firstRun && self._beforeStartPromise) { - var stopped = self._beforeStartPromise.await(); + var stopped = await self._beforeStartPromise; if (stopped) { return true; } } - appProcess.start(); + await appProcess.start(); + function maybePrintLintWarnings(bundleResult) { if (! (self.projectContext.lintAppAndLocalPackages && bundleResult.warnings)) { @@ -773,7 +779,7 @@ Object.assign(AppRunner.prototype, { maybePrintLintWarnings(bundleResult); if (cordovaRunner && !cordovaRunner.started) { - cordovaRunner.startRunTargets(); + await cordovaRunner.startRunTargets(); } // Start watching for changes for files if requested. There's no @@ -842,22 +848,22 @@ Object.assign(AppRunner.prototype, { await appProcess.proc.sendMessage("client-refresh"); } - function runPostStartupCallbacks(bundleResult) { + async function runPostStartupCallbacks(bundleResult) { const callbacks = bundleResult.postStartupCallbacks; if (! callbacks) return; - const messages = buildmessage.capture({ + const messages = await buildmessage.capture({ title: "running post-startup callbacks" - }, () => { + }, async () => { while (callbacks.length > 0) { const fn = callbacks.shift(); try { - Promise.await(fn({ + await fn({ // Miscellany that the callback might find useful. pauseClient, refreshClient, runLog, - })); + }); } catch (error) { buildmessage.error(error.message); } @@ -875,19 +881,17 @@ Object.assign(AppRunner.prototype, { Console.enableProgressDisplay(false); - const postStartupResult = Promise.race([ - listenPromise, - runPromise - ]).then(() => { - return runPostStartupCallbacks(bundleResult); - }).await(); + const promList = [runPromise, listenPromise]; + await Promise.race(promList) + + const postStartupResult = + await runPostStartupCallbacks(bundleResult) if (postStartupResult) return postStartupResult; // Wait for either the process to exit, or (if watchForChanges) a // source file to change. Or, for stop() to be called. - var ret = runPromise.await(); - + var ret = await runPromise; try { while (ret.outcome === 'changed-refreshable') { if (! canRefreshClient) { @@ -896,7 +900,8 @@ Object.assign(AppRunner.prototype, { // We stay in this loop as long as only refreshable assets have changed. // When ret.refreshable becomes false, we restart the server. - bundleResultOrRunResult = bundleApp(); + bundleResultOrRunResult = await bundleApp(); + if (bundleResultOrRunResult.runResult) { return bundleResultOrRunResult.runResult; } @@ -913,11 +918,11 @@ Object.assign(AppRunner.prototype, { // Establish a watcher on the new files. setupClientWatcher(); - const postStartupResult = runPostStartupCallbacks(bundleResult); + const postStartupResult = await runPostStartupCallbacks(bundleResult); if (postStartupResult) return postStartupResult; // Wait until another file changes. - ret = oldPromise.await(); + ret = await oldPromise; } } finally { self.runPromise = null; @@ -930,7 +935,7 @@ Object.assign(AppRunner.prototype, { if (self.hmrServer) { self.hmrServer.setAppState("okay"); } - appProcess.stop(); + await appProcess.stop(); serverWatcher && serverWatcher.stop(); clientWatcher && clientWatcher.stop(); @@ -939,12 +944,12 @@ Object.assign(AppRunner.prototype, { return ret; }, - _fiber: function () { + _runApp: async function () { var self = this; var firstRun = true; while (true) { - var runResult = self._runOnce({ + var runResult = await self._runOnce({ onListen: function () { if (! self.noRestartBanner && ! firstRun) { runLog.logRestart(self); @@ -955,7 +960,7 @@ Object.assign(AppRunner.prototype, { }); firstRun = false; - var wantExit = self.onRunEnd ? !self.onRunEnd(runResult) : false; + var wantExit = self.onRunEnd ? !(await self.onRunEnd(runResult)) : false; if (wantExit || self.exitPromise || runResult.outcome === "stopped") { break; } @@ -1022,7 +1027,7 @@ Object.assign(AppRunner.prototype, { } // If onChange wasn't called synchronously (clearing watchPromise), wait // on it. - self.watchPromise && self.watchPromise.await(); + self.watchPromise && await self.watchPromise; // While we were waiting, did somebody stop() us? if (self.exitPromise) { break; @@ -1042,7 +1047,7 @@ Object.assign(AppRunner.prototype, { // Giving up for good. self._cleanUpPromises(); - self.fiber = null; + self.isRunning = null; } }); diff --git a/tools/runners/run-hmr.js b/tools/runners/run-hmr.js index a7625dbabd..15c78a2e83 100644 --- a/tools/runners/run-hmr.js +++ b/tools/runners/run-hmr.js @@ -12,17 +12,17 @@ export class HMRServer { this.projectContext = projectContext; this.hmrPath = hmrPath; - this.secret = secret; + this.secretBuffer = Buffer.from(secret); this.wsServer = null; - this.connByArch = Object.create(null); + this.connByArch = new Map(); this.started = false; - this.changeSetsByArch = Object.create(null); + this.changeSetsByArch = new Map(); this.maxChangeSets = 300; - this.cacheKeys = Object.create(null); - this.trimmedArchUntil = Object.create(null); + this.cacheKeys = new Map(); + this.trimmedArchUntil = new Map(); this.firstBuild = null; if (!cordovaServerPort) { @@ -55,7 +55,7 @@ export class HMRServer { stop() { this.wsServer.close(); - this.connByArch = Object.create(null); + this.connByArch = new Map(); } _handleWsConn(conn, req) { @@ -78,8 +78,9 @@ export class HMRServer { })); } - let secretsMatch = secret.length === this.secret.length && - crypto.timingSafeEqual(Buffer.from(secret), Buffer.from(this.secret)); + let secretsMatch = + secret.length === Buffer.byteLength(this.secretBuffer) && + crypto.timingSafeEqual(Buffer.from(secret), this.secretBuffer); if ( !fromCordova && @@ -93,8 +94,11 @@ export class HMRServer { return; } - this.connByArch[arch] = this.connByArch[arch] || []; - this.connByArch[arch].push(conn); + if (!this.connByArch.has(arch)) { + this.connByArch.set(arch, new Set()); + } + const archConnsSet = this.connByArch.get(arch); + archConnsSet.add(conn); connArch = arch; registered = true; break; @@ -143,28 +147,18 @@ export class HMRServer { // TODO: should use pings to detect disconnected sockets conn.on('close', () => { - if (!connArch) { - return; - } - - const archConns = this.connByArch[connArch] || []; - const index = archConns.indexOf(conn); - if (index > -1) { - archConns.splice( - index, - 1 - ); - } + if (!connArch) return; + const archConnsSet = this.connByArch.get(connArch); + if (archConnsSet) archConnsSet.delete(conn); }); } _sendAll(message) { - Object.values(this.connByArch).forEach(conns => { - conns.forEach(conn => { - conn.send(JSON.stringify(message)); - }); - }); - } + const messageStr = JSON.stringify(message); + for (const connsSet of Object.values(this.connByArch)) { + for (const conn of connsSet) conn.send(messageStr); + } + } setAppState(state) { if (state === 'error') { @@ -184,7 +178,7 @@ export class HMRServer { } } - compare({ name, arch, hmrAvailable, files, cacheKey }, getFileOutput) { + async compare({ name, arch, hmrAvailable, files, cacheKey }, getFileOutput) { if (this.firstBuild = null) { this.firstBuild = Date.now(); } @@ -248,20 +242,33 @@ export class HMRServer { onlyReplaceableChanges && removedFilePaths.length === 0; - function saveFileDetails(file) { - return { - content: getFileOutput(file).toStringWithSourceMap({}), - path: file.absModuleId, - meteorInstallOptions: file.meteorInstallOptions + async function saveFileDetails(file) { + const content = await getFileOutput(file); + return { + content: content.toStringWithSourceMap({}), + path: file.absModuleId, + meteorInstallOptions: file.meteorInstallOptions }; } + const iterWithFn = async (iter, fn) => { + const results = await Promise.allSettled(iter.map(fn)); + return results + .filter(result => { + if (result.status === 'rejected') { + console.error('HMR iterWithFn:', result.reason); + } + return result.status === 'fulfilled'; + }) + .map(result => result.value); + } + const result = { fileHashes, unreloadableHashes: unreloadable, reloadable, - addedFiles: reloadable ? addedFiles.map(saveFileDetails) : [], - changedFiles: reloadable ? changedFiles.map(saveFileDetails) : [], + addedFiles: reloadable ? await iterWithFn(addedFiles, saveFileDetails) : [], + changedFiles: reloadable ? await iterWithFn(changedFiles, saveFileDetails) : [], linkedAt: Date.now(), id: this._createId(), name @@ -273,7 +280,7 @@ export class HMRServer { this.changeSetsByArch[arch].push(result); this._trimChangeSets(arch); - if (!arch in this.trimmedArchUntil) { + if (!(arch in this.trimmedArchUntil)) { this.trimmedArchUntil[arch] = this.firstBuild - 1; } diff --git a/tools/runners/run-log.js b/tools/runners/run-log.js index d7a2f812f6..51efd8a4b3 100644 --- a/tools/runners/run-log.js +++ b/tools/runners/run-log.js @@ -16,11 +16,10 @@ var fiberHelpers = require('../utils/fiber-helpers.js'); // anywhere that may overlap with use of runLog. let _Log; -function getLoggingPackage() { +async function getLoggingPackage() { if (! _Log) { - _Log = require("../tool-env/isopackets.js") - .loadIsopackage('logging') - .Log; + const { loadIsopackage } = require("../tool-env/isopackets.js"); + _Log = (await loadIsopackage('logging')).Log; } // Since no other process will be listening to stdout and parsing it, @@ -84,10 +83,10 @@ Object.assign(RunLog.prototype, { this.rawLogs = !!rawLogs; }, - logAppOutput: function (line, isStderr) { + logAppOutput: async function (line, isStderr) { var self = this; - var Log = getLoggingPackage(); + var Log = await getLoggingPackage(); var obj = (isStderr ? Log.objFromText(line, { level: 'warn', stderr: true }) : diff --git a/tools/runners/run-mongo.js b/tools/runners/run-mongo.js index 7a7bcd8444..c9a7de7334 100644 --- a/tools/runners/run-mongo.js +++ b/tools/runners/run-mongo.js @@ -1,3 +1,4 @@ +import { loadIsopackage } from '../tool-env/isopackets.js'; import { MongoExitCodes } from '../utils/mongo-exit-codes'; var files = require('../fs/files'); var utils = require('../utils/utils.js'); @@ -5,7 +6,6 @@ var fiberHelpers = require('../utils/fiber-helpers.js'); var runLog = require('./run-log.js'); var child_process = require('child_process'); var _ = require('underscore'); -import { loadIsopackage } from '../tool-env/isopackets.js'; var Console = require('../console/console.js').Console; // Given a Mongo URL, open an interactive Mongo shell on this terminal @@ -28,6 +28,17 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) { mongodPath = files.convertToOSPath(mongodPath); dbPath = files.convertToOSPath(dbPath); + // Because we're spawning the process with shell: true on win32, the + // command string and args array are effectively concatenated to + // a single string and passed into the shell. If any of those paths + // contain spaces, these will get broken up on white-spaces and treated + // as separate tokens. If they are quoted, they will be parsed + // correctly by the shell. + if (process.platform === 'win32') { + mongodPath = '"' + mongodPath + '"' + dbPath = '"' + dbPath + '"' + } + let args = [ // nb: cli-test.sh and findMongoPids make strong assumptions about the // order of the arguments! Check them before changing any arguments. @@ -49,21 +60,8 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) { // Use mmapv1 on 32bit platforms, as our binary doesn't support WT if (process.arch === 'ia32') { args.push('--storageEngine', 'mmapv1', '--smallfiles'); - } else if (process.platform !== 'linux') { - // MongoDB 4, which we use on 64-bit systems, displays a banner in the - // Mongo shell about a free monitoring service, which can be disabled - // with this flag. However, the custom Linux build (see MONGO_BASE_URL - // in scripts/generate-dev-bundle.sh) neither displays the banner nor - // supports the flag, so it's safe/important to avoid passing the flag - // to mongod on 64-bit linux. - args.push('--enableFreeMonitoring', 'off'); } - // run with rosetta on mac m1 - if (process.platform === 'darwin' && process.arch === 'arm64') { - args = ['-x86_64', mongodPath, ...args]; - mongodPath = 'arch'; - } return child_process.spawn(mongodPath, args, { // Apparently in some contexts, Mongo crashes if your locale isn't set up // right. I wasn't able to reproduce it, but many people on #4019 @@ -78,6 +76,7 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) { }, process.env ), + ...process.platform === 'win32' && { shell: true }, }); } @@ -90,7 +89,7 @@ var findMongoPids; if (process.platform === 'win32') { // Windows doesn't have a ps equivalent that (reliably) includes the command // line, so approximate using the combined output of tasklist and netstat. - findMongoPids = function(dbDir_unused, port) { + findMongoPids = async function(dbDir_unused, port) { var promise = fiberHelpers.makeFulfillablePromise(); child_process.exec('tasklist /fi "IMAGENAME eq mongod.exe"', function( @@ -160,10 +159,10 @@ if (process.platform === 'win32') { } }); - return promise.await(); + return await promise; }; } else { - findMongoPids = function(dbDir, port) { + findMongoPids = async function(dbDir, port) { var promise = fiberHelpers.makeFulfillablePromise(); // 'ps ax' should be standard across all MacOS and Linux. @@ -263,14 +262,14 @@ if (process.platform === 'win32') { } ); - return promise.await(); + return await promise; }; } // See if mongo is running already. Yields. Returns the port that // mongo is running on or null if mongo is not running. -var findMongoPort = function(dbDir) { - var pids = findMongoPids(dbDir); +var findMongoPort = async function(dbDir) { + var pids = await findMongoPids(dbDir); if (pids.length !== 1) { return null; @@ -325,8 +324,7 @@ if (process.platform === 'win32') { ); client.on('error', () => resolve(null)); }) - .catch(() => null) - .await(); + .catch(() => null); }; } @@ -335,42 +333,43 @@ if (process.platform === 'win32') { // // This is a big hammer for dealing with still running mongos, but // smaller hammers have failed before and it is getting tiresome. -var findMongoAndKillItDead = function(port, dbPath) { - var pids = findMongoPids(null, port); +var findMongoAndKillItDead = async function(port, dbPath) { + var pids = await findMongoPids(null, port); // Go through the list serially. There really should only ever be // at most one but we're not taking any chances. - _.each(pids, function(processInfo) { - var pid = processInfo.pid; + pidsLoop: + for (const processInfo of pids) { + var pid = processInfo.pid; - // Send kill attempts and wait. First a SIGINT, then if it isn't - // dead within 2 sec, SIGKILL. Check every 100ms to see if it's - // dead. - for (var attempts = 1; attempts <= 40; attempts++) { - var signal = 0; - if (attempts === 1) { - signal = 'SIGINT'; - } else if (attempts === 20 || attempts === 30) { - signal = 'SIGKILL'; + // Send kill attempts and wait. First a SIGINT, then if it isn't + // dead within 2 sec, SIGKILL. Check every 100ms to see if it's + // dead. + for (var attempts = 1; attempts <= 40; attempts++) { + var signal = 0; + if (attempts === 1) { + signal = 'SIGINT'; + } else if (attempts === 20 || attempts === 30) { + signal = 'SIGKILL'; + } + + try { + process.kill(pid, signal); + } catch (e) { + // it's dead. on to the next one + break pidsLoop; + } + + await utils.sleepMs(100); } - try { - process.kill(pid, signal); - } catch (e) { - // it's dead. on to the next one - return; - } - - utils.sleepMs(100); + // give up after 4 seconds. + // XXX should actually catch this higher up and print a nice + // error. foreseeable conditions should never result in exceptions + // for the user. + throw new Error("Can't kill running mongo (pid " + pid + ').'); } - // give up after 4 seconds. - // XXX should actually catch this higher up and print a nice - // error. foreseeable conditions should never result in exceptions - // for the user. - throw new Error("Can't kill running mongo (pid " + pid + ').'); - }); - // If we had to kill mongod with SIGKILL, or on Windows where all calls to // `process.kill` work like SIGKILL, mongod will not have the opportunity to // close gracefully. Delete a lock file that may have been left over. @@ -396,7 +395,7 @@ var StoppedDuringLaunch = function() {}; // are killed (and onExit is then invoked). Also, the entirety of all three // databases is deleted before starting up. This is mode intended for testing // mongo failover, not for normal development or production use. -var launchMongo = function(options) { +var launchMongo = async function(options) { var onExit = options.onExit || function() {}; var noOplog = false; @@ -440,8 +439,8 @@ var launchMongo = function(options) { return; } stopped = true; - _.each(subHandles, function(handle) { - handle.stop(); + _.each(subHandles, function(h) { + h.stop(); }); if (options.onStopped) { @@ -452,18 +451,14 @@ var launchMongo = function(options) { }; }); - var yieldingMethod = function(object, methodName, ...args) { - return Promise.race([ + var yieldingMethod = async function(object, methodName, ...args) { + return await Promise.race([ stopPromise, - new Promise((resolve, reject) => { - object[methodName](...args, (err, res) => { - err ? reject(err) : resolve(res); - }); - }), - ]).await(); + object[methodName](...args), + ]); }; - var launchOneMongoAndWaitForReadyForInitiate = function( + var launchOneMongoAndWaitForReadyForInitiate = async function( dbPath, port, portFile @@ -473,13 +468,13 @@ var launchMongo = function(options) { var proc = null; if (options.allowKilling) { - findMongoAndKillItDead(port, dbPath); + await findMongoAndKillItDead(port, dbPath); } if (options.multiple) { // This is only for testing, so we're OK with incurring the replset // setup on each startup. - files.rm_recursive(dbPath); + await files.rm_recursive_deferred(dbPath); files.mkdir_p(dbPath, 0o755); } else if (portFile) { var portFileExists = false; @@ -543,17 +538,17 @@ var launchMongo = function(options) { require('../tool-env/cleanup.js').onExit(stop); subHandles.push({ stop }); - var procExitHandler = fiberHelpers.bindEnvironment(function(code, signal) { + var procExitHandler = fiberHelpers.bindEnvironment(async function(code, signal) { // Defang subHandle.stop(). proc = null; // Kill any other processes too. This will also remove // procExitHandler from the other processes, so onExit will only be called // once. - handle.stop(); + await handle.stop(); // Invoke the outer onExit callback. - onExit(code, signal, stderrOutput, detectedErrors); + await onExit(code, signal, stderrOutput, detectedErrors); }); proc.on('exit', procExitHandler); @@ -569,6 +564,7 @@ var launchMongo = function(options) { listening && (noOplog || replSetReadyToBeInitiated || replSetReady) ) { + proc.stdout.removeListener('data', stdoutOnData); resolve(); resolve = null; @@ -647,15 +643,15 @@ var launchMongo = function(options) { stderrOutput += data; }); - stopOrReadyPromise.await(); + await stopOrReadyPromise; }; - var initiateReplSetAndWaitForReady = function () { + var initiateReplSetAndWaitForReady = async function () { try { // Load mongo so we'll be able to talk to it. - const {MongoClient} = loadIsopackage( + const {MongoClient} = (await loadIsopackage( 'npm-mongo' - ).NpmModuleMongodb; + )).NpmModuleMongodb; // Connect to the intended primary and start a replset. const client = new MongoClient( @@ -681,9 +677,9 @@ var launchMongo = function(options) { }; try { - const config = yieldingMethod(db.admin(), 'command', { + const config = (await yieldingMethod(db.admin(), 'command', { replSetGetConfig: 1, - }).config; + })).config; // If a replication set configuration already exists, it's // important that the new version number is greater than the old. @@ -709,12 +705,12 @@ var launchMongo = function(options) { } try { - yieldingMethod(db.admin(), 'command', { + await yieldingMethod(db.admin(), 'command', { replSetInitiate: configuration, }); } catch (e) { if (e.message === 'already initialized') { - yieldingMethod(db.admin(), 'command', { + await yieldingMethod(db.admin(), 'command', { replSetReconfig: configuration, force: true, }); @@ -732,7 +728,7 @@ var launchMongo = function(options) { // Wait until the primary is writable. If it isn't writable after one // minute, throw an error and report the replica set status. while (!stopped) { - const {ismaster} = yieldingMethod(db.admin(), 'command', { + const {ismaster} = await yieldingMethod(db.admin(), 'command', { isMaster: 1, }); @@ -742,13 +738,13 @@ var launchMongo = function(options) { // We are explicitly setting it to 1 when there is only 1 node, as we do simulate replica sets with only 1 node // when running locally or in test environments. // ref: https://docs.mongodb.com/manual/reference/write-concern/#mongodb-writeconcern-writeconcern.-majority- - yieldingMethod(db.admin(), 'command', { + await yieldingMethod(db.admin(), 'command', { setDefaultRWConcern: 1, ...( options.multiple ? {} : {defaultWriteConcern: {w: 1}}) }); break; } else if (Date.now() - writableTimestamp > 60000) { - const status = yieldingMethod(db.admin(), 'command', { + const status = await yieldingMethod(db.admin(), 'command', { replSetGetStatus: 1, }); @@ -758,7 +754,7 @@ var launchMongo = function(options) { ); } - utils.sleepMs(50); + await utils.sleepMs(50); } client.close(true /* means "the app is closing the connection" */); @@ -774,24 +770,31 @@ var launchMongo = function(options) { try { if (options.multiple) { var dbBasePath = files.pathJoin(options.projectLocalDir, 'dbs'); - _.each(_.range(3), function(i) { + let i = 2; + while (i >= 0) { // Did we get stopped (eg, by one of the processes exiting) by now? Then // don't start anything new. if (stopped) { return; } - var dbPath = files.pathJoin(options.projectLocalDir, 'dbs', '' + i); - launchOneMongoAndWaitForReadyForInitiate(dbPath, options.port + i); - }); + const newDbPath = files.pathJoin(options.projectLocalDir, 'dbs', '' + i); + // TODO [fibers]: it looks like we shouldn't wait for this function to finish. + // if all tests are passing, we're probably fine... + await launchOneMongoAndWaitForReadyForInitiate(newDbPath, options.port + i); + i--; + } + if (!stopped) { - initiateReplSetAndWaitForReady(); + await initiateReplSetAndWaitForReady(); } } else { - var dbPath = files.pathJoin(options.projectLocalDir, 'db'); - var portFile = !noOplog && files.pathJoin(dbPath, 'METEOR-PORT'); - launchOneMongoAndWaitForReadyForInitiate(dbPath, options.port, portFile); + const newDbPath = files.pathJoin(options.projectLocalDir, 'db'); + var portFile = !noOplog && files.pathJoin(newDbPath, 'METEOR-PORT'); + // TODO [fibers]: it looks like we shouldn't wait for this function to finish. + // if all tests are passing, we're probably fine... + await launchOneMongoAndWaitForReadyForInitiate(newDbPath, options.port, portFile); if (!stopped && !noOplog) { - initiateReplSetAndWaitForReady(); + await initiateReplSetAndWaitForReady(); if (!stopped) { // Write down that we configured the database properly. files.writeFile(portFile, '' + options.port); @@ -843,14 +846,14 @@ Object.assign(MRp, { // // If the server fails to start for the first time (after a few // restarts), we'll print a message and give up. - start: function() { + start: async function() { var self = this; if (self.handle) { throw new Error('already running?'); } - self._startOrRestart(); + await self._startOrRestart(); // Did we properly start up? Great! if (self.handle) { @@ -864,9 +867,9 @@ Object.assign(MRp, { // Otherwise, wait for a successful _startOrRestart, or a failure. if (!self.resolveStartupPromise) { - new Promise(function(resolve) { + await new Promise(function(resolve) { self.resolveStartupPromise = resolve; - }).await(); + }); } }, @@ -881,7 +884,7 @@ Object.assign(MRp, { // // In case (a), self.handle will be the handle returned from launchMongo; in // case (b) self.handle will be null. - _startOrRestart: function() { + _startOrRestart: async function() { var self = this; if (self.handle) { @@ -895,7 +898,7 @@ Object.assign(MRp, { // shouldn't annoy the user by telling it that we couldn't start up. self.suppressExitMessage = true; } - self.handle = launchMongo({ + self.handle = await launchMongo({ projectLocalDir: self.projectLocalDir, port: self.port, multiple: self.multiple, @@ -914,7 +917,7 @@ Object.assign(MRp, { } }, - _exited: function(code, signal, stderr, detectedErrors) { + _exited: async function(code, signal, stderr, detectedErrors) { var self = this; self.handle = null; @@ -966,9 +969,9 @@ Object.assign(MRp, { if (self.errorCount < 3) { // Wait a second, then restart. self.restartTimer = setTimeout( - fiberHelpers.bindEnvironment(function() { + fiberHelpers.bindEnvironment(async function() { self.restartTimer = null; - self._startOrRestart(); + await self._startOrRestart(); }), 1000 ); @@ -1053,10 +1056,10 @@ Object.assign(MRp, { } }, - _fail: function() { + _fail: async function() { var self = this; self.stop(); - self.onFailure && self.onFailure(); + self.onFailure && await self.onFailure(); self._allowStartupToReturn(); }, diff --git a/tools/runners/run-proxy.js b/tools/runners/run-proxy.js index d591054232..f237f68fde 100644 --- a/tools/runners/run-proxy.js +++ b/tools/runners/run-proxy.js @@ -26,7 +26,7 @@ Object.assign(Proxy.prototype, { // Start the proxy server, block (yield) until it is ready to go // (actively listening on outer and proxying to inner), and then // return. - start: function () { + start: async function () { var self = this; if (self.server) { @@ -71,7 +71,7 @@ Object.assign(Proxy.prototype, { allowStart = resolve; }); - self.server.on('error', function (err) { + self.server.on('error', async function (err) { if (err.code === 'EADDRINUSE') { var port = self.listenPort; runLog.log( @@ -92,7 +92,7 @@ Object.assign(Proxy.prototype, { } else { runLog.log('' + err); } - self.onFailure(); + await self.onFailure(); allowStart(); }); @@ -142,7 +142,7 @@ Object.assign(Proxy.prototype, { allowStart(); }); - promise.await(); + await promise; }, // Idempotent. diff --git a/tools/runners/run-selenium.js b/tools/runners/run-selenium.js index 8bbaaaf2ac..1187a56221 100644 --- a/tools/runners/run-selenium.js +++ b/tools/runners/run-selenium.js @@ -1,4 +1,3 @@ -var Fiber = require('fibers'); var files = require('../fs/files'); var runLog = require('./run-log.js'); var utils = require('../utils/utils.js'); @@ -36,7 +35,7 @@ Object.assign(Selenium.prototype, { // Start the selenium server, block (yield) until it is ready to go // (actively listening on outer and proxying to inner), and then // return. - start: function () { + start: async function () { var self = this; if (self.server) { @@ -66,42 +65,38 @@ Object.assign(Selenium.prototype, { var builder = new webdriver.Builder().withCapabilities(capabilities); self.driver = builder.build(); - Promise.await(self.driver.getSession()); - Promise.await(self.driver.get(self.url)); + await self.driver.getSession(); + await self.driver.get(self.url); - Fiber(function () { - try { - self._pollLogs(); - } catch (err) { - runLog.log("Log polling exited unexpectedly: " + err); - } - }).run(); + try { + await self._pollLogs(); + } catch (err) { + runLog.log("Log polling exited unexpectedly: " + err); + } }, - stop: function () { + stop: async function () { var self = this; if (! self.driver) { return; } - Promise.await(self.driver.close()); - Promise.await(self.driver.quit()); + await self.driver.close(); + await self.driver.quit(); self.driver = null; }, - _flushLogs: function () { + _flushLogs: async function () { var self = this; - Promise.await( - self.driver.executeScript("console.log('" + DUMMY_FLUSH + "');", []) - ); + await self.driver.executeScript("console.log('" + DUMMY_FLUSH + "');", []); }, - _getLogs: function () { + _getLogs: async function () { var self = this; - Promise.await(self.driver.manage().logs().get('browser')); + await self.driver.manage().logs().get('browser'); }, _gotStateDone: function () { @@ -143,11 +138,11 @@ Object.assign(Selenium.prototype, { } }, - _pollLogsOnce: function () { + _pollLogsOnce: async function () { var self = this; - self._flushLogs(); - var logs = self._getLogs() || []; + await self._flushLogs(); + var logs = await self._getLogs() || []; logs.forEach(function (log) { var msg = log.message; var regex = /([^\s]*)\s*([^\s]*)\s*(.*)/i; @@ -176,16 +171,16 @@ Object.assign(Selenium.prototype, { }); }, - _pollLogs: function () { + _pollLogs: async function () { var self = this; while (self.driver) { try { - self._pollLogsOnce(); + await self._pollLogsOnce(); } catch (err) { runLog.log("Error reading console log: " + err); } - utils.sleepMs(1000); + await utils.sleepMs(1000); } }, }); diff --git a/tools/runners/run-updater.js b/tools/runners/run-updater.js index c4a51be525..b52251aa9f 100644 --- a/tools/runners/run-updater.js +++ b/tools/runners/run-updater.js @@ -19,7 +19,7 @@ export class Updater { // Check every 3 hours. (Should not share buildmessage state with // the main fiber.) async function check() { - self._check(); + await self._check(); } this.timer = setInterval(check, CHECK_UPDATE_INTERVAL); @@ -29,10 +29,10 @@ export class Updater { check(); } - _check() { + async _check() { const updater = require('../packaging/updater'); try { - updater.tryToDownloadUpdate({ showBanner: true }); + await updater.tryToDownloadUpdate({ showBanner: true }); } catch (e) { // oh well, this was the background. Only show errors if we are in debug // mode. diff --git a/tools/static-assets/README.md b/tools/static-assets/README.md index 1884abb1d6..6cef051b69 100644 --- a/tools/static-assets/README.md +++ b/tools/static-assets/README.md @@ -44,10 +44,6 @@ Similar to `skel`, `skel-solid` is copied on `meteor create --solid` command. Similar to `skel`, `skel-vue` is copied on `meteor create --vue` command. -## skel-vue-2 - Package Skeleton - -Similar to `skel`, `skel-vue-2` is copied on `meteor create --vue-2` command. - ## server - Bundled App's Bootstrap The `server` folder is copied by Isobuild when the app is bundled (on diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index c37cdee6b6..43c2668bde 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -1,7 +1,5 @@ -var Fiber = require("fibers"); var fs = require("fs"); var path = require("path"); -var Future = require("fibers/future"); var sourcemap_support = require('source-map-support'); var bootUtils = require('./boot-utils.js'); @@ -10,18 +8,10 @@ var npmRequire = require('./npm-require.js').require; var Profile = require('./profile').Profile; // This code is duplicated in tools/main.js. -var MIN_NODE_VERSION = 'v14.0.0'; +var MIN_NODE_VERSION = 'v18.16.0'; var hasOwn = Object.prototype.hasOwnProperty; -// For now it's a function to ensure we don't get a falsy value. -// Once we figure out the best place to create this EV (maybe it's here), -// it won't need to be a function anymore. - -global._isFibersEnabled = function () { - return !process.env.DISABLE_FIBERS; -}; - if (require('semver').lt(process.version, MIN_NODE_VERSION)) { process.stderr.write( 'Meteor requires Node ' + MIN_NODE_VERSION + ' or later.\n'); @@ -43,7 +33,8 @@ var starJson = JSON.parse(fs.readFileSync(path.join(buildDir, "star.json"))); __meteor_bootstrap__ = { startupHooks: [], serverDir: serverDir, - configJson: configJson + configJson: configJson, + isFibersDisabled: true }; __meteor_runtime_config__ = { @@ -58,11 +49,11 @@ if (!process.env.APP_ID) { // Map from load path to its source map. var parsedSourceMaps = {}; -const meteorDebugFuture = - process.env.METEOR_INSPECT_BRK ? new Future : null; +let meteorDebugPromiseResolver = null; +const meteorDebugPromise = process.env.METEOR_INSPECT_BRK ? new Promise(resolve => meteorDebugPromiseResolver = resolve) : null; -function maybeWaitForDebuggerToAttach() { - if (meteorDebugFuture) { +async function maybeWaitForDebuggerToAttach() { + if (meteorDebugPromise && meteorDebugPromiseResolver) { const { pause } = require("./debug"); const pauseThresholdMs = 50; const pollIntervalMs = 500; @@ -73,7 +64,7 @@ function maybeWaitForDebuggerToAttach() { // This setTimeout not only waits for the debugger to attach, but also // keeps the process alive by preventing the event loop from running // empty while the main Fiber yields. - setTimeout(function poll() { + setTimeout(async function poll() { const pauseStartTimeMs = +new Date; if (pauseStartTimeMs - waitStartTimeMs > waitLimitMs) { @@ -81,7 +72,7 @@ function maybeWaitForDebuggerToAttach() { `Debugger did not attach after ${waitLimitMinutes} minutes; continuing.` ); - meteorDebugFuture.return(); + meteorDebugPromiseResolver(); } else { // This pause function contains a debugger keyword that will only @@ -101,7 +92,7 @@ function maybeWaitForDebuggerToAttach() { // time, we can conclude the debugger keyword must be active, // which means a debugging client must be connected, which means // we should stop polling and let the main Fiber continue. - meteorDebugFuture.return(); + meteorDebugPromiseResolver(); } else { // If the pause() function call didn't take a meaningful amount @@ -114,7 +105,7 @@ function maybeWaitForDebuggerToAttach() { }, pollIntervalMs); // The polling will continue while we wait here. - meteorDebugFuture.wait(); + await meteorDebugPromise; } } @@ -230,12 +221,12 @@ var specialArgPaths = { } }; -var loadServerBundles = Profile("Load server bundles", function () { - var infos = []; +const loadServerBundles = Profile("Load server bundles", async function () { + const infos = []; - serverJson.load.forEach(function (fileInfo) { - var code = fs.readFileSync(path.resolve(serverDir, fileInfo.path)); - var nonLocalNodeModulesPaths = []; + for (const fileInfo of serverJson.load) { + const code = fs.readFileSync(path.resolve(serverDir, fileInfo.path)); + const nonLocalNodeModulesPaths = []; function addNodeModulesPath(path) { nonLocalNodeModulesPaths.push( @@ -265,7 +256,7 @@ var loadServerBundles = Profile("Load server bundles", function () { } } - var Npm = { + const Npm = { /** * @summary Require a package that was specified using * `Npm.depends()`. @@ -277,14 +268,14 @@ var loadServerBundles = Profile("Load server bundles", function () { return "Npm.require(" + JSON.stringify(name) + ")"; }, function (name, error) { if (nonLocalNodeModulesPaths.length > 0) { - var fullPath; + let fullPath; // Replace all backslashes with forward slashes, just in case // someone passes a Windows-y module identifier. name = name.split("\\").join("/"); nonLocalNodeModulesPaths.some(function (nodeModuleBase) { - var packageBase = files.convertToOSPath(files.pathResolve( + const packageBase = files.convertToOSPath(files.pathResolve( nodeModuleBase, name.split("/", 1)[0] )); @@ -301,7 +292,7 @@ var loadServerBundles = Profile("Load server bundles", function () { } } - var resolved = require.resolve(name); + const resolved = require.resolve(name); if (resolved === name && ! path.isAbsolute(resolved)) { // If require.resolve(id) === id and id is not an absolute // identifier, it must be a built-in module like fs or http. @@ -309,30 +300,36 @@ var loadServerBundles = Profile("Load server bundles", function () { } throw error || new Error( - "Cannot find module " + JSON.stringify(name) + "Cannot find module " + JSON.stringify(name) ); }) }; - var getAsset = function (assetPath, encoding, callback) { - var promiseResolver, promise; + function getAsset (assetPath, encoding, callback) { + var promiseResolver, promiseReject, promise; if (! callback) { - promise = new Promise((resolve, reject) => { - promiseResolver = function (error, result) { - error ? reject(error) : resolve(result); - } + promise = new Promise((r, reject) => { + promiseResolver = r; + promiseReject = reject; }); - callback = promiseResolver; } // This assumes that we've already loaded the meteor package, so meteor // itself can't call Assets.get*. (We could change this function so that // it doesn't call bindEnvironment if you don't pass a callback if we need // to.) - var _callback = Package.meteor.Meteor.bindEnvironment(function (err, result) { + const _callback = Package.meteor.Meteor.bindEnvironment(function (err, result) { if (result && ! encoding) - // Sadly, this copies in Node 0.10. + // Sadly, this copies in Node 0.10. result = new Uint8Array(result); - callback(err, result); + if (promiseResolver) { + if (err) { + promiseReject(err); + return; + } + promiseResolver(result); + } else { + callback(err, result); + } }, function (e) { console.log("Exception in callback of getAsset", e.stack); }); @@ -348,7 +345,7 @@ var loadServerBundles = Profile("Load server bundles", function () { if (! fileInfo.assets || ! hasOwn.call(fileInfo.assets, assetPath)) { _callback(new Error("Unknown asset: " + assetPath)); } else { - var filePath = path.join(serverDir, fileInfo.assets[assetPath]); + const filePath = path.join(serverDir, fileInfo.assets[assetPath]); fs.readFile(files.convertToOSPath(filePath), encoding, _callback); } @@ -356,24 +353,12 @@ var loadServerBundles = Profile("Load server bundles", function () { return promise; }; - var Assets = { - getText: function (assetPath, callback) { - const result = getAsset(assetPath, "utf8", callback); - if (!callback) { - return Future.fromPromise(result).wait(); - } + const Assets = { + getTextAsync: function (assetPath, callback) { + return getAsset(assetPath, "utf8", callback); }, - getTextAsync: function (assetPath) { - return getAsset(assetPath, "utf8"); - }, - getBinary: function (assetPath, callback) { - const result = getAsset(assetPath, undefined, callback); - if (!callback) { - return Future.fromPromise(result).wait(); - } - }, - getBinaryAsync: function (assetPath) { - return getAsset(assetPath, undefined); + getBinaryAsync: function (assetPath, callback) { + return getAsset(assetPath, undefined, callback); }, /** * @summary Get the absolute path to the static server asset. Note that assets are read-only. @@ -399,20 +384,20 @@ var loadServerBundles = Profile("Load server bundles", function () { } }; - var wrapParts = ["(function(Npm,Assets"]; + const wrapParts = ["(function(Npm,Assets"]; - var specialArgs = - hasOwn.call(specialArgPaths, fileInfo.path) && - specialArgPaths[fileInfo.path](fileInfo); + const specialArgs = + hasOwn.call(specialArgPaths, fileInfo.path) && + specialArgPaths[fileInfo.path](fileInfo); - var specialKeys = Object.keys(specialArgs || {}); + const specialKeys = Object.keys(specialArgs || {}); specialKeys.forEach(function (key) { wrapParts.push("," + key); }); // \n is necessary in case final line is a //-comment wrapParts.push("){", code, "\n})"); - var wrapped = wrapParts.join(""); + const wrapped = wrapParts.join(""); // It is safer to use the absolute path when source map is present as // different tooling, such as node-inspector, can get confused on relative @@ -420,24 +405,24 @@ var loadServerBundles = Profile("Load server bundles", function () { // fileInfo.path is a standard path, convert it to OS path to join with // __dirname - var fileInfoOSPath = files.convertToOSPath(fileInfo.path); - var absoluteFilePath = path.resolve(__dirname, fileInfoOSPath); + const fileInfoOSPath = files.convertToOSPath(fileInfo.path); + const absoluteFilePath = path.resolve(__dirname, fileInfoOSPath); - var scriptPath = - parsedSourceMaps[absoluteFilePath] ? absoluteFilePath : fileInfoOSPath; + const scriptPath = + parsedSourceMaps[absoluteFilePath] ? absoluteFilePath : fileInfoOSPath; - var func = require('vm').runInThisContext(wrapped, { + const func = require('vm').runInThisContext(wrapped, { filename: scriptPath, displayErrors: true }); - var args = [Npm, Assets]; + const args = [Npm, Assets]; specialKeys.forEach(function (key) { args.push(specialArgs[key]); }); - if (meteorDebugFuture) { + if (meteorDebugPromise) { infos.push({ fn: Profile(fileInfo.path, func), args @@ -446,27 +431,32 @@ var loadServerBundles = Profile("Load server bundles", function () { // Allows us to use code-coverage if the debugger is not enabled Profile(fileInfo.path, func).apply(global, args); } - }); + } - maybeWaitForDebuggerToAttach(); + await maybeWaitForDebuggerToAttach(); - infos.forEach(info => { + for (const info of infos) { info.fn.apply(global, info.args); - }); + } + if (global.Package && global.Package['core-runtime']) { + return global.Package['core-runtime'].waitUntilAllLoaded(); + } + + return null; }); -var callStartupHooks = Profile("Call Meteor.startup hooks", function () { +var callStartupHooks = Profile("Call Meteor.startup hooks", async function () { // run the user startup hooks. other calls to startup() during this can still // add hooks to the end. while (__meteor_bootstrap__.startupHooks.length) { var hook = __meteor_bootstrap__.startupHooks.shift(); - Profile.time(hook.stack || "(unknown)", hook); + await Profile.time(hook.stack || "(unknown)", hook); } // Setting this to null tells Meteor.startup to call hooks immediately. __meteor_bootstrap__.startupHooks = null; }); -var runMain = Profile("Run main()", function () { +var runMain = Profile("Run main()", async function () { // find and run main() // XXX hack. we should know the package that contains main. var mains = []; @@ -492,7 +482,7 @@ var runMain = Profile("Run main()", function () { process.stderr.write("Program has more than one main() function?\n"); process.exit(1); } - var exitCode = mains[0].call({}, process.argv.slice(3)); + var exitCode = await mains[0].call({}, process.argv.slice(3)); // XXX hack, needs a better way to keep alive if (exitCode !== 'DAEMON') process.exit(exitCode); @@ -502,10 +492,19 @@ var runMain = Profile("Run main()", function () { } }); -Fiber(function () { - Profile.run("Server startup", function () { - loadServerBundles(); - callStartupHooks(); - runMain(); +(async function startServerProcess() { + if (!global.__METEOR_ASYNC_LOCAL_STORAGE) { + const { AsyncLocalStorage } = require('async_hooks'); + global.__METEOR_ASYNC_LOCAL_STORAGE = new AsyncLocalStorage(); + } + + await Profile.run('Server startup', async function() { + await loadServerBundles(); + await callStartupHooks(); + await runMain(); }); -}).run(); +})().catch(e => { + console.log('error on boot.js', e ) + console.log(e.stack); + process.exit(1) +}); diff --git a/tools/static-assets/server/npm-rebuild.js b/tools/static-assets/server/npm-rebuild.js index e0a5624d3c..ca1a3be7bf 100644 --- a/tools/static-assets/server/npm-rebuild.js +++ b/tools/static-assets/server/npm-rebuild.js @@ -28,11 +28,10 @@ var binDir = path.dirname(process.execPath); process.env.PATH = binDir + path.delimiter + process.env.PATH; var npmCmd = "npm"; +var shell = false; if (process.platform === "win32") { - var npmCmdPath = path.join(binDir, "npm.cmd"); - if (fs.existsSync(npmCmdPath)) { - npmCmd = npmCmdPath; - } + npmCmd = "npm.cmd"; + shell = true; } function rebuild(i) { @@ -41,7 +40,8 @@ function rebuild(i) { if (! dir) { // Print Node/V8/etc. versions for diagnostic purposes. spawn(npmCmd, ["version", "--json"], { - stdio: "inherit" + stdio: "inherit", + shell, }); return; @@ -49,7 +49,8 @@ function rebuild(i) { spawn(npmCmd, rebuildArgs, { cwd: path.join(__dirname, dir), - stdio: "inherit" + stdio: "inherit", + shell, }).on("exit", function (code) { if (code !== 0) { process.exit(code); diff --git a/tools/static-assets/server/npm-require.js b/tools/static-assets/server/npm-require.js index da0879d933..8a32227fef 100644 --- a/tools/static-assets/server/npm-require.js +++ b/tools/static-assets/server/npm-require.js @@ -145,7 +145,7 @@ function resolve(id) { if (res === null) { var idParts = id.split("/"); var meteorAddTip = ""; - // If it looks like `meteor/xxx`, the user may forgot to add the + // If it looks like `meteor/xxx`, the user may forgot to add the // package before importing it. if (idParts.length === 2 && idParts[0] === "meteor") { diff --git a/tools/static-assets/server/runtime.js b/tools/static-assets/server/runtime.js index 2b0f800940..3c15a6f9d1 100644 --- a/tools/static-assets/server/runtime.js +++ b/tools/static-assets/server/runtime.js @@ -47,14 +47,27 @@ module.exports = function enable ({ cachePath, createLoader = true } = {}) { }; const reifyVersion = require("@meteorjs/reify/package.json").version; + const reifyAcornParse = require("@meteorjs/reify/lib/parsers/acorn").parse; const reifyBabelParse = require("@meteorjs/reify/lib/parsers/babel").parse; const reifyCompile = require("@meteorjs/reify/lib/compiler").compile; function compileContent (content) { let identical = true; + let result; try { - const result = reifyCompile(content, { + result = reifyCompile(content, { + parse: reifyAcornParse, + generateLetDeclarations: false, + ast: false, + }); + if (!result.identical) { + identical = false; + content = result.code; + } + } catch (acornError) { + // Fallback: Babel + result = reifyCompile(content, { parse: reifyBabelParse, generateLetDeclarations: false, ast: false, @@ -63,9 +76,9 @@ module.exports = function enable ({ cachePath, createLoader = true } = {}) { identical = false; content = result.code; } - } finally { - return { content, identical }; } + + return { content, identical }; } const _compile = Mp._compile; diff --git a/tools/static-assets/skel-apollo/.meteor/packages b/tools/static-assets/skel-apollo/.meteor/packages index 0addfea192..718d356e3d 100644 --- a/tools/static-assets/skel-apollo/.meteor/packages +++ b/tools/static-assets/skel-apollo/.meteor/packages @@ -19,4 +19,4 @@ hot-module-replacement # Update client in development without reloading the pag ~prototype~ static-html # Define static page content in .html files apollo # Basic Apollo integration for Meteor apps -swydo:graphql # Import .graphql files +compat:graphql # Import .graphql files diff --git a/tools/static-assets/skel-apollo/package.json b/tools/static-assets/skel-apollo/package.json index 6295d82ae4..8af983a7cb 100644 --- a/tools/static-assets/skel-apollo/package.json +++ b/tools/static-assets/skel-apollo/package.json @@ -2,19 +2,18 @@ "name": "~name~", "private": true, "scripts": { - "start": "meteor run", + "start": "meteor run --open", "test": "meteor test --once --driver-package meteortesting:mocha", "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha", "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@apollo/client": "^3.7.14", - "@apollo/server": "^4.7.1", - "@babel/runtime": "^7.21.5", - "body-parser": "^1.20.2", - "express": "^4.18.2", - "graphql": "^16.6.0", - "meteor-node-stubs": "^1.2.5", + "@apollo/client": "^3.9.2", + "@apollo/server": "^4.10.0", + "@babel/runtime": "^7.23.9", + "@swc/helpers": "^0.5.17", + "graphql": "^16.8.1", + "meteor-node-stubs": "^1.2.12", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -23,6 +22,7 @@ "client": "client/main.jsx", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-apollo/server/apollo.js b/tools/static-assets/skel-apollo/server/apollo.js index 44b51d0cac..eeee0be6bf 100644 --- a/tools/static-assets/skel-apollo/server/apollo.js +++ b/tools/static-assets/skel-apollo/server/apollo.js @@ -1,22 +1,22 @@ import { ApolloServer } from '@apollo/server'; -import { WebApp } from 'meteor/webapp'; +import { WebApp, WebAppInternals } from 'meteor/webapp'; import { getUser } from 'meteor/apollo'; import { LinksCollection } from '/imports/api/links'; import typeDefs from '/imports/apollo/schema.graphql'; -import express from 'express'; import { expressMiddleware } from '@apollo/server/express4'; -import { json } from 'body-parser'; + +const express = WebAppInternals.NpmModules.express.module; const resolvers = { Query: { - getLink: async (obj, { id }) => LinksCollection.findOne(id), - getLinks: async () => LinksCollection.find().fetch() + getLink: async (obj, { id }) => LinksCollection.findOneAsync(id), + getLinks: async () => LinksCollection.find().fetchAsync() } }; const context = async ({ req }) => ({ user: await getUser(req.headers.authorization) -}) +}); const server = new ApolloServer({ cache: 'bounded', @@ -27,12 +27,9 @@ const server = new ApolloServer({ export async function startApolloServer() { await server.start(); - WebApp.connectHandlers.use( + WebApp.handlers.use( '/graphql', // Configure the path as you want. - express() // Create new Express router. - .disable('etag') // We don't server GET requests, so there's no need for that. - .disable('x-powered-by') // A small safety measure. - .use(json()) // From `body-parser`. - .use(expressMiddleware(server, { context })), // From `@apollo/server/express4`. - ) + express.json(), + expressMiddleware(server, { context }) // From `@apollo/server/express4` + ); } diff --git a/tools/static-assets/skel-apollo/server/main.js b/tools/static-assets/skel-apollo/server/main.js index 9f9a9b4b7a..1e5812aa4c 100644 --- a/tools/static-assets/skel-apollo/server/main.js +++ b/tools/static-assets/skel-apollo/server/main.js @@ -17,7 +17,7 @@ Meteor.startup(async () => { if (await LinksCollection.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-bare/package.json b/tools/static-assets/skel-bare/package.json index ba420dae93..f2cb0b71a7 100644 --- a/tools/static-assets/skel-bare/package.json +++ b/tools/static-assets/skel-bare/package.json @@ -5,7 +5,7 @@ "start": "meteor run" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1" + "@babel/runtime": "^7.23.5", + "meteor-node-stubs": "^1.2.12" } } diff --git a/tools/static-assets/skel-blaze/package.json b/tools/static-assets/skel-blaze/package.json index e520663880..e197964537 100644 --- a/tools/static-assets/skel-blaze/package.json +++ b/tools/static-assets/skel-blaze/package.json @@ -8,15 +8,17 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "jquery": "^3.6.0", - "meteor-node-stubs": "^1.2.1" + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "jquery": "^3.7.1", + "meteor-node-stubs": "^1.2.12" }, "meteor": { "mainModule": { "client": "client/main.js", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-chakra-ui/package.json b/tools/static-assets/skel-chakra-ui/package.json index c02b9d2b53..99b3e13d76 100644 --- a/tools/static-assets/skel-chakra-ui/package.json +++ b/tools/static-assets/skel-chakra-ui/package.json @@ -8,22 +8,24 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.18.6", + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", "@chakra-ui/icons": "^1.1.7", "@chakra-ui/react": "^1.8.8", "@emotion/react": "^11.9.3", "@emotion/styled": "^11.9.3", "@react-icons/all-files": "^4.1.0", "framer-motion": "^6.4.2", - "meteor-node-stubs": "^1.2.3", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "meteor-node-stubs": "^1.2.12", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "meteor": { "mainModule": { "client": "client/main.jsx", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-chakra-ui/server/main.js b/tools/static-assets/skel-chakra-ui/server/main.js index 0198535e0a..49452ad352 100644 --- a/tools/static-assets/skel-chakra-ui/server/main.js +++ b/tools/static-assets/skel-chakra-ui/server/main.js @@ -10,7 +10,7 @@ Meteor.startup(async () => { if (await LinksCollection.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-full/imports/startup/server/fixtures.js b/tools/static-assets/skel-full/imports/startup/server/fixtures.js index f3473aa4f8..ce32eeac56 100644 --- a/tools/static-assets/skel-full/imports/startup/server/fixtures.js +++ b/tools/static-assets/skel-full/imports/startup/server/fixtures.js @@ -12,7 +12,7 @@ Meteor.startup(async () => { if (await Links.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-full/package.json b/tools/static-assets/skel-full/package.json index 66e7523a35..1abdbdd683 100644 --- a/tools/static-assets/skel-full/package.json +++ b/tools/static-assets/skel-full/package.json @@ -6,11 +6,19 @@ "test": "meteor test --once --driver-package meteortesting:mocha" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "jquery": "^3.6.0", - "meteor-node-stubs": "^1.2.1" + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "jquery": "^3.7.1", + "meteor-node-stubs": "^1.2.12" }, "devDependencies": { "chai": "^4.2.0" + }, + "meteor": { + "mainModule": { + "client": "client/main.js", + "server": "server/main.js" + }, + "modern": true } } diff --git a/tools/static-assets/skel-minimal/.meteor/packages b/tools/static-assets/skel-minimal/.meteor/packages index d0998cd7ad..9f6770b9e9 100644 --- a/tools/static-assets/skel-minimal/.meteor/packages +++ b/tools/static-assets/skel-minimal/.meteor/packages @@ -13,6 +13,7 @@ ecmascript # Enable ECMAScript2015+ syntax in app code typescript # Enable TypeScript syntax in .ts and .tsx modules shell-server # Server-side component of the `meteor shell` command webapp # Serves a Meteor app over HTTP +ddp # The protocol and client/server libraries that Meteor uses to send data server-render # Support for server-side rendering hot-module-replacement # Rebuilds the client if there is a change on the client without restarting the server ~prototype~ diff --git a/tools/static-assets/skel-minimal/package.json b/tools/static-assets/skel-minimal/package.json index 246b296d48..74d5a9b271 100644 --- a/tools/static-assets/skel-minimal/package.json +++ b/tools/static-assets/skel-minimal/package.json @@ -8,14 +8,16 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1" + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.12" }, "meteor": { "mainModule": { "client": "client/main.js", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-react/package.json b/tools/static-assets/skel-react/package.json index 1b0c4457f4..ee33ff775c 100644 --- a/tools/static-assets/skel-react/package.json +++ b/tools/static-assets/skel-react/package.json @@ -8,8 +8,9 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.20.7", - "meteor-node-stubs": "^1.2.5", + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.12", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -18,6 +19,7 @@ "client": "client/main.jsx", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-react/server/main.js b/tools/static-assets/skel-react/server/main.js index 0198535e0a..49452ad352 100644 --- a/tools/static-assets/skel-react/server/main.js +++ b/tools/static-assets/skel-react/server/main.js @@ -10,7 +10,7 @@ Meteor.startup(async () => { if (await LinksCollection.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-solid/.meteor/packages b/tools/static-assets/skel-solid/.meteor/packages index 492b563f76..665679a90c 100644 --- a/tools/static-assets/skel-solid/.meteor/packages +++ b/tools/static-assets/skel-solid/.meteor/packages @@ -19,4 +19,4 @@ hot-module-replacement # Update client in development without reloading the pag ~prototype~ static-html # Define static page content in .html files -vite:bundler +jorgenvatle:vite diff --git a/tools/static-assets/skel-solid/client/entry-meteor.js b/tools/static-assets/skel-solid/client/entry-meteor.js new file mode 100644 index 0000000000..0ec3ddc121 --- /dev/null +++ b/tools/static-assets/skel-solid/client/entry-meteor.js @@ -0,0 +1,14 @@ +/** + * Entrypoint for the Meteor client + * + * Generally, this file can be left empty. Vite will add imports for + * lazy-loaded Meteor packages to this file to ensure they aren't omitted from + * the final production bundle. + * + * Use ./main.js as the primary entrypoint for your client code to take full + * advantage of Vite's plugin and build system. + * + * This can also be a good place to put code that you don't want Vite to + * process, for example, if you run into a compatibility issue or need to use + * nested imports which Vite doesn't support. + */ \ No newline at end of file diff --git a/tools/static-assets/skel-solid/client/main.js b/tools/static-assets/skel-solid/client/main.js new file mode 100644 index 0000000000..44bcc64d55 --- /dev/null +++ b/tools/static-assets/skel-solid/client/main.js @@ -0,0 +1 @@ +import '../imports/ui/main'; \ No newline at end of file diff --git a/tools/static-assets/skel-solid/client/main.jsx b/tools/static-assets/skel-solid/client/main.jsx deleted file mode 100644 index 97d382a9bd..0000000000 --- a/tools/static-assets/skel-solid/client/main.jsx +++ /dev/null @@ -1 +0,0 @@ -// main entry point is in imports/ui/main.jsx diff --git a/tools/static-assets/skel-solid/client/main.css b/tools/static-assets/skel-solid/imports/ui/main.css similarity index 100% rename from tools/static-assets/skel-solid/client/main.css rename to tools/static-assets/skel-solid/imports/ui/main.css diff --git a/tools/static-assets/skel-solid/imports/ui/main.jsx b/tools/static-assets/skel-solid/imports/ui/main.jsx index 99eb6c43d7..044f1aee69 100644 --- a/tools/static-assets/skel-solid/imports/ui/main.jsx +++ b/tools/static-assets/skel-solid/imports/ui/main.jsx @@ -2,6 +2,7 @@ import { render } from 'solid-js/web'; import { App } from './App'; import { Meteor } from "meteor/meteor"; +import './main.css'; Meteor.startup(() => { render(() => , document.getElementById('root')); diff --git a/tools/static-assets/skel-solid/package.json b/tools/static-assets/skel-solid/package.json index e3cbb0efb5..17401d9c1b 100644 --- a/tools/static-assets/skel-solid/package.json +++ b/tools/static-assets/skel-solid/package.json @@ -8,21 +8,25 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1", - "solid-js": "^1.5.4" + "@babel/runtime": "^7.23.9", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.12", + "picocolors": "^1.1.1", + "solid-js": "^1.9.4" }, "meteor": { "mainModule": { - "client": "client/main.jsx", - "server": "server/main.js" + "client": "client/entry-meteor.js", + "server": "server/entry-meteor.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true }, "devDependencies": { - "babel-preset-solid": "^1.5.4", - "vite": "^3.0.9", - "vite-plugin-solid": "^2.3.0", - "vite-plugin-solid-svg": "^0.4.1" + "babel-preset-solid": "^1.8.15", + "meteor-vite": "^3.2.1", + "vite": "^6.0.11", + "vite-plugin-solid": "^2.11.0", + "vite-plugin-solid-svg": "^0.8.1" } } diff --git a/tools/static-assets/skel-solid/server/entry-meteor.js b/tools/static-assets/skel-solid/server/entry-meteor.js new file mode 100644 index 0000000000..8a066f8e94 --- /dev/null +++ b/tools/static-assets/skel-solid/server/entry-meteor.js @@ -0,0 +1,12 @@ +/** + * Entrypoint for the Meteor server + * Generally, this file can be left empty. Vite will add imports for your app's + * server bundle here during both development and production build. + * + * Use ./main.js as the primary entrypoint for your app to take full advantage + * of Vite's plugin and build system. + * + * This can also be a good place to put code that you don't want Vite to + * process, for example, if you run into a compatibility issue or need to use + * nested imports. + */ \ No newline at end of file diff --git a/tools/static-assets/skel-solid/vite.config.js b/tools/static-assets/skel-solid/vite.config.js deleted file mode 100644 index c49fa70b16..0000000000 --- a/tools/static-assets/skel-solid/vite.config.js +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'vite'; -import solidPlugin from 'vite-plugin-solid'; -import solidSvg from "vite-plugin-solid-svg"; - -export default defineConfig({ - plugins: [solidPlugin(), solidSvg({ - defaultExport: 'component', - })], - meteor: { - clientEntry: 'imports/ui/main.jsx', - }, -}); diff --git a/tools/static-assets/skel-solid/vite.config.mjs b/tools/static-assets/skel-solid/vite.config.mjs new file mode 100644 index 0000000000..e0215dbb10 --- /dev/null +++ b/tools/static-assets/skel-solid/vite.config.mjs @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite'; +import solidPlugin from 'vite-plugin-solid'; +import solidSvg from "vite-plugin-solid-svg"; +import { meteor } from 'meteor-vite/plugin'; + +export default defineConfig({ + plugins: [ + solidPlugin(), + solidSvg({ defaultExport: 'component' }), + meteor({ + clientEntry: 'client/main.js', + serverEntry: 'server/main.js', + enableExperimentalFeatures: true, + stubValidation: { + ignorePackages: ['meteor/mongo'], + }, + }), + ], +}); diff --git a/tools/static-assets/skel-svelte/imports/ui/App.svelte b/tools/static-assets/skel-svelte/imports/ui/App.svelte index d64c1297ee..9f18322c0b 100644 --- a/tools/static-assets/skel-svelte/imports/ui/App.svelte +++ b/tools/static-assets/skel-svelte/imports/ui/App.svelte @@ -6,15 +6,11 @@ const addToCounter = () => { counter += 1; } - - let subIsReady = false; - $m: { - const handle = Meteor.subscribe("links.all"); - subIsReady = handle.ready(); - } // more information about $m at https://atmospherejs.com/zodern/melte#tracker-statements - let links; + $m: handle = Meteor.subscribe("links.all"); + $m: subIsReady = handle.ready(); + $m: links = LinksCollection.find().fetch(); diff --git a/tools/static-assets/skel-svelte/package.json b/tools/static-assets/skel-svelte/package.json index 0ae79b3327..0929124049 100644 --- a/tools/static-assets/skel-svelte/package.json +++ b/tools/static-assets/skel-svelte/package.json @@ -8,9 +8,10 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.20.6", - "meteor-node-stubs": "^1.2.5", - "svelte": "^3.54.0" + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.12", + "svelte": "^3.59.2" }, "devDependencies": { "svelte-preprocess": "^5.0.0" @@ -27,6 +28,7 @@ ] } }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-svelte/tsconfig.json b/tools/static-assets/skel-svelte/tsconfig.json index 11f2c45698..7f0c17ad00 100644 --- a/tools/static-assets/skel-svelte/tsconfig.json +++ b/tools/static-assets/skel-svelte/tsconfig.json @@ -16,5 +16,5 @@ "preserveSymlinks": true, // required by zodern:types "preserveValueImports": true // otherwise TS will remove imported components }, - "exclude": ["./.meteor/**", "./packages/**"] // this may solve VS Code Svelte plugin warnings + "exclude": ["./.meteor/**", "!./.meteor/local/types", "./packages/**"] // this may solve VS Code Svelte plugin warnings } diff --git a/tools/static-assets/skel-tailwind/package.json b/tools/static-assets/skel-tailwind/package.json index 122c7e4cf8..73971202ba 100644 --- a/tools/static-assets/skel-tailwind/package.json +++ b/tools/static-assets/skel-tailwind/package.json @@ -8,9 +8,10 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.15.4", + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", "autoprefixer": "^10.4.4", - "meteor-node-stubs": "^1.2.1", + "meteor-node-stubs": "^1.2.12", "postcss": "^8.4.12", "postcss-load-config": "^3.1.4", "react": "^17.0.2", @@ -22,6 +23,7 @@ "client": "client/main.jsx", "server": "server/main.js" }, - "testModule": "tests/main.js" + "testModule": "tests/main.js", + "modern": true } } diff --git a/tools/static-assets/skel-tailwind/server/main.js b/tools/static-assets/skel-tailwind/server/main.js index 6d8dd672ad..6edde23143 100644 --- a/tools/static-assets/skel-tailwind/server/main.js +++ b/tools/static-assets/skel-tailwind/server/main.js @@ -10,7 +10,7 @@ Meteor.startup(async () => { if (await LinksCollection.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-typescript/package.json b/tools/static-assets/skel-typescript/package.json index 5689e482f6..77ff7934bf 100644 --- a/tools/static-assets/skel-typescript/package.json +++ b/tools/static-assets/skel-typescript/package.json @@ -8,23 +8,25 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@babel/runtime": "^7.20.7", - "meteor-node-stubs": "^1.2.5", + "@babel/runtime": "^7.23.5", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.12", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@types/mocha": "^8.2.3", - "@types/node": "^18.13.0", - "@types/react": "^18.0.26", - "@types/react-dom": "^18.0.10", - "typescript": "^4.9.4" + "@types/node": "^22.10.6", + "@types/react": "^18.2.5", + "@types/react-dom": "^18.2.4", + "typescript": "^5.4.5" }, "meteor": { "mainModule": { "client": "client/main.tsx", "server": "server/main.ts" }, - "testModule": "tests/main.ts" + "testModule": "tests/main.ts", + "modern": true } } diff --git a/tools/static-assets/skel-typescript/server/main.ts b/tools/static-assets/skel-typescript/server/main.ts index 861a50c044..5a7ca3abb0 100644 --- a/tools/static-assets/skel-typescript/server/main.ts +++ b/tools/static-assets/skel-typescript/server/main.ts @@ -10,7 +10,7 @@ Meteor.startup(async () => { if (await LinksCollection.find().countAsync() === 0) { await insertLink({ title: 'Do the Tutorial', - url: 'https://www.meteor.com/tutorials/react/creating-an-app', + url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html', }); await insertLink({ diff --git a/tools/static-assets/skel-vue-2/.gitignore b/tools/static-assets/skel-vue-2/.gitignore deleted file mode 100644 index c2658d7d1b..0000000000 --- a/tools/static-assets/skel-vue-2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/tools/static-assets/skel-vue-2/.meteor/packages b/tools/static-assets/skel-vue-2/.meteor/packages deleted file mode 100644 index 83be6b3a62..0000000000 --- a/tools/static-assets/skel-vue-2/.meteor/packages +++ /dev/null @@ -1,24 +0,0 @@ -# Meteor packages used by this project, one per line. -# Check this file (and the other files in this directory) into your repository. -# -# 'meteor add' and 'meteor remove' will edit this file for you, -# but you can also edit it by hand. - -meteor-base # Packages every Meteor app needs to have -mobile-experience # Packages for a great mobile UX -mongo # The database Meteor supports right now -reactive-var # Reactive variable for tracker - -standard-minifier-css # CSS minifier run for production mode -standard-minifier-js # JS minifier run for production mode -es5-shim # ECMAScript 5 compatibility for older browsers -ecmascript # Enable ECMAScript2015+ syntax in app code -typescript # Enable TypeScript syntax in .ts and .tsx modules -shell-server # Server-side component of the `meteor shell` command - -tracker # Dependency tracker to allow reactive callbacks -static-html # Define static page content in .html files -akryum:vue-component # Vue-CLI template to publish components - -meteortesting:mocha # A package for writing and running your meteor app and package tests with mocha -johanbrook:publication-collector # Test a Meteor publication by collecting its output diff --git a/tools/static-assets/skel-vue-2/client/main.html b/tools/static-assets/skel-vue-2/client/main.html deleted file mode 100644 index 7a78efb67d..0000000000 --- a/tools/static-assets/skel-vue-2/client/main.html +++ /dev/null @@ -1,8 +0,0 @@ - - ~name~ - - - - -
    - diff --git a/tools/static-assets/skel-vue-2/client/main.js b/tools/static-assets/skel-vue-2/client/main.js deleted file mode 100644 index 665c6aa1b1..0000000000 --- a/tools/static-assets/skel-vue-2/client/main.js +++ /dev/null @@ -1,12 +0,0 @@ -import Vue from 'vue' - -import '../imports/ui/plugins' - -import App from '../imports/ui/App.vue' - -Meteor.startup(() => { - new Vue({ - el: '#app', - ...App, - }) -}) diff --git a/tools/static-assets/skel-vue-2/imports/api/collections/Links.js b/tools/static-assets/skel-vue-2/imports/api/collections/Links.js deleted file mode 100644 index de6a43c4a4..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/collections/Links.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Mongo } from 'meteor/mongo'; - -export default new Mongo.Collection('links'); diff --git a/tools/static-assets/skel-vue-2/imports/api/collections/Links.tests.js b/tools/static-assets/skel-vue-2/imports/api/collections/Links.tests.js deleted file mode 100644 index ce178512d0..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/collections/Links.tests.js +++ /dev/null @@ -1,24 +0,0 @@ -// Tests for the behavior of the links collection -// -// https://guide.meteor.com/testing.html - -import { Meteor } from 'meteor/meteor'; -import { assert } from 'chai'; -import Links from './Links.js'; - -if (Meteor.isServer) { - describe('links collection', function () { - it('insert correctly', function () { - const linkId = Links.insert({ - title: 'meteor homepage', - url: 'https://www.meteor.com', - }); - const added = Links.find({ _id: linkId }); - const collectionName = added._getCollectionName(); - const count = added.count(); - - assert.equal(collectionName, 'links'); - assert.equal(count, 1); - }); - }); -} diff --git a/tools/static-assets/skel-vue-2/imports/api/fixtures.js b/tools/static-assets/skel-vue-2/imports/api/fixtures.js deleted file mode 100644 index daa11f32f1..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/fixtures.js +++ /dev/null @@ -1,31 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import Links from './collections/Links.js'; - -async function insertLink({ title, url }) { - await Links.insertAsync({ title, url, createdAt: new Date() }); -} - -Meteor.startup(async () => { - // If the Links collection is empty, add some data. - if (await Links.find().countAsync() === 0) { - await insertLink({ - title: 'Do the Tutorial', - url: 'https://vue-tutorial.meteor.com/', - }); - - await insertLink({ - title: 'Follow the Guide', - url: 'https://guide.meteor.com', - }); - - await insertLink({ - title: 'Read the Docs', - url: 'https://docs.meteor.com', - }); - - await insertLink({ - title: 'Discussions', - url: 'https://forums.meteor.com', - }); - } -}); diff --git a/tools/static-assets/skel-vue-2/imports/api/methods/createLink.js b/tools/static-assets/skel-vue-2/imports/api/methods/createLink.js deleted file mode 100644 index 876f710978..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/methods/createLink.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; -import Links from '../collections/Links.js'; - -Meteor.methods({ - 'createLink'(title, url) { - check(url, String); - check(title, String); - - return Links.insert({ - url, - title, - createdAt: new Date(), - }); - }, -}); diff --git a/tools/static-assets/skel-vue-2/imports/api/methods/createLink.tests.js b/tools/static-assets/skel-vue-2/imports/api/methods/createLink.tests.js deleted file mode 100644 index d899a7338f..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/methods/createLink.tests.js +++ /dev/null @@ -1,20 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { assert } from 'chai'; -import Links from '../collections/Links.js'; -import './methods.js'; - -if (Meteor.isServer) { - describe('method: createLink', function () { - beforeEach(function () { - Links.remove({}); - }); - - it('can add a new link', function () { - const addLink = Meteor.server.method_handlers['createLink']; - - addLink.apply({}, ['meteor.com', 'https://www.meteor.com']); - - assert.equal(Links.find().count(), 1); - }); - }); -} diff --git a/tools/static-assets/skel-vue-2/imports/api/methods/index.js b/tools/static-assets/skel-vue-2/imports/api/methods/index.js deleted file mode 100644 index c52403a2e8..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/methods/index.js +++ /dev/null @@ -1 +0,0 @@ -import './createLink' diff --git a/tools/static-assets/skel-vue-2/imports/api/publications/index.js b/tools/static-assets/skel-vue-2/imports/api/publications/index.js deleted file mode 100644 index d161b580e7..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/publications/index.js +++ /dev/null @@ -1 +0,0 @@ -import './links' diff --git a/tools/static-assets/skel-vue-2/imports/api/publications/links.js b/tools/static-assets/skel-vue-2/imports/api/publications/links.js deleted file mode 100644 index f085d75045..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/publications/links.js +++ /dev/null @@ -1,6 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import Links from '../collections/Links.js'; - -Meteor.publish('links', function () { - return Links.find(); -}); diff --git a/tools/static-assets/skel-vue-2/imports/api/publications/links.tests.js b/tools/static-assets/skel-vue-2/imports/api/publications/links.tests.js deleted file mode 100644 index 37f337c869..0000000000 --- a/tools/static-assets/skel-vue-2/imports/api/publications/links.tests.js +++ /dev/null @@ -1,22 +0,0 @@ -import { assert } from 'chai' -import { PublicationCollector } from 'meteor/johanbrook:publication-collector' -import Links from '../collections/Links.js' -import './publications.js' - -describe('Publish links', function () { - beforeEach(function () { - Links.remove({}) - Links.insert({ - title: 'meteor homepage', - url: 'https://www.meteor.com' - }) - }) - - it('sends all links', function (done) { - const collector = new PublicationCollector() - collector.collect('links', (collections) => { - assert.equal(collections.links.length, 1) - done() - }) - }) -}) diff --git a/tools/static-assets/skel-vue-2/imports/ui/App.vue b/tools/static-assets/skel-vue-2/imports/ui/App.vue deleted file mode 100644 index e126098ccb..0000000000 --- a/tools/static-assets/skel-vue-2/imports/ui/App.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/tools/static-assets/skel-vue-2/imports/ui/components/Hello.vue b/tools/static-assets/skel-vue-2/imports/ui/components/Hello.vue deleted file mode 100644 index 64947eb06a..0000000000 --- a/tools/static-assets/skel-vue-2/imports/ui/components/Hello.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/tools/static-assets/skel-vue-2/imports/ui/components/Info.vue b/tools/static-assets/skel-vue-2/imports/ui/components/Info.vue deleted file mode 100644 index b52b2be838..0000000000 --- a/tools/static-assets/skel-vue-2/imports/ui/components/Info.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - - diff --git a/tools/static-assets/skel-vue-2/imports/ui/plugins.js b/tools/static-assets/skel-vue-2/imports/ui/plugins.js deleted file mode 100644 index eb976c92e5..0000000000 --- a/tools/static-assets/skel-vue-2/imports/ui/plugins.js +++ /dev/null @@ -1,4 +0,0 @@ -import Vue from 'vue' -import VueMeteorTracker from 'vue-meteor-tracker' - -Vue.use(VueMeteorTracker) diff --git a/tools/static-assets/skel-vue-2/server/main.js b/tools/static-assets/skel-vue-2/server/main.js deleted file mode 100644 index 42950618b6..0000000000 --- a/tools/static-assets/skel-vue-2/server/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import '../imports/api/fixtures' -import '../imports/api/methods' -import '../imports/api/publications' diff --git a/tools/static-assets/skel-vue-2/tests/main.js b/tools/static-assets/skel-vue-2/tests/main.js deleted file mode 100644 index 6d2a32e09d..0000000000 --- a/tools/static-assets/skel-vue-2/tests/main.js +++ /dev/null @@ -1,20 +0,0 @@ -import assert from "assert"; - -describe("skel", function () { - it("package.json has correct name", async function () { - const { name } = await import("../package.json"); - assert.strictEqual(name, "skel"); - }); - - if (Meteor.isClient) { - it("client is not server", function () { - assert.strictEqual(Meteor.isServer, false); - }); - } - - if (Meteor.isServer) { - it("server is not client", function () { - assert.strictEqual(Meteor.isClient, false); - }); - } -}); diff --git a/tools/static-assets/skel-vue/.meteor/packages b/tools/static-assets/skel-vue/.meteor/packages index 2565a5fe32..b5e90db564 100644 --- a/tools/static-assets/skel-vue/.meteor/packages +++ b/tools/static-assets/skel-vue/.meteor/packages @@ -4,18 +4,19 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor-base@1.5.1 # Packages every Meteor app needs to have -mobile-experience@1.1.0 # Packages for a great mobile UX -mongo@1.16.0 # The database Meteor supports right now -reactive-var@1.0.11 # Reactive variable for tracker +meteor-base # Packages every Meteor app needs to have +mobile-experience # Packages for a great mobile UX +mongo # The database Meteor supports right now +reactive-var # Reactive variable for tracker -standard-minifier-css@1.8.2 # CSS minifier run for production mode -standard-minifier-js@2.8.1 # JS minifier run for production mode -es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers -ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code -typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules -shell-server@0.5.0 # Server-side component of the `meteor shell` command -hot-module-replacement@0.5.1 # Update client in development without reloading the page +standard-minifier-css # CSS minifier run for production mode +standard-minifier-js # JS minifier run for production mode +es5-shim # ECMAScript 5 compatibility for older browsers +ecmascript # Enable ECMAScript2015+ syntax in app code +typescript # Enable TypeScript syntax in .ts and .tsx modules +shell-server # Server-side component of the `meteor shell` command +hot-module-replacement # Update client in development without reloading the page -static-html@1.3.2 # Define static page content in .html files -vite:bundler +static-html # Define static page content in .html files +jorgenvatle:vite +~prototype~ diff --git a/tools/static-assets/skel-vue/.meteor/release b/tools/static-assets/skel-vue/.meteor/release deleted file mode 100644 index 1d2a6d0f79..0000000000 --- a/tools/static-assets/skel-vue/.meteor/release +++ /dev/null @@ -1 +0,0 @@ -METEOR@2.8.0 diff --git a/tools/static-assets/skel-vue/.meteor/versions b/tools/static-assets/skel-vue/.meteor/versions deleted file mode 100644 index 3b89f7359b..0000000000 --- a/tools/static-assets/skel-vue/.meteor/versions +++ /dev/null @@ -1,71 +0,0 @@ -allow-deny@1.1.1 -autoupdate@1.8.0 -babel-compiler@7.9.2 -babel-runtime@1.5.1 -base64@1.0.12 -binary-heap@1.0.11 -blaze-tools@1.1.3 -boilerplate-generator@1.7.1 -caching-compiler@1.2.2 -caching-html-compiler@1.2.1 -callback-hook@1.4.0 -check@1.3.1 -ddp@1.4.0 -ddp-client@2.6.0 -ddp-common@1.4.0 -ddp-server@2.6.0 -diff-sequence@1.1.1 -dynamic-import@0.7.2 -ecmascript@0.16.2 -ecmascript-runtime@0.8.0 -ecmascript-runtime-client@0.12.1 -ecmascript-runtime-server@0.11.0 -ejson@1.1.2 -es5-shim@4.8.0 -fetch@0.1.1 -geojson-utils@1.0.10 -hot-code-push@1.0.4 -hot-module-replacement@0.5.1 -html-tools@1.1.3 -htmljs@1.1.1 -id-map@1.1.1 -inter-process-messaging@0.1.1 -launch-screen@1.3.0 -logging@1.3.1 -meteor@1.10.1 -meteor-base@1.5.1 -minifier-css@1.6.1 -minifier-js@2.7.5 -minimongo@1.9.0 -mobile-experience@1.1.0 -mobile-status-bar@1.1.0 -modern-browsers@0.1.8 -modules@0.19.0 -modules-runtime@0.13.0 -modules-runtime-hot@0.14.0 -mongo@1.16.0 -mongo-decimal@0.1.3 -mongo-dev-server@1.1.0 -mongo-id@1.0.8 -npm-mongo@4.9.0 -ordered-dict@1.1.0 -promise@0.12.0 -random@1.2.0 -react-fast-refresh@0.2.3 -reactive-var@1.0.11 -reload@1.3.1 -retry@1.1.0 -routepolicy@1.1.1 -shell-server@0.5.0 -socket-stream-client@0.5.0 -spacebars-compiler@1.3.1 -standard-minifier-css@1.8.2 -standard-minifier-js@2.8.1 -static-html@1.3.2 -templating-tools@1.2.2 -tracker@1.2.0 -typescript@4.5.4 -underscore@1.0.10 -vite:bundler@0.1.9 -webapp@1.13.1 -webapp-hashing@1.1.0 diff --git a/tools/static-assets/skel-vue/client/entry-meteor.js b/tools/static-assets/skel-vue/client/entry-meteor.js new file mode 100644 index 0000000000..0ec3ddc121 --- /dev/null +++ b/tools/static-assets/skel-vue/client/entry-meteor.js @@ -0,0 +1,14 @@ +/** + * Entrypoint for the Meteor client + * + * Generally, this file can be left empty. Vite will add imports for + * lazy-loaded Meteor packages to this file to ensure they aren't omitted from + * the final production bundle. + * + * Use ./main.js as the primary entrypoint for your client code to take full + * advantage of Vite's plugin and build system. + * + * This can also be a good place to put code that you don't want Vite to + * process, for example, if you run into a compatibility issue or need to use + * nested imports which Vite doesn't support. + */ \ No newline at end of file diff --git a/tools/static-assets/skel-vue/client/main.css b/tools/static-assets/skel-vue/client/main.css deleted file mode 100644 index b5c61c9567..0000000000 --- a/tools/static-assets/skel-vue/client/main.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/tools/static-assets/skel-vue/client/main.js b/tools/static-assets/skel-vue/client/main.js index 97d382a9bd..403d8a2d2a 100644 --- a/tools/static-assets/skel-vue/client/main.js +++ b/tools/static-assets/skel-vue/client/main.js @@ -1 +1 @@ -// main entry point is in imports/ui/main.jsx +import '../imports/ui/main' \ No newline at end of file diff --git a/tools/static-assets/skel-vue/imports/ui/App.vue b/tools/static-assets/skel-vue/imports/ui/App.vue index 7a775391cb..19a68a1ea1 100644 --- a/tools/static-assets/skel-vue/imports/ui/App.vue +++ b/tools/static-assets/skel-vue/imports/ui/App.vue @@ -1,5 +1,5 @@