diff --git a/.autofix.markdownlint-cli2.jsonc b/.autofix.markdownlint-cli2.jsonc new file mode 100644 index 0000000000000..5d7f87fcab44d --- /dev/null +++ b/.autofix.markdownlint-cli2.jsonc @@ -0,0 +1,8 @@ +{ + "config": { + "default": false, + "no-trailing-spaces": { + "br_spaces": 0 + } + } +} diff --git a/.circleci/.gitignore b/.circleci/.gitignore deleted file mode 100644 index 2b7d56379cacd..0000000000000 --- a/.circleci/.gitignore +++ /dev/null @@ -1 +0,0 @@ -config-staging diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 372018b9e2532..0000000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,76 +0,0 @@ -version: 2.1 - -# Required for dynamic configuration -setup: true - -# Orbs -orbs: - path-filtering: circleci/path-filtering@0.1.0 - continuation: circleci/continuation@0.2.0 - -# All input parameters to pass to build config -parameters: - run-docs-only: - type: boolean - default: false - - upload-to-storage: - type: string - default: '1' - - run-build-linux: - type: boolean - default: false - - run-build-mac: - type: boolean - default: false - - run-linux-publish: - type: boolean - default: false - - linux-publish-arch-limit: - type: enum - default: all - enum: ["all", "arm", "arm64", "x64", "ia32"] - - run-macos-publish: - type: boolean - default: false - - macos-publish-arch-limit: - type: enum - default: all - enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"] - -jobs: - generate-config: - docker: - - image: cimg/node:16.14 - steps: - - checkout - - path-filtering/set-parameters: - base-revision: main - mapping: | - ^((?!docs/).)*$ run-build-mac true - ^((?!docs/).)*$ run-build-linux true - docs/.* run-docs-only true - ^((?!docs/).)*$ run-docs-only false - - run: - command: | - cd .circleci/config - yarn - export CIRCLECI_BINARY="$HOME/circleci" - curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | DESTDIR=$CIRCLECI_BINARY bash - node build.js - name: Pack config.yml - - continuation/continue: - configuration_path: .circleci/config-staging/built.yml - parameters: /tmp/pipeline-parameters.json - -# Initial setup workflow -workflows: - setup: - jobs: - - generate-config diff --git a/.circleci/config/base.yml b/.circleci/config/base.yml deleted file mode 100644 index 4cad08bb782a3..0000000000000 --- a/.circleci/config/base.yml +++ /dev/null @@ -1,2235 +0,0 @@ -version: 2.1 - -parameters: - run-docs-only: - type: boolean - default: false - - upload-to-storage: - type: string - default: '1' - - run-build-linux: - type: boolean - default: false - - run-build-mac: - type: boolean - default: false - - run-linux-publish: - type: boolean - default: false - - linux-publish-arch-limit: - type: enum - default: all - enum: ["all", "arm", "arm64", "x64"] - - run-macos-publish: - type: boolean - default: false - - macos-publish-arch-limit: - type: enum - default: all - enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"] - -# Executors -executors: - linux-docker: - parameters: - size: - description: "Docker executor size" - type: enum - enum: ["medium", "xlarge", "2xlarge"] - docker: - - image: ghcr.io/electron/build:e6bebd08a51a0d78ec23e5b3fd7e7c0846412328 - resource_class: << parameters.size >> - - macos: - parameters: - size: - description: "macOS executor size" - type: enum - enum: ["macos.x86.medium.gen2", "large"] - macos: - xcode: 13.3.0 - resource_class: << parameters.size >> - - # Electron Runners - apple-silicon: - resource_class: electronjs/macos-arm64 - machine: true - - linux-arm: - resource_class: electronjs/linux-arm - machine: true - - linux-arm64: - resource_class: electronjs/linux-arm64 - machine: true - -# The config expects the following environment variables to be set: -# - "SLACK_WEBHOOK" Slack hook URL to send notifications. -# -# The publishing scripts expect access tokens to be defined as env vars, -# but those are not covered here. -# -# CircleCI docs on variables: -# https://circleci.com/docs/2.0/env-vars/ - -# Build configurations options. -env-testing-build: &env-testing-build - GN_CONFIG: //electron/build/args/testing.gn - CHECK_DIST_MANIFEST: '1' - -env-release-build: &env-release-build - GN_CONFIG: //electron/build/args/release.gn - STRIP_BINARIES: true - GENERATE_SYMBOLS: true - CHECK_DIST_MANIFEST: '1' - IS_RELEASE: true - -env-headless-testing: &env-headless-testing - DISPLAY: ':99.0' - -env-stack-dumping: &env-stack-dumping - ELECTRON_ENABLE_STACK_DUMPING: '1' - -env-browsertests: &env-browsertests - GN_CONFIG: //electron/build/args/native_tests.gn - BUILD_TARGET: electron/spec:chromium_browsertests - TESTS_CONFIG: src/electron/spec/configs/browsertests.yml - -env-unittests: &env-unittests - GN_CONFIG: //electron/build/args/native_tests.gn - BUILD_TARGET: electron/spec:chromium_unittests - TESTS_CONFIG: src/electron/spec/configs/unittests.yml - -env-arm: &env-arm - GN_EXTRA_ARGS: 'target_cpu = "arm"' - MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm - BUILD_NATIVE_MKSNAPSHOT: 1 - TARGET_ARCH: arm - -env-apple-silicon: &env-apple-silicon - GN_EXTRA_ARGS: 'target_cpu = "arm64" use_prebuilt_v8_context_snapshot = true' - TARGET_ARCH: arm64 - USE_PREBUILT_V8_CONTEXT_SNAPSHOT: 1 - npm_config_arch: arm64 - -env-runner: &env-runner - IS_ELECTRON_RUNNER: 1 - -env-arm64: &env-arm64 - GN_EXTRA_ARGS: 'target_cpu = "arm64" fatal_linker_warnings = false enable_linux_installer = false' - MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm64 - BUILD_NATIVE_MKSNAPSHOT: 1 - TARGET_ARCH: arm64 - -env-mas: &env-mas - GN_EXTRA_ARGS: 'is_mas_build = true' - MAS_BUILD: 'true' - -env-mas-apple-silicon: &env-mas-apple-silicon - GN_EXTRA_ARGS: 'target_cpu = "arm64" is_mas_build = true use_prebuilt_v8_context_snapshot = true' - MAS_BUILD: 'true' - TARGET_ARCH: arm64 - USE_PREBUILT_V8_CONTEXT_SNAPSHOT: 1 - -env-send-slack-notifications: &env-send-slack-notifications - NOTIFY_SLACK: true - -env-global: &env-global - ELECTRON_OUT_DIR: Default - -env-linux-medium: &env-linux-medium - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 3 - -env-linux-2xlarge: &env-linux-2xlarge - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 34 - -env-linux-2xlarge-release: &env-linux-2xlarge-release - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 16 - -env-machine-mac: &env-machine-mac - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 6 - -env-mac-large: &env-mac-large - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 18 - -env-mac-large-release: &env-mac-large-release - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 8 - -env-ninja-status: &env-ninja-status - NINJA_STATUS: "[%r processes, %f/%t @ %o/s : %es] " - -env-disable-run-as-node: &env-disable-run-as-node - GN_BUILDFLAG_ARGS: 'enable_run_as_node = false' - -env-32bit-release: &env-32bit-release - # Set symbol level to 1 for 32 bit releases because of https://crbug.com/648948 - GN_BUILDFLAG_ARGS: 'symbol_level = 1' - -env-macos-build: &env-macos-build - # Disable pre-compiled headers to reduce out size, only useful for rebuilds - GN_BUILDFLAG_ARGS: 'enable_precompiled_headers = false' - -# Individual (shared) steps. -step-maybe-notify-slack-failure: &step-maybe-notify-slack-failure - run: - name: Send a Slack notification on failure - command: | - if [ "$NOTIFY_SLACK" == "true" ]; then - export MESSAGE="Build failed for *<$CIRCLE_BUILD_URL|$CIRCLE_JOB>* nightly build from *$CIRCLE_BRANCH*." - curl -g -H "Content-Type: application/json" -X POST \ - -d "{\"text\": \"$MESSAGE\", \"attachments\": [{\"color\": \"#FC5C3C\",\"title\": \"$CIRCLE_JOB nightly build results\",\"title_link\": \"$CIRCLE_BUILD_URL\"}]}" $SLACK_WEBHOOK - fi - when: on_fail - -step-maybe-notify-slack-success: &step-maybe-notify-slack-success - run: - name: Send a Slack notification on success - command: | - if [ "$NOTIFY_SLACK" == "true" ]; then - export MESSAGE="Build succeeded for *<$CIRCLE_BUILD_URL|$CIRCLE_JOB>* nightly build from *$CIRCLE_BRANCH*." - curl -g -H "Content-Type: application/json" -X POST \ - -d "{\"text\": \"$MESSAGE\", \"attachments\": [{\"color\": \"good\",\"title\": \"$CIRCLE_JOB nightly build results\",\"title_link\": \"$CIRCLE_BUILD_URL\"}]}" $SLACK_WEBHOOK - fi - when: on_success - -step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac - run: - name: Cleanup after testing - command: | - if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then - killall Electron || echo "No Electron processes left running" - killall Safari || echo "No Safari processes left running" - rm -rf ~/Library/Application\ Support/Electron* - rm -rf ~/Library/Application\ Support/electron* - security delete-generic-password -l "Chromium Safe Storage" || echo "✓ Keychain does not contain password from tests" - security delete-generic-password -l "Electron Test Main Safe Storage" || echo "✓ Keychain does not contain password from tests" - elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - XVFB=/usr/bin/Xvfb - /sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running" - pkill electron || echo "electron not running" - rm -rf ~/.config/Electron* - rm -rf ~/.config/electron* - fi - - when: always - -step-checkout-electron: &step-checkout-electron - checkout: - path: src/electron - -step-depot-tools-get: &step-depot-tools-get - run: - name: Get depot tools - command: | - git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git - if [ "`uname`" == "Darwin" ]; then - # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems - sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja - else - sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja - # Remove swift-format dep from cipd on macOS until we send a patch upstream. - cd depot_tools - patch gclient.py -R \<<'EOF' - 676,677c676 - < packages = dep_value.get('packages', []) - < for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')): - --- - > for package in dep_value.get('packages', []): - EOF - fi - -step-depot-tools-add-to-path: &step-depot-tools-add-to-path - run: - name: Add depot tools to PATH - command: echo 'export PATH="$PATH:'"$PWD"'/depot_tools"' >> $BASH_ENV - -step-gclient-sync: &step-gclient-sync - run: - name: Gclient sync - command: | - # If we did not restore a complete sync then we need to sync for realz - if [ ! -s "src/electron/.circle-sync-done" ]; then - gclient config \ - --name "src/electron" \ - --unmanaged \ - $GCLIENT_EXTRA_ARGS \ - "$CIRCLE_REPOSITORY_URL" - - ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags - if [ "$IS_RELEASE" != "true" ]; then - # Re-export all the patches to check if there were changes. - python src/electron/script/export_all_patches.py src/electron/patches/config.json - cd src/electron - git update-index --refresh || true - if ! git diff-index --quiet HEAD --; then - # There are changes to the patches. Make a git commit with the updated patches - git add patches - GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>" - # Export it - mkdir -p ../../patches - git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch - if (node ./script/push-patch.js 2> /dev/null > /dev/null); then - echo - echo "======================================================================" - echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch" - echo "A new CI job will kick off shortly" - echo "======================================================================" - exit 1 - else - echo - echo "======================================================================" - echo "There were changes to the patches when applying." - echo "Check the CI artifacts for a patch you can apply to fix it." - echo "======================================================================" - exit 1 - fi - fi - fi - fi - -step-setup-env-for-build: &step-setup-env-for-build - run: - name: Setup Environment Variables - command: | - # To find `gn` executable. - echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV - -step-setup-goma-for-build: &step-setup-goma-for-build - run: - name: Setup Goma - command: | - echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV - if [ "`uname`" == "Darwin" ]; then - echo 'ulimit -n 10000' >> $BASH_ENV - echo 'sudo launchctl limit maxfiles 65536 200000' >> $BASH_ENV - fi - if [ ! -z "$RAW_GOMA_AUTH" ]; then - echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config - fi - git clone https://github.com/electron/build-tools.git - cd build-tools - npm install - mkdir third_party - node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" - export GOMA_FALLBACK_ON_AUTH_FAILURE=true - third_party/goma/goma_ctl.py ensure_start - if [ ! -z "$RAW_GOMA_AUTH" ] && [ "`third_party/goma/goma_auth.py info`" != "Login as Fermi Planck" ]; then - echo "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token." - exit 1 - fi - echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV - echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV - echo 'export GOMA_FALLBACK_ON_AUTH_FAILURE=true' >> $BASH_ENV - cd .. - touch "${TMPDIR:=/tmp}"/.goma-ready - background: true - -step-wait-for-goma: &step-wait-for-goma - run: - name: Wait for Goma - command: | - until [ -f "${TMPDIR:=/tmp}"/.goma-ready ] - do - sleep 5 - done - echo "Goma ready" - no_output_timeout: 5m - -step-restore-brew-cache: &step-restore-brew-cache - restore_cache: - paths: - - /usr/local/Cellar/gnu-tar - - /usr/local/bin/gtar - keys: - - v5-brew-cache-{{ arch }} - -step-save-brew-cache: &step-save-brew-cache - save_cache: - paths: - - /usr/local/Cellar/gnu-tar - - /usr/local/bin/gtar - key: v5-brew-cache-{{ arch }} - name: Persisting brew cache - -step-get-more-space-on-mac: &step-get-more-space-on-mac - run: - name: Free up space on MacOS - command: | - if [ "`uname`" == "Darwin" ]; then - sudo mkdir -p $TMPDIR/del-target - - tmpify() { - if [ -d "$1" ]; then - sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) - fi - } - - strip_arm_deep() { - opwd=$(pwd) - cd $1 - f=$(find . -perm +111 -type f) - for fp in $f - do - if [[ $(file "$fp") == *"universal binary"* ]]; then - if [[ $(file "$fp") == *"arm64e)"* ]]; then - sudo lipo -remove arm64e "$fp" -o "$fp" || true - fi - if [[ $(file "$fp") == *"arm64)"* ]]; then - sudo lipo -remove arm64 "$fp" -o "$fp" || true - fi - fi - done - - cd $opwd - } - - tmpify /Library/Developer/CoreSimulator - tmpify ~/Library/Developer/CoreSimulator - tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform - tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform - tmpify $(xcode-select -p)/Platforms/WatchOS.platform - tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform - tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform - tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0 - tmpify ~/.rubies - tmpify ~/Library/Caches/Homebrew - tmpify /usr/local/Homebrew - sudo rm -rf $TMPDIR/del-target - - # sudo rm -rf "/System/Library/Desktop Pictures" - # sudo rm -rf /System/Library/Templates/Data - # sudo rm -rf /System/Library/Speech/Voices - # sudo rm -rf "/System/Library/Screen Savers" - # sudo rm -rf /System/Volumes/Data/Library/Developer/CommandLineTools/SDKs - # sudo rm -rf "/System/Volumes/Data/Library/Application Support/Apple/Photos/Print Products" - # sudo rm -rf /System/Volumes/Data/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/ - # sudo rm -rf /System/Volumes/Data/Library/Java - # sudo rm -rf /System/Volumes/Data/Library/Ruby - # sudo rm -rf /System/Volumes/Data/Library/Printers - # sudo rm -rf /System/iOSSupport - # sudo rm -rf /System/Applications/*.app - # sudo rm -rf /System/Applications/Utilities/*.app - # sudo rm -rf /System/Library/LinguisticData - # sudo rm -rf /System/Volumes/Data/private/var/db/dyld/* - # sudo rm -rf /System/Library/Fonts/* - # sudo rm -rf /System/Library/PreferencePanes - # sudo rm -rf /System/Library/AssetsV2/* - sudo rm -rf /Applications/Safari.app - sudo rm -rf ~/project/src/build/linux - sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data - sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS - - # lipo off some huge binaries arm64 versions to save space - strip_arm_deep $(xcode-select -p)/../SharedFrameworks - # strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr - fi - background: true - -# On macOS delete all .git directories under src/ expect for -# third_party/angle/ and third_party/dawn/ because of build time generation of files -# gen/angle/commit.h depends on third_party/angle/.git/HEAD -# https://chromium-review.googlesource.com/c/angle/angle/+/2074924 -# and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD -# https://dawn-review.googlesource.com/c/dawn/+/83901 -# TODO: maybe better to always leave out */.git/HEAD file for all targets ? -step-delete-git-directories: &step-delete-git-directories - run: - name: Delete all .git directories under src on MacOS to free space - command: | - if [ "`uname`" == "Darwin" ]; then - cd src - ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" ) | xargs rm -rf - fi - -# On macOS the yarn install command during gclient sync was run on a linux -# machine and therefore installed a slightly different set of dependencies -# Notably "fsevents" is a macOS only dependency, we rerun yarn install once -# we are on a macOS machine to get the correct state -step-install-npm-deps-on-mac: &step-install-npm-deps-on-mac - run: - name: Install node_modules on MacOS - command: | - if [ "`uname`" == "Darwin" ]; then - cd src/electron - node script/yarn install - fi - -step-install-npm-deps: &step-install-npm-deps - run: - name: Install node_modules - command: | - cd src/electron - node script/yarn install --frozen-lockfile - -# This step handles the differences between the linux "gclient sync" -# and the expected state on macOS -step-fix-sync: &step-fix-sync - run: - name: Fix Sync - command: | - if [ "`uname`" == "Darwin" ]; then - # Fix Clang Install (wrong binary) - rm -rf src/third_party/llvm-build - python3 src/tools/clang/scripts/update.py - - # Fix esbuild (wrong binary) - echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file - # Remove extra output from calling gclient getdep which always calls update_depot_tools - sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file - cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file - fi - - cd src/third_party/angle - rm .git/objects/info/alternates - git remote set-url origin https://chromium.googlesource.com/angle/angle.git - cp .git/config .git/config.backup - git remote remove origin - mv .git/config.backup .git/config - git fetch - -step-install-signing-cert-on-mac: &step-install-signing-cert-on-mac - run: - name: Import and trust self-signed codesigning cert on MacOS - command: | - if [ "$TARGET_ARCH" != "arm64" ] && [ "`uname`" == "Darwin" ]; then - sudo security authorizationdb write com.apple.trust-settings.admin allow - cd src/electron - ./script/codesign/generate-identity.sh - fi - -step-install-gnutar-on-mac: &step-install-gnutar-on-mac - run: - name: Install gnu-tar on macos - command: | - if [ "`uname`" == "Darwin" ]; then - if [ ! -d /usr/local/Cellar/gnu-tar/ ]; then - brew update - brew install gnu-tar - fi - ln -fs /usr/local/bin/gtar /usr/local/bin/tar - fi - -step-gn-gen-default: &step-gn-gen-default - run: - name: Default GN gen - command: | - cd src - gn gen out/Default --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - -step-gn-check: &step-gn-check - run: - name: GN check - command: | - cd src - gn check out/Default //electron:electron_lib - gn check out/Default //electron:electron_app - gn check out/Default //electron/shell/common/api:mojo - # Check the hunspell filenames - node electron/script/gen-hunspell-filenames.js --check - node electron/script/gen-libc++-filenames.js --check - -step-electron-build: &step-electron-build - run: - name: Electron build - no_output_timeout: 60m - command: | - # On arm platforms we generate a cross-arch ffmpeg that ninja does not seem - # to realize is not correct / should be rebuilt. We delete it here so it is - # rebuilt - if [ "$TRIGGER_ARM_TEST" == "true" ]; then - rm -f src/out/Default/libffmpeg.so - fi - cd src - # Enable if things get really bad - # if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then - # diskutil erasevolume HFS+ "xcode_disk" `hdiutil attach -nomount ram://12582912` - # mv /Applications/Xcode-12.beta.5.app /Volumes/xcode_disk/ - # ln -s /Volumes/xcode_disk/Xcode-12.beta.5.app /Applications/Xcode-12.beta.5.app - # fi - - # Lets generate a snapshot and mksnapshot and then delete all the x-compiled generated files to save space - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" == "1" ]; then - ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - (cd out/Default; zip mksnapshot.zip mksnapshot_args clang_x64_v8_arm64/gen/v8/embedded.S) - rm -rf out/Default/clang_x64_v8_arm64/gen - rm -rf out/Default/clang_x64_v8_arm64/obj - rm -rf out/Default/clang_x64_v8_arm64/thinlto-cache - rm -rf out/Default/clang_x64/obj - - # Regenerate because we just deleted some ninja files - gn gen out/Default --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - fi - NINJA_SUMMARIZE_BUILD=1 autoninja -C out/Default electron -j $NUMBER_OF_NINJA_PROCESSES - cp out/Default/.ninja_log out/electron_ninja_log - node electron/script/check-symlinks.js - -step-maybe-electron-dist-strip: &step-maybe-electron-dist-strip - run: - name: Strip electron binaries - command: | - if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" == "Linux" ]; then - if [ x"$TARGET_ARCH" == x ]; then - target_cpu=x64 - else - target_cpu="$TARGET_ARCH" - fi - cd src - electron/script/copy-debug-symbols.py --target-cpu="$target_cpu" --out-dir=out/Default/debug --compress - electron/script/strip-binaries.py --target-cpu="$target_cpu" - electron/script/add-debug-link.py --target-cpu="$target_cpu" --debug-dir=out/Default/debug - fi - -step-electron-chromedriver-build: &step-electron-chromedriver-build - run: - name: Build chromedriver.zip - command: | - cd src - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - gn gen out/chromedriver --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") is_component_ffmpeg=false proprietary_codecs=false $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - export CHROMEDRIVER_DIR="out/chromedriver" - else - export CHROMEDRIVER_DIR="out/Default" - fi - ninja -C $CHROMEDRIVER_DIR electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES - if [ "`uname`" == "Linux" ]; then - electron/script/strip-binaries.py --target-cpu="$TARGET_ARCH" --file $PWD/$CHROMEDRIVER_DIR/chromedriver - fi - ninja -C $CHROMEDRIVER_DIR electron:electron_chromedriver_zip - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - cp out/chromedriver/chromedriver.zip out/Default - fi - -step-nodejs-headers-build: &step-nodejs-headers-build - run: - name: Build Node.js headers - command: | - cd src - ninja -C out/Default third_party/electron_node:headers - -step-electron-publish: &step-electron-publish - run: - name: Publish Electron Dist - command: | - if [ "`uname`" == "Darwin" ]; then - rm -rf src/out/Default/obj - fi - - cd src/electron - if [ "$UPLOAD_TO_STORAGE" == "1" ]; then - echo 'Uploading Electron release distribution to Azure' - script/release/uploaders/upload.py --verbose --UPLOAD_TO_STORAGE - else - echo 'Uploading Electron release distribution to GitHub releases' - script/release/uploaders/upload.py --verbose - fi - -step-persist-data-for-tests: &step-persist-data-for-tests - persist_to_workspace: - root: . - paths: - # Build artifacts - - src/out/Default/dist.zip - - src/out/Default/mksnapshot.zip - - src/out/Default/chromedriver.zip - - src/out/Default/gen/node_headers - - src/out/Default/overlapped-checker - - src/out/ffmpeg/ffmpeg.zip - - src/electron - - src/third_party/electron_node - - src/third_party/nan - - src/cross-arch-snapshots - - src/third_party/llvm-build - - src/build/linux - - src/buildtools/third_party/libc++ - - src/buildtools/third_party/libc++abi - - src/out/Default/obj/buildtools/third_party - -step-electron-dist-unzip: &step-electron-dist-unzip - run: - name: Unzip dist.zip - command: | - cd src/out/Default - # -o overwrite files WITHOUT prompting - # TODO(alexeykuzmin): Remove '-o' when it's no longer needed. - # -: allows to extract archive members into locations outside - # of the current ``extraction root folder''. - # ASan builds have the llvm-symbolizer binaries listed as - # runtime_deps, with their paths as `../../third_party/...` - # unzip exits with non-zero code on such zip files unless -: is - # passed. - unzip -:o dist.zip - -step-mksnapshot-unzip: &step-mksnapshot-unzip - run: - name: Unzip mksnapshot.zip - command: | - cd src/out/Default - unzip -:o mksnapshot.zip - -step-chromedriver-unzip: &step-chromedriver-unzip - run: - name: Unzip chromedriver.zip - command: | - cd src/out/Default - unzip -:o chromedriver.zip - -step-ffmpeg-gn-gen: &step-ffmpeg-gn-gen - run: - name: ffmpeg GN gen - command: | - cd src - gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS" - -step-ffmpeg-build: &step-ffmpeg-build - run: - name: Non proprietary ffmpeg build - command: | - cd src - ninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES - -step-verify-mksnapshot: &step-verify-mksnapshot - run: - name: Verify mksnapshot - command: | - if [ "$IS_ASAN" != "1" ]; then - cd src - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots - else - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default - fi - fi - -step-verify-chromedriver: &step-verify-chromedriver - run: - name: Verify ChromeDriver - command: | - if [ "$IS_ASAN" != "1" ]; then - cd src - python electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default - fi - -step-setup-linux-for-headless-testing: &step-setup-linux-for-headless-testing - run: - name: Setup for headless testing - command: | - if [ "`uname`" != "Darwin" ]; then - sh -e /etc/init.d/xvfb start - fi - -step-show-goma-stats: &step-show-goma-stats - run: - shell: /bin/bash - name: Check goma stats after build - command: | - set +e - set +o pipefail - $LOCAL_GOMA_DIR/goma_ctl.py stat - $LOCAL_GOMA_DIR/diagnose_goma_log.py - true - when: always - background: true - -step-mksnapshot-build: &step-mksnapshot-build - run: - name: mksnapshot build - no_output_timeout: 30m - command: | - cd src - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" != "1" ]; then - ninja -C out/Default electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - fi - if [ "`uname`" != "Darwin" ]; then - if [ "$TARGET_ARCH" == "arm" ]; then - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator - elif [ "$TARGET_ARCH" == "arm64" ]; then - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator - else - electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator - fi - fi - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" != "1" ] && [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES - (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S) - fi - -step-hunspell-build: &step-hunspell-build - run: - name: hunspell build - command: | - cd src - if [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES - fi - -step-maybe-generate-libcxx: &step-maybe-generate-libcxx - run: - name: maybe generate libcxx - command: | - cd src - if [ "`uname`" == "Linux" ]; then - ninja -C out/Default electron:libcxx_headers_zip -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default electron:libcxxabi_headers_zip -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default electron:libcxx_objects_zip -j $NUMBER_OF_NINJA_PROCESSES - fi - -step-maybe-generate-breakpad-symbols: &step-maybe-generate-breakpad-symbols - run: - name: Generate breakpad symbols - no_output_timeout: 30m - command: | - if [ "$GENERATE_SYMBOLS" == "true" ]; then - cd src - ninja -C out/Default electron:electron_symbols - fi - -step-maybe-zip-symbols: &step-maybe-zip-symbols - run: - name: Zip symbols - command: | - cd src - export BUILD_PATH="$PWD/out/Default" - ninja -C out/Default electron:licenses - ninja -C out/Default electron:electron_version - DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH - -step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot - run: - name: Generate cross arch snapshot (arm/arm64) - command: | - if [ "$GENERATE_CROSS_ARCH_SNAPSHOT" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then - cd src - if [ "$TARGET_ARCH" == "arm" ]; then - export MKSNAPSHOT_PATH="clang_x86_v8_arm" - elif [ "$TARGET_ARCH" == "arm64" ]; then - export MKSNAPSHOT_PATH="clang_x64_v8_arm64" - fi - cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default - cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default - if [ "`uname`" == "Linux" ]; then - cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default - elif [ "`uname`" == "Darwin" ]; then - cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.dylib" out/Default - fi - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only - mkdir cross-arch-snapshots - cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots - fi - -step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs - run: - name: Generate type declarations - command: | - if [ "`uname`" == "Darwin" ]; then - cd src/electron - node script/yarn create-typescript-definitions - fi - -step-fix-known-hosts-linux: &step-fix-known-hosts-linux - run: - name: Fix Known Hosts on Linux - command: | - if [ "`uname`" == "Linux" ]; then - ./src/electron/.circleci/fix-known-hosts.sh - fi - -# Checkout Steps -step-generate-deps-hash: &step-generate-deps-hash - run: - name: Generate DEPS Hash - command: node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target - -step-touch-sync-done: &step-touch-sync-done - run: - name: Touch Sync Done - command: touch src/electron/.circle-sync-done - -# Restore exact src cache based on the hash of DEPS and patches/* -# If no cache is matched EXACTLY then the .circle-sync-done file is empty -# If a cache is matched EXACTLY then the .circle-sync-done file contains "done" -step-maybe-restore-src-cache: &step-maybe-restore-src-cache - restore_cache: - keys: - - v14-src-cache-{{ checksum "src/electron/.depshash" }} - name: Restoring src cache -step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker - restore_cache: - keys: - - v14-src-cache-marker-{{ checksum "src/electron/.depshash" }} - name: Restoring src cache marker - -# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done -# If the src cache was restored above then this will match an empty cache -# If the src cache was not restored above then this will match a close git cache -step-maybe-restore-git-cache: &step-maybe-restore-git-cache - restore_cache: - paths: - - git-cache - keys: - - v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }} - - v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }} - name: Conditionally restoring git cache - -step-restore-out-cache: &step-restore-out-cache - restore_cache: - paths: - - ./src/out/Default - keys: - - v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Restoring out cache - -step-set-git-cache-path: &step-set-git-cache-path - run: - name: Set GIT_CACHE_PATH to make gclient to use the cache - command: | - # CircleCI does not support interpolation when setting environment variables. - # https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command - echo 'export GIT_CACHE_PATH="$PWD/git-cache"' >> $BASH_ENV - -# Persist the git cache based on the hash of DEPS and .circle-sync-done -# If the src cache was restored above then this will persist an empty cache -step-save-git-cache: &step-save-git-cache - save_cache: - paths: - - git-cache - key: v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }} - name: Persisting git cache - -step-save-out-cache: &step-save-out-cache - save_cache: - paths: - - ./src/out/Default - key: v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Persisting out cache - -step-run-electron-only-hooks: &step-run-electron-only-hooks - run: - name: Run Electron Only Hooks - command: gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" - -step-generate-deps-hash-cleanly: &step-generate-deps-hash-cleanly - run: - name: Generate DEPS Hash - command: (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target - -# Mark the sync as done for future cache saving -step-mark-sync-done: &step-mark-sync-done - run: - name: Mark Sync Done - command: echo DONE > src/electron/.circle-sync-done - -# Minimize the size of the cache -step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-checkout - run: - name: Remove some unused data to avoid storing it in the workspace/cache - command: | - rm -rf src/android_webview - rm -rf src/ios/chrome - rm -rf src/third_party/blink/web_tests - rm -rf src/third_party/blink/perf_tests - rm -rf src/third_party/WebKit/LayoutTests - rm -rf third_party/electron_node/deps/openssl - rm -rf third_party/electron_node/deps/v8 - rm -rf chrome/test/data/xr/webvr_info - -# Save the src cache based on the deps hash -step-save-src-cache: &step-save-src-cache - save_cache: - paths: - - /var/portal - key: v14-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }} - name: Persisting src cache -step-make-src-cache-marker: &step-make-src-cache-marker - run: - name: Making src cache marker - command: touch .src-cache-marker -step-save-src-cache-marker: &step-save-src-cache-marker - save_cache: - paths: - - .src-cache-marker - key: v14-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }} - -step-maybe-early-exit-no-doc-change: &step-maybe-early-exit-no-doc-change - run: - name: Shortcircuit job if change is not doc only - command: | - if [ ! -s src/electron/.skip-ci-build ]; then - circleci-agent step halt - fi - -step-ts-compile: &step-ts-compile - run: - name: Run TS/JS compile on doc only change - command: | - cd src/electron - node script/yarn create-typescript-definitions - node script/yarn tsc -p tsconfig.default_app.json --noEmit - for f in build/webpack/*.js - do - out="${f:29}" - if [ "$out" != "base.js" ]; then - node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development - fi - done - -# List of all steps. -steps-electron-gn-check: &steps-electron-gn-check - steps: - - *step-checkout-electron - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - install-python2-mac - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-generate-deps-hash - - *step-touch-sync-done - - maybe-restore-portaled-src-cache - - run: - name: Ensure src checkout worked - command: | - if [ ! -d "src/third_party/blink" ]; then - echo src cache was not restored for an unknown reason - exit 1 - fi - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - -steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-change - steps: - # Checkout - Copied from steps-checkout - - *step-checkout-electron - - *step-install-npm-deps - - #Compile ts/js to verify doc change didn't break anything - - *step-ts-compile - -steps-tests: &steps-tests - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-mksnapshot-unzip - - *step-chromedriver-unzip - - *step-setup-linux-for-headless-testing - - *step-restore-brew-cache - - *step-fix-known-hosts-linux - - install-python2-mac - - *step-install-signing-cert-on-mac - - - run: - name: Run Electron tests - environment: - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap - ELECTRON_DISABLE_SECURITY_WARNINGS: 1 - command: | - cd src - if [ "$IS_ASAN" == "1" ]; then - ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron" - export ASAN_OPTIONS="symbolize=0 handle_abort=1" - export G_SLICE=always-malloc - export NSS_DISABLE_ARENA_FREE_LIST=1 - export NSS_DISABLE_UNLOAD=1 - export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer - export MOCHA_TIMEOUT=180000 - echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)" - (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split --split-by=timings)) 2>&1 | $ASAN_SYMBOLIZE - (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split --split-by=timings)) 2>&1 | $ASAN_SYMBOLIZE - else - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true - (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging) - (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging) - else - if [ "$TARGET_ARCH" == "ia32" ]; then - npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js - fi - (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split --split-by=timings)) - (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split --split-by=timings)) - fi - fi - - run: - name: Check test results existence - command: | - cd src - - # Check if test results exist and are not empty. - if [ ! -s "junit/test-results-remote.xml" ]; then - exit 1 - fi - if [ ! -s "junit/test-results-main.xml" ]; then - exit 1 - fi - - store_test_results: - path: src/junit - - - *step-verify-mksnapshot - - *step-verify-chromedriver - - - *step-maybe-notify-slack-failure - - - *step-maybe-cleanup-arm64-mac - -steps-test-nan: &steps-test-nan - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-setup-linux-for-headless-testing - - *step-fix-known-hosts-linux - - run: - name: Run Nan Tests - command: | - cd src - node electron/script/nan-spec-runner.js - -steps-test-node: &steps-test-node - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-setup-linux-for-headless-testing - - *step-fix-known-hosts-linux - - run: - name: Run Node Tests - command: | - cd src - node electron/script/node-spec-runner.js --default --jUnitDir=junit - - store_test_results: - path: src/junit - -# Command Aliases -commands: - install-python2-mac: - steps: - - restore_cache: - keys: - - v2.7.18-python-cache-{{ arch }} - name: Restore python cache - - run: - name: Install python2 on macos - command: | - if [ "`uname`" == "Darwin" ] && [ "$IS_ELECTRON_RUNNER" != "1" ]; then - if [ ! -f "python-downloads/python-2.7.18-macosx10.9.pkg" ]; then - mkdir python-downloads - echo 'Downloading Python 2.7.18' - curl -O https://dev-cdn.electronjs.org/python/python-2.7.18-macosx10.9.pkg - mv python-2.7.18-macosx10.9.pkg python-downloads - else - echo 'Using Python install from cache' - fi - sudo installer -pkg python-downloads/python-2.7.18-macosx10.9.pkg -target / - fi - - save_cache: - paths: - - python-downloads - key: v2.7.18-python-cache-{{ arch }} - name: Persisting python cache - maybe-restore-portaled-src-cache: - parameters: - halt-if-successful: - type: boolean - default: false - steps: - - run: - name: Prepare for cross-OS sync restore - command: | - sudo mkdir -p /var/portal - sudo chown -R $(id -u):$(id -g) /var/portal - - when: - condition: << parameters.halt-if-successful >> - steps: - - *step-maybe-restore-src-cache-marker - - run: - name: Halt the job early if the src cache exists - command: | - if [ -f ".src-cache-marker" ]; then - circleci-agent step halt - fi - - *step-maybe-restore-src-cache - - run: - name: Fix the src cache restore point on macOS - command: | - if [ -d "/var/portal/src" ]; then - echo Relocating Cache - rm -rf src - mv /var/portal/src ./ - fi - - move_and_store_all_artifacts: - steps: - - run: - name: Move all generated artifacts to upload folder - command: | - rm -rf generated_artifacts - mkdir generated_artifacts - mv_if_exist() { - if [ -f "$1" ] || [ -d "$1" ]; then - echo Storing $1 - mv $1 generated_artifacts - else - echo Skipping $1 - It is not present on disk - fi - } - mv_if_exist src/out/Default/dist.zip - mv_if_exist src/out/Default/gen/node_headers.tar.gz - mv_if_exist src/out/Default/symbols.zip - mv_if_exist src/out/Default/mksnapshot.zip - mv_if_exist src/out/Default/chromedriver.zip - mv_if_exist src/out/ffmpeg/ffmpeg.zip - mv_if_exist src/out/Default/hunspell_dictionaries.zip - mv_if_exist src/cross-arch-snapshots - mv_if_exist src/out/electron_ninja_log - mv_if_exist src/out/Default/.ninja_log - when: always - - store_artifacts: - path: generated_artifacts - destination: ./ - - store_artifacts: - path: generated_artifacts/cross-arch-snapshots - destination: cross-arch-snapshots - - checkout-from-cache: - steps: - - *step-checkout-electron - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-generate-deps-hash - - maybe-restore-portaled-src-cache - - run: - name: Ensure src checkout worked - command: | - if [ ! -d "src/third_party/blink" ]; then - echo src cache was not restored for some reason, idk what happened here... - exit 1 - fi - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - - step-electron-dist-build: - parameters: - additional-targets: - type: string - default: '' - steps: - - run: - name: Build dist.zip - command: | - cd src - if [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:electron_dist_zip << parameters.additional-targets >> - if [ "$CHECK_DIST_MANIFEST" == "1" ]; then - if [ "`uname`" == "Darwin" ]; then - target_os=mac - target_cpu=x64 - if [ x"$MAS_BUILD" == x"true" ]; then - target_os=mac_mas - fi - if [ "$TARGET_ARCH" == "arm64" ]; then - target_cpu=arm64 - fi - elif [ "`uname`" == "Linux" ]; then - target_os=linux - if [ x"$TARGET_ARCH" == x ]; then - target_cpu=x64 - else - target_cpu="$TARGET_ARCH" - fi - else - echo "Unknown system: `uname`" - exit 1 - fi - electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.$target_cpu.manifest - fi - fi - - electron-build: - parameters: - attach: - type: boolean - default: false - persist: - type: boolean - default: true - persist-checkout: - type: boolean - default: false - checkout: - type: boolean - default: true - checkout-and-assume-cache: - type: boolean - default: false - save-git-cache: - type: boolean - default: false - checkout-to-create-src-cache: - type: boolean - default: false - build: - type: boolean - default: true - use-out-cache: - type: boolean - default: true - restore-src-cache: - type: boolean - default: true - build-nonproprietary-ffmpeg: - type: boolean - default: true - steps: - - when: - condition: << parameters.attach >> - steps: - - attach_workspace: - at: . - - run: rm -rf src/electron - - *step-restore-brew-cache - - *step-install-gnutar-on-mac - - install-python2-mac - - *step-save-brew-cache - - when: - condition: << parameters.build >> - steps: - - *step-setup-goma-for-build - - when: - condition: << parameters.checkout-and-assume-cache >> - steps: - - checkout-from-cache - - when: - condition: << parameters.checkout >> - steps: - # Checkout - Copied from steps-checkout - - *step-checkout-electron - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-get-more-space-on-mac - - *step-generate-deps-hash - - *step-touch-sync-done - - when: - condition: << parameters.restore-src-cache >> - steps: - - maybe-restore-portaled-src-cache: - halt-if-successful: << parameters.checkout-to-create-src-cache >> - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - # This sync call only runs if .circle-sync-done is an EMPTY file - - *step-gclient-sync - - store_artifacts: - path: patches - # These next few steps reset Electron to the correct commit regardless of which cache was restored - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - - *step-touch-sync-done - - when: - condition: << parameters.save-git-cache >> - steps: - - *step-save-git-cache - # Mark sync as done _after_ saving the git cache so that it is uploaded - # only when the src cache was not present - # Their are theoretically two cases for this cache key - # 1. `vX-git-cache-DONE-{deps_hash} - # 2. `vX-git-cache-EMPTY-{deps_hash} - # - # Case (1) occurs when the flag file has "DONE" in it - # which only occurs when "step-mark-sync-done" is run - # or when the src cache was restored successfully as that - # flag file contains "DONE" in the src cache. - # - # Case (2) occurs when the flag file is empty, this occurs - # when the src cache was not restored and "step-mark-sync-done" - # has not run yet. - # - # Notably both of these cases also have completely different - # gclient cache states. - # In (1) the git cache is completely empty as we didn't run - # "gclient sync" because the src cache was restored. - # In (2) the git cache is full as we had to run "gclient sync" - # - # This allows us to do make the follow transitive assumption: - # In cases where the src cache is restored, saving the git cache - # will save an empty cache. In cases where the src cache is built - # during this build the git cache will save a full cache. - # - # In order words if there is a src cache for a given DEPS hash - # the git cache restored will be empty. But if the src cache - # is missing we will restore a useful git cache. - - *step-mark-sync-done - - *step-minimize-workspace-size-from-checkout - - *step-delete-git-directories - - when: - condition: << parameters.persist-checkout >> - steps: - - persist_to_workspace: - root: . - paths: - - depot_tools - - src - - when: - condition: << parameters.checkout-to-create-src-cache >> - steps: - - run: - name: Move src folder to the cross-OS portal - command: | - sudo mkdir -p /var/portal - sudo chown -R $(id -u):$(id -g) /var/portal - mv ./src /var/portal - - *step-save-src-cache - - *step-make-src-cache-marker - - *step-save-src-cache-marker - - - when: - condition: << parameters.build >> - steps: - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-wait-for-goma - - *step-get-more-space-on-mac - - *step-fix-sync - - *step-delete-git-directories - - # Electron app - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-restore-out-cache - - *step-gn-gen-default - - *step-electron-build - - *step-maybe-electron-dist-strip - - step-electron-dist-build: - additional-targets: shell_browser_ui_unittests third_party/electron_node:headers third_party/electron_node:overlapped-checker electron:hunspell_dictionaries_zip - - - *step-show-goma-stats - - # mksnapshot - - *step-mksnapshot-build - - *step-maybe-cross-arch-snapshot - - # chromedriver - - *step-electron-chromedriver-build - - - when: - condition: << parameters.build-nonproprietary-ffmpeg >> - steps: - # ffmpeg - - *step-ffmpeg-gn-gen - - *step-ffmpeg-build - - # Save all data needed for a further tests run. - - when: - condition: << parameters.persist >> - steps: - - *step-minimize-workspace-size-from-checkout - - run: | - rm -rf src/third_party/electron_node/deps/openssl - rm -rf src/third_party/electron_node/deps/v8 - - *step-persist-data-for-tests - - - when: - condition: << parameters.build >> - steps: - - *step-maybe-generate-breakpad-symbols - - *step-maybe-zip-symbols - - - when: - condition: << parameters.build >> - steps: - - move_and_store_all_artifacts - - run: - name: Remove the big things on macOS, this seems to be better on average - command: | - if [ "`uname`" == "Darwin" ]; then - mkdir -p src/out/Default - cd src/out/Default - find . -type f -size +50M -delete - mkdir -p gen/electron - cd gen/electron - # These files do not seem to like being in a cache, let us remove them - find . -type f -name '*_pkg_info' -delete - fi - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-save-out-cache - - - *step-maybe-notify-slack-failure - - electron-publish: - parameters: - attach: - type: boolean - default: false - checkout: - type: boolean - default: true - steps: - - when: - condition: << parameters.attach >> - steps: - - attach_workspace: - at: . - - when: - condition: << parameters.checkout >> - steps: - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-restore-brew-cache - - install-python2-mac - - *step-get-more-space-on-mac - - when: - condition: << parameters.checkout >> - steps: - - *step-checkout-electron - - *step-touch-sync-done - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - - *step-gclient-sync - - *step-delete-git-directories - - *step-minimize-workspace-size-from-checkout - - *step-fix-sync - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-wait-for-goma - - *step-gn-gen-default - - # Electron app - - *step-electron-build - - *step-show-goma-stats - - *step-maybe-generate-breakpad-symbols - - *step-maybe-electron-dist-strip - - step-electron-dist-build - - *step-maybe-zip-symbols - - # mksnapshot - - *step-mksnapshot-build - - # chromedriver - - *step-electron-chromedriver-build - - # Node.js headers - - *step-nodejs-headers-build - - # ffmpeg - - *step-ffmpeg-gn-gen - - *step-ffmpeg-build - - # hunspell - - *step-hunspell-build - - # libcxx - - *step-maybe-generate-libcxx - - # typescript defs - - *step-maybe-generate-typescript-defs - - # Publish - - *step-electron-publish - - move_and_store_all_artifacts - -# List of all jobs. -jobs: - # Layer 0: Docs. Standalone. - ts-compile-doc-change: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - <<: *steps-electron-ts-compile-for-doc-change - - # Layer 1: Checkout. - linux-make-src-cache: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - save-git-cache: true - checkout-to-create-src-cache: true - - mac-checkout: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - restore-src-cache: false - - mac-make-src-cache: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: false - build: false - checkout: true - save-git-cache: true - checkout-to-create-src-cache: true - - # Layer 2: Builds. - linux-x64-testing: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-global - <<: *env-testing-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - use-out-cache: false - - linux-x64-testing-asan: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-global - <<: *env-testing-build - <<: *env-ninja-status - CHECK_DIST_MANIFEST: '0' - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - GN_EXTRA_ARGS: 'is_asan = true' - steps: - - electron-build: - persist: true - checkout: true - use-out-cache: false - build-nonproprietary-ffmpeg: false - - linux-x64-testing-no-run-as-node: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-disable-run-as-node - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - use-out-cache: false - - linux-x64-testing-gn-check: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-testing-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - <<: *steps-electron-gn-check - - linux-x64-publish: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-release-build - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.linux-publish-arch-limit >>] - - equal: ["x64", << pipeline.parameters.linux-publish-arch-limit >>] - steps: - - electron-publish: - attach: false - checkout: true - - - linux-arm-testing: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-global - <<: *env-arm - <<: *env-testing-build - <<: *env-ninja-status - TRIGGER_ARM_TEST: true - GENERATE_CROSS_ARCH_SNAPSHOT: true - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - use-out-cache: false - - linux-arm-publish: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm - <<: *env-release-build - <<: *env-32bit-release - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True' - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.linux-publish-arch-limit >>] - - equal: ["arm", << pipeline.parameters.linux-publish-arch-limit >>] - steps: - - electron-publish: - attach: false - checkout: true - - linux-arm64-testing: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-global - <<: *env-arm64 - <<: *env-testing-build - <<: *env-ninja-status - TRIGGER_ARM_TEST: true - GENERATE_CROSS_ARCH_SNAPSHOT: true - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - use-out-cache: false - - linux-arm64-testing-gn-check: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-arm64 - <<: *env-testing-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - <<: *steps-electron-gn-check - - linux-arm64-publish: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm64 - <<: *env-release-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True' - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.linux-publish-arch-limit >>] - - equal: ["arm64", << pipeline.parameters.linux-publish-arch-limit >>] - steps: - - electron-publish: - attach: false - checkout: true - - osx-testing-x64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: true - - osx-testing-x64-gn-check: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-machine-mac - <<: *env-testing-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - <<: *steps-electron-gn-check - - osx-publish-x64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large-release - <<: *env-release-build - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>] - - equal: ["osx-x64", << pipeline.parameters.macos-publish-arch-limit >>] - steps: - - electron-publish: - attach: true - checkout: false - - osx-publish-arm64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large-release - <<: *env-release-build - <<: *env-apple-silicon - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>] - - equal: ["osx-arm64", << pipeline.parameters.macos-publish-arch-limit >>] - steps: - - electron-publish: - attach: true - checkout: false - - osx-testing-arm64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - <<: *env-apple-silicon - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - GENERATE_CROSS_ARCH_SNAPSHOT: true - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: true - - mas-testing-x64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-mas - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: true - - mas-testing-x64-gn-check: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-machine-mac - <<: *env-mas - <<: *env-testing-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - <<: *steps-electron-gn-check - - mas-publish-x64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large-release - <<: *env-mas - <<: *env-release-build - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>] - - equal: ["mas-x64", << pipeline.parameters.macos-publish-arch-limit >>] - steps: - - electron-publish: - attach: true - checkout: false - - mas-publish-arm64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large-release - <<: *env-mas-apple-silicon - <<: *env-release-build - UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>] - - equal: ["mas-arm64", << pipeline.parameters.macos-publish-arch-limit >>] - steps: - - electron-publish: - attach: true - checkout: false - - mas-testing-arm64: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - <<: *env-mas-apple-silicon - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - GENERATE_CROSS_ARCH_SNAPSHOT: true - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: true - - # Layer 3: Tests. - linux-x64-testing-tests: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - parallelism: 3 - <<: *steps-tests - - linux-x64-testing-asan-tests: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - IS_ASAN: '1' - DISABLE_CRASH_REPORTER_TESTS: '1' - parallelism: 3 - <<: *steps-tests - - linux-x64-testing-nan: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-nan - - linux-x64-testing-node: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-node - - linux-arm-testing-tests: - executor: linux-arm - environment: - <<: *env-arm - <<: *env-global - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-tests - - linux-arm64-testing-tests: - executor: linux-arm64 - environment: - <<: *env-arm64 - <<: *env-global - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-tests - - osx-testing-x64-tests: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-stack-dumping - parallelism: 2 - <<: *steps-tests - - osx-testing-arm64-tests: - executor: apple-silicon - environment: - <<: *env-mac-large - <<: *env-stack-dumping - <<: *env-apple-silicon - <<: *env-runner - <<: *steps-tests - - mas-testing-x64-tests: - executor: - name: macos - size: macos.x86.medium.gen2 - environment: - <<: *env-mac-large - <<: *env-stack-dumping - parallelism: 2 - <<: *steps-tests - - mas-testing-arm64-tests: - executor: apple-silicon - environment: - <<: *env-mac-large - <<: *env-stack-dumping - <<: *env-apple-silicon - <<: *env-runner - <<: *steps-tests - -# List all workflows -workflows: - docs-only: - when: - and: - - equal: [false, << pipeline.parameters.run-macos-publish >>] - - equal: [false, << pipeline.parameters.run-linux-publish >>] - - equal: [true, << pipeline.parameters.run-docs-only >>] - jobs: - - ts-compile-doc-change - - publish-linux: - when: << pipeline.parameters.run-linux-publish >> - jobs: - - linux-x64-publish: - context: release-env - - linux-arm-publish: - context: release-env - - linux-arm64-publish: - context: release-env - - publish-macos: - when: << pipeline.parameters.run-macos-publish >> - jobs: - - mac-checkout - - osx-publish-x64: - requires: - - mac-checkout - context: release-env - - mas-publish-x64: - requires: - - mac-checkout - context: release-env - - osx-publish-arm64: - requires: - - mac-checkout - context: release-env - - mas-publish-arm64: - requires: - - mac-checkout - context: release-env - - build-linux: - when: - and: - - equal: [false, << pipeline.parameters.run-macos-publish >>] - - equal: [false, << pipeline.parameters.run-linux-publish >>] - - equal: [true, << pipeline.parameters.run-build-linux >>] - jobs: - - linux-make-src-cache - - linux-x64-testing: - requires: - - linux-make-src-cache - - linux-x64-testing-asan: - requires: - - linux-make-src-cache - - linux-x64-testing-no-run-as-node: - requires: - - linux-make-src-cache - - linux-x64-testing-gn-check: - requires: - - linux-make-src-cache - - linux-x64-testing-tests: - requires: - - linux-x64-testing - - linux-x64-testing-asan-tests: - requires: - - linux-x64-testing-asan - - linux-x64-testing-nan: - requires: - - linux-x64-testing - - linux-x64-testing-node: - requires: - - linux-x64-testing - - linux-arm-testing: - requires: - - linux-make-src-cache - - linux-arm-testing-tests: - filters: - branches: - # Do not run this on forked pull requests - ignore: /pull\/[0-9]+/ - requires: - - linux-arm-testing - - linux-arm64-testing: - requires: - - linux-make-src-cache - - linux-arm64-testing-tests: - filters: - branches: - # Do not run this on forked pull requests - ignore: /pull\/[0-9]+/ - requires: - - linux-arm64-testing - - linux-arm64-testing-gn-check: - requires: - - linux-make-src-cache - - build-mac: - when: - and: - - equal: [false, << pipeline.parameters.run-macos-publish >>] - - equal: [false, << pipeline.parameters.run-linux-publish >>] - - equal: [true, << pipeline.parameters.run-build-mac >>] - jobs: - - mac-make-src-cache - - osx-testing-x64: - requires: - - mac-make-src-cache - - osx-testing-x64-gn-check: - requires: - - mac-make-src-cache - - osx-testing-x64-tests: - requires: - - osx-testing-x64 - - osx-testing-arm64: - requires: - - mac-make-src-cache - - osx-testing-arm64-tests: - filters: - branches: - # Do not run this on forked pull requests - ignore: /pull\/[0-9]+/ - requires: - - osx-testing-arm64 - - mas-testing-x64: - requires: - - mac-make-src-cache - - mas-testing-x64-gn-check: - requires: - - mac-make-src-cache - - mas-testing-x64-tests: - requires: - - mas-testing-x64 - - mas-testing-arm64: - requires: - - mac-make-src-cache - - mas-testing-arm64-tests: - filters: - branches: - # Do not run this on forked pull requests - ignore: /pull\/[0-9]+/ - requires: - - mas-testing-arm64 - lint: - jobs: - - lint diff --git a/.circleci/config/build.js b/.circleci/config/build.js deleted file mode 100644 index 4e255608a0905..0000000000000 --- a/.circleci/config/build.js +++ /dev/null @@ -1,34 +0,0 @@ -const cp = require('child_process'); -const fs = require('fs-extra'); -const path = require('path'); -const yaml = require('js-yaml'); - -const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging'); - -function copyAndExpand(dir = './') { - const absDir = path.resolve(__dirname, dir); - const targetDir = path.resolve(STAGING_DIR, dir); - - if (!fs.existsSync(targetDir)) { - fs.mkdirSync(targetDir); - } - - for (const file of fs.readdirSync(absDir)) { - if (!file.endsWith('.yml')) { - if (fs.statSync(path.resolve(absDir, file)).isDirectory()) { - copyAndExpand(path.join(dir, file)); - } - continue; - } - - fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), { - noRefs: true, - })); - } -} - -if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR); -copyAndExpand(); - -const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]); -fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString()); diff --git a/.circleci/config/jobs/lint.yml b/.circleci/config/jobs/lint.yml deleted file mode 100644 index 2137566547120..0000000000000 --- a/.circleci/config/jobs/lint.yml +++ /dev/null @@ -1,51 +0,0 @@ -executor: - name: linux-docker - size: medium -steps: - - checkout: - path: src/electron - - run: - name: Setup third_party Depot Tools - command: | - # "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file. - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools - echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV - - run: - name: Download GN Binary - command: | - chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" - gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)" - - cipd ensure -ensure-file - -root . \<<-CIPD - \$ServiceURL https://chrome-infra-packages.appspot.com/ - @Subdir src/buildtools/linux64 - gn/gn/linux-amd64 $gn_version - CIPD - - echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV - - run: - name: Download clang-format Binary - command: | - chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" - - sha1_path='buildtools/linux64/clang-format.sha1' - curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}" - - download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}" - - run: - name: Run Lint - command: | - # gn.py tries to find a gclient root folder starting from the current dir. - # When it fails and returns "None" path, the whole script fails. Let's "fix" it. - touch .gclient - # Another option would be to checkout "buildtools" inside the Electron checkout, - # but then we would lint its contents (at least gn format), and it doesn't pass it. - - cd src/electron - node script/yarn install --frozen-lockfile - node script/yarn lint - - run: - name: Run Script Typechecker - command: | - cd src/electron - node script/yarn tsc -p tsconfig.script.json diff --git a/.circleci/config/package.json b/.circleci/config/package.json deleted file mode 100644 index 054dd7c11cc9e..0000000000000 --- a/.circleci/config/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@electron/circleci-config", - "version": "0.0.0", - "private": true, - "license": "MIT", - "dependencies": { - "fs-extra": "^10.1.0", - "js-yaml": "^4.1.0" - } -} diff --git a/.circleci/config/yarn.lock b/.circleci/config/yarn.lock deleted file mode 100644 index 51b2d9877643f..0000000000000 --- a/.circleci/config/yarn.lock +++ /dev/null @@ -1,43 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -fs-extra@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== diff --git a/.circleci/fix-known-hosts.sh b/.circleci/fix-known-hosts.sh deleted file mode 100755 index d6d36e791ad5e..0000000000000 --- a/.circleci/fix-known-hosts.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -mkdir -p ~/.ssh -echo "|1|B3r+7aO0/x90IdefihIjxIoJrrk=|OJddGDfhbuLFc1bUyy84hhIw57M= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== -|1|rGlEvW55DtzNZp+pzw9gvyOyKi4=|LLWr+7qlkAlw3YGGVfLHHxB/kR0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000000..6fb5e40a261ff --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,4 @@ +--- +Checks: '-modernize-use-nullptr' +InheritParentConfig: true +... diff --git a/.devcontainer/README.md b/.devcontainer/README.md index c12625a1481e8..9cfac3588531b 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -4,14 +4,13 @@ Welcome to the Codespaces Electron Developer Environment. ## Quick Start -Upon creation of your codespace you should have [build tools](https://github.com/electron/build-tools) installed and an initialized gclient checkout of Electron. In order to build electron you'll need to run the following commands. +Upon creation of your codespace you should have [build tools](https://github.com/electron/build-tools) installed and an initialized gclient checkout of Electron. In order to build electron you'll need to run the following command. ```bash -e sync -vv e build ``` -The initial sync will take approximately ~30 minutes and the build will take ~8 minutes. Incremental syncs and incremental builds are substantially quicker. +The initial build will take ~8 minutes. Incremental builds are substantially quicker. If you pull changes from upstream that touch either the `patches` folder or the `DEPS` folder you will have to run `e sync` in order to keep your checkout up to date. ## Directory Structure @@ -26,9 +25,19 @@ Codespaces doesn't lean very well into gclient based checkouts, the directory st /workspaces/electron ``` -## Goma +## Reclient -If you are a maintainer [with Goma access](../docs/development/goma.md) it should be automatically configured and authenticated when you spin up a new codespaces instance. You can validate this by checking `e d goma_auth info` or by checking that your build-tools configuration has a goma mode of `cluster`. +If you are a maintainer [with Reclient access](../docs/development/reclient.md) you'll need to ensure you're authenticated when you spin up a new codespaces instance. You can validate this by checking `e d rbe info` - your build-tools configuration should have `Access` type `Cache & Execute`: + +```console +Authentication Status: Authenticated +Since: 2024-05-28 10:29:33 +0200 CEST +Expires: 2024-08-26 10:29:33 +0200 CEST +... +Access: Cache & Execute +``` + +To authenticate if you're not logged in, run `e d rbe login` and follow the link to authenticate. ## Running Electron diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5c800028282d8..d7049d37919b7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,30 +2,10 @@ "dockerComposeFile": "docker-compose.yml", "service": "buildtools", "onCreateCommand": ".devcontainer/on-create-command.sh", + "updateContentCommand": ".devcontainer/update-content-command.sh", "workspaceFolder": "/workspaces/gclient/src/electron", - "extensions": [ - "joeleinbinder.mojom-language", - "rafaelmaiolla.diff", - "surajbarkale.ninja", - "ms-vscode.cpptools", - "mutantdino.resourcemonitor", - "dbaeumer.vscode-eslint", - "shakram02.bash-beautify", - "marshallofsound.gnls-electron" - ], - "settings": { - "[gn]": { - "editor.formatOnSave": true - }, - "editor.tabSize": 2, - "bashBeautify.tabSize": 2 - }, - "forwardPorts": [8088, 6080, 5901], + "forwardPorts": [6080, 5901], "portsAttributes": { - "8088": { - "label": "Goma Control Panel", - "onAutoForward": "silent" - }, "6080": { "label": "VNC web client (noVNC)", "onAutoForward": "silent" @@ -36,8 +16,47 @@ } }, "hostRequirements": { - "storage": "32gb", - "cpus": 8 + "storage": "128gb", + "cpus": 16 }, - "remoteUser": "builduser" + "remoteUser": "builduser", + "customizations": { + "codespaces": { + "openFiles": [ + ".devcontainer/README.md" + ] + }, + "vscode": { + "extensions": [ + "joeleinbinder.mojom-language", + "rafaelmaiolla.diff", + "surajbarkale.ninja", + "ms-vscode.cpptools", + "mutantdino.resourcemonitor", + "dbaeumer.vscode-eslint", + "shakram02.bash-beautify", + "marshallofsound.gnls-electron", + ], + "settings": { + "editor.tabSize": 2, + "bashBeautify.tabSize": 2, + "typescript.tsdk": "node_modules/typescript/lib", + "[gn]": { + "editor.formatOnSave": true + }, + "[javascript]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } + }, + "[typescript]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } + }, + "javascript.preferences.quoteStyle": "single", + "typescript.preferences.quoteStyle": "single" + } + } + } } \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 794577745512d..f867f0eb621a4 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -2,14 +2,14 @@ version: '3' services: buildtools: - image: ghcr.io/electron/devcontainer:27db4a3e3512bfd2e47f58cea69922da0835f1d9 + image: ghcr.io/electron/devcontainer:77262e58c37631ab082482f42c33cdf68c6c394b volumes: - ..:/workspaces/gclient/src/electron:cached - - /var/run/docker.sock:/var/run/docker.sock + - /var/run/docker.sock:/var/run/docker.sock - command: /bin/sh -c "while sleep 1000; do :; done" + command: /bin/sh -c "while sleep 1000; do :; done" user: builduser diff --git a/.devcontainer/on-create-command.sh b/.devcontainer/on-create-command.sh index 8899906dff20e..b6a9318d97607 100755 --- a/.devcontainer/on-create-command.sh +++ b/.devcontainer/on-create-command.sh @@ -10,11 +10,14 @@ export PATH="$PATH:$buildtools/src" # Create the persisted buildtools config folder mkdir -p $buildtools_configs +mkdir -p $gclient_root/.git-cache rm -f $buildtools/configs ln -s $buildtools_configs $buildtools/configs # Write the gclient config if it does not already exist if [ ! -f $gclient_root/.gclient ]; then + echo "Creating gclient config" + echo "solutions = [ { \"name\" : \"src/electron\", \"url\" : \"https://github.com/electron/electron\", @@ -31,15 +34,21 @@ fi # Write the default buildtools config file if it does # not already exist if [ ! -f $buildtools/configs/evm.testing.json ]; then + echo "Creating build-tools testing config" + write_config() { echo " { \"root\": \"/workspaces/gclient\", - \"goma\": \"$1\", + \"remotes\": { + \"electron\": { + \"origin\": \"https://github.com/electron/electron.git\" + } + }, \"gen\": { \"args\": [ \"import(\\\"//electron/build/args/testing.gn\\\")\", - \"import(\\\"/home/builduser/.electron_build_tools/third_party/goma.gn\\\")\" + \"use_remoteexec = true\" ], \"out\": \"Testing\" }, @@ -47,28 +56,17 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then \"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\", \"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\" }, - \"remotes\": { - \"electron\": { - \"origin\": \"https://github.com/electron/electron.git\" - } - } + \"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\", + \"configValidationLevel\": \"strict\", + \"reclient\": \"$1\", + \"preserveXcode\": 5 } " >$buildtools/configs/evm.testing.json } - # Start out as cache only - write_config cache-only - - e use testing + write_config remote_exec - # Attempt to auth to the goma service via codespaces tokens - # if it works we can use the goma cluster - export NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN - if e d goma_auth login; then - write_config cluster - fi + e use testing else - # Even if the config file existed we still need to re-auth with the goma - # cluster - NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN e d goma_auth login || true + echo "build-tools testing config already exists" fi diff --git a/.devcontainer/update-content-command.sh b/.devcontainer/update-content-command.sh new file mode 100755 index 0000000000000..012eef97140ba --- /dev/null +++ b/.devcontainer/update-content-command.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -eo pipefail + +buildtools=$HOME/.electron_build_tools + +export PATH="$PATH:$buildtools/src" + +# Sync latest +e d gclient sync --with_branch_heads --with_tags diff --git a/.env.example b/.env.example index 4d218327bd60e..9f435578dddab 100644 --- a/.env.example +++ b/.env.example @@ -2,5 +2,4 @@ # See docs/development/releasing.md APPVEYOR_CLOUD_TOKEN= -CIRCLE_TOKEN= ELECTRON_GITHUB_TOKEN= diff --git a/.eslintrc.json b/.eslintrc.json index 7669da1863675..2bec582ff6fa9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,6 @@ "semi": ["error", "always"], "no-var": "error", "no-unused-vars": "off", - "no-global-assign": "off", "guard-for-in": "error", "@typescript-eslint/no-unused-vars": ["error", { "vars": "all", @@ -20,20 +19,46 @@ "prefer-const": ["error", { "destructuring": "all" }], - "standard/no-callback-literal": "off", - "node/no-deprecated-api": "off" + "n/no-callback-literal": "off", + "import/newline-after-import": "error", + "import/order": ["error", { + "alphabetize": { + "order": "asc" + }, + "newlines-between": "always", + "pathGroups": [ + { + "pattern": "@electron/internal/**", + "group": "external", + "position": "before" + }, + { + "pattern": "@electron/**", + "group": "external", + "position": "before" + }, + { + "pattern": "{electron,electron/**}", + "group": "external", + "position": "before" + } + ], + "pathGroupsExcludedImportTypes": [], + "distinctGroup": true, + "groups": [ + "external", + "builtin", + ["sibling", "parent"], + "index", + "type" + ] + }] }, "parserOptions": { "ecmaVersion": 6, "sourceType": "module" }, "overrides": [ - { - "files": "*.js", - "rules": { - "@typescript-eslint/no-unused-vars": "off" - } - }, { "files": "*.ts", "rules": { diff --git a/.gitattributes b/.gitattributes index 88189455c32c1..f4542e6b25f8f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,14 +1,34 @@ # `git apply` and friends don't understand CRLF, even on windows. Force those # files to be checked out with LF endings even if core.autocrlf is true. *.patch text eol=lf +DEPS text eol=lf +yarn.lock text eol=lf +script/zip_manifests/*.manifest text eol=lf patches/**/.patches merge=union # Source code and markdown files should always use LF as line ending. +*.c text eol=lf *.cc text eol=lf -*.mm text eol=lf +*.cpp text eol=lf +*.csv text eol=lf +*.grd text eol=lf +*.grdp text eol=lf +*.gn text eol=lf +*.gni text eol=lf *.h text eol=lf -*.js text eol=lf -*.ts text eol=lf +*.html text eol=lf +*.idl text eol=lf +*.in text eol=lf +*.js text eol=lf +*.json text eol=lf +*.json5 text eol=lf +*.md text eol=lf +*.mm text eol=lf +*.mojom text eol=lf +*.patches text eol=lf +*.proto text eol=lf *.py text eol=lf *.ps1 text eol=lf -*.md text eol=lf +*.sh text eol=lf +*.ts text eol=lf +*.txt text eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6bfa64f5a2483..c1f5a5362ba41 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,16 +4,26 @@ # https://git-scm.com/docs/gitignore # Upgrades WG -/patches/ @electron/wg-upgrades @electron/wg-security +/patches/ @electron/patch-owners DEPS @electron/wg-upgrades # Releases WG +/.github/workflows/update_appveyor_image.yml @electron/wg-releases +/docs/breaking-changes.md @electron/wg-releases /npm/ @electron/wg-releases /script/release @electron/wg-releases +appveyor.yml @electron/wg-releases +appveyor-bake.yml @electron/wg-releases +appveyor-woa.yml @electron/wg-releases # Security WG /lib/browser/devtools.ts @electron/wg-security /lib/browser/guest-view-manager.ts @electron/wg-security -/lib/browser/guest-window-proxy.ts @electron/wg-security /lib/browser/rpc-server.ts @electron/wg-security /lib/renderer/security-warnings.ts @electron/wg-security + +# Infra WG +/.github/actions/ @electron/wg-infra +/.github/workflows/*-publish.yml @electron/wg-infra +/.github/workflows/build.yml @electron/wg-infra +/.github/workflows/pipeline-*.yml @electron/wg-infra diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7ea654e33ecea..74318cdb7206d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report -description: Report an Electron bug -title: "[Bug]: " +description: Report a bug in Electron +type: 'bug' labels: "bug :beetle:" body: - type: checkboxes @@ -19,14 +19,15 @@ body: label: Electron Version description: | What version of Electron are you using? - - Note: Please only report issues for [currently supported versions of Electron](https://www.electronjs.org/docs/latest/tutorial/support#currently-supported-versions). - placeholder: 17.0.0 + + Note: Please only report issues for [currently supported versions of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline). + placeholder: 32.0.0 validations: required: true - type: dropdown attributes: - label: What operating system are you using? + label: What operating system(s) are you using? + multiple: true options: - Windows - macOS diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..aa3d859873ad0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Discord Chat + url: https://discord.gg/APGC3k5yaH + about: Have questions? Try asking on our Discord - this issue tracker is for reporting bugs or feature requests only + - name: Open Collective + url: https://opencollective.com/electron + about: Help support Electron by contributing to our Open Collective diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 9e8c1cd168b5e..5bca8a2be4eb4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature Request description: Suggest an idea for Electron -title: "[Feature Request]: " +type: 'enhancement' labels: "enhancement :sparkles:" body: - type: checkboxes @@ -29,7 +29,7 @@ body: - type: textarea attributes: label: Alternatives Considered - description: A clear and concise description of any alternative solutions or features you've considered. + description: A clear and concise description of any alternative solutions or features you've considered. validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/maintainer_issue.yml b/.github/ISSUE_TEMPLATE/maintainer_issue.yml new file mode 100644 index 0000000000000..9ae65a117626c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/maintainer_issue.yml @@ -0,0 +1,14 @@ +name: Maintainer Issue (not for public use) +description: Only to be created by Electron maintainers +body: +- type: checkboxes + attributes: + label: Confirmation + options: + - label: I am a [maintainer](https://github.com/orgs/electron/people) of the Electron project. (If not, please create a [different issue type](https://github.com/electron/electron/issues/new/).) + required: true +- type: textarea + attributes: + label: Description + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3551177321e6d..79dce49f46f72 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,5 @@ #### Description of Change + +Notes: diff --git a/.github/actions/build-electron/action.yml b/.github/actions/build-electron/action.yml new file mode 100644 index 0000000000000..6f12ffe4edd94 --- /dev/null +++ b/.github/actions/build-electron/action.yml @@ -0,0 +1,223 @@ +name: 'Build Electron' +description: 'Builds Electron & Friends' +inputs: + target-arch: + description: 'Target arch' + required: true + target-platform: + description: 'Target platform, should be linux, win, macos' + required: true + artifact-platform: + description: 'Artifact platform, should be linux, win, darwin or mas' + required: true + step-suffix: + description: 'Suffix for build steps' + required: false + default: '' + is-release: + description: 'Is release build' + required: true + strip-binaries: + description: 'Strip binaries (Linux only)' + required: false + generate-symbols: + description: 'Generate symbols' + required: true + upload-to-storage: + description: 'Upload to storage' + required: true + is-asan: + description: 'The ASan Linux build' + required: false +runs: + using: "composite" + steps: + - name: Set GN_EXTRA_ARGS for MacOS x64 Builds + shell: bash + if: ${{ inputs.target-arch == 'x64' && inputs.target-platform == 'macos' }} + run: | + GN_APPENDED_ARGS="$GN_EXTRA_ARGS target_cpu=\"x64\" v8_snapshot_toolchain=\"//build/toolchain/mac:clang_x64\"" + echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV + - name: Build Electron ${{ inputs.step-suffix }} + shell: bash + run: | + rm -rf "src/out/Default/Electron Framework.framework" + rm -rf src/out/Default/Electron*.app + + cd src/electron + # TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing + git pack-refs + cd .. + + if [ "`uname`" = "Darwin" ]; then + ulimit -n 10000 + sudo launchctl limit maxfiles 65536 200000 + fi + + NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES + cp out/Default/.ninja_log out/electron_ninja_log + node electron/script/check-symlinks.js + - name: Strip Electron Binaries ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.strip-binaries == 'true' }} + run: | + cd src + electron/script/copy-debug-symbols.py --target-cpu="${{ inputs.target-arch }}" --out-dir=out/Default/debug --compress + electron/script/strip-binaries.py --target-cpu="${{ inputs.target-arch }}" --verbose + electron/script/add-debug-link.py --target-cpu="${{ inputs.target-arch }}" --debug-dir=out/Default/debug + - name: Build Electron dist.zip ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + e build --target electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES -d explain + if [ "${{ inputs.is-asan }}" != "true" ]; then + target_os=${{ inputs.target-platform == 'macos' && 'mac' || inputs.target-platform }} + if [ "${{ inputs.artifact-platform }}" = "mas" ]; then + target_os="${target_os}_mas" + fi + electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest + fi + - name: Build Mksnapshot ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + e build --target electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES + ELECTRON_DEPOT_TOOLS_DISABLE_LOG=1 e d gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args + # Remove unused args from mksnapshot_args + SEDOPTION="-i" + if [ "`uname`" = "Darwin" ]; then + SEDOPTION="-i ''" + fi + sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args + sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args + + if [ "${{ inputs.target-platform }}" = "linux" ]; then + if [ "${{ inputs.target-arch }}" = "arm" ]; then + electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot + electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot + electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator + else + electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot + electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator + fi + fi + + e build --target electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES + if [ "${{ inputs.target-platform }}" = "win" ]; then + cd out/Default + powershell Compress-Archive -update mksnapshot_args mksnapshot.zip + powershell Compress-Archive -update gen/v8/embedded.S mksnapshot.zip + else + (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S) + fi + - name: Generate Cross-Arch Snapshot (arm/arm64) ${{ inputs.step-suffix }} + shell: bash + if: ${{ (inputs.target-arch == 'arm' || inputs.target-arch == 'arm64') && inputs.target-platform == 'linux' }} + run: | + cd src + if [ "${{ inputs.target-arch }}" = "arm" ]; then + MKSNAPSHOT_PATH="clang_x86_v8_arm" + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + MKSNAPSHOT_PATH="clang_x64_v8_arm64" + fi + + cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default + cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default + cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default + + python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only + mkdir cross-arch-snapshots + cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots + # Clean up so that ninja does not get confused + rm -f out/Default/libffmpeg.so + - name: Build Chromedriver ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + e build --target electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES + e build --target electron:electron_chromedriver_zip + - name: Build Node.js headers ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + e build --target electron:node_headers + - name: Generate & Zip Symbols ${{ inputs.step-suffix }} + shell: bash + run: | + # Generate breakpad symbols on release builds + if [ "${{ inputs.generate-symbols }}" = "true" ]; then + e build --target electron:electron_symbols + fi + cd src + export BUILD_PATH="$(pwd)/out/Default" + e build --target electron:licenses + e build --target electron:electron_version_file + if [ "${{ inputs.is-release }}" = "true" ]; then + DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH + else + electron/script/zip-symbols.py -b $BUILD_PATH + fi + - name: Generate FFMpeg ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' }} + run: | + cd src + gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true $GN_EXTRA_ARGS" + e build --target electron:electron_ffmpeg_zip -C ../../out/ffmpeg -j $NUMBER_OF_NINJA_PROCESSES + - name: Generate Hunspell Dictionaries ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }} + run: | + e build --target electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES + - name: Generate Libcxx ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }} + run: | + e build --target electron:libcxx_headers_zip -j $NUMBER_OF_NINJA_PROCESSES + e build --target electron:libcxxabi_headers_zip -j $NUMBER_OF_NINJA_PROCESSES + e build --target electron:libcxx_objects_zip -j $NUMBER_OF_NINJA_PROCESSES + - name: Generate TypeScript Definitions ${{ inputs.step-suffix }} + if: ${{ inputs.is-release == 'true' }} + shell: bash + run: | + cd src/electron + node script/yarn create-typescript-definitions + - name: Publish Electron Dist ${{ inputs.step-suffix }} + if: ${{ inputs.is-release == 'true' }} + shell: bash + run: | + rm -rf src/out/Default/obj + cd src/electron + if [ "${{ inputs.upload-to-storage }}" = "1" ]; then + echo 'Uploading Electron release distribution to Azure' + script/release/uploaders/upload.py --verbose --upload_to_storage + else + echo 'Uploading Electron release distribution to GitHub releases' + script/release/uploaders/upload.py --verbose + fi + - name: Generate Artifact Key + shell: bash + run: | + if [ "${{ inputs.is-asan }}" = "true" ]; then + ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}_asan + else + ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + fi + echo "ARTIFACT_KEY=$ARTIFACT_KEY" >> $GITHUB_ENV + # The current generated_artifacts_<< artifact.key >> name was taken from CircleCI + # to ensure we don't break anything, but we may be able to improve that. + - name: Move all Generated Artifacts to Upload Folder ${{ inputs.step-suffix }} + shell: bash + run: ./src/electron/script/actions/move-artifacts.sh + - name: Upload Generated Artifacts ${{ inputs.step-suffix }} + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 + with: + name: generated_artifacts_${{ env.ARTIFACT_KEY }} + path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + - name: Upload Src Artifacts ${{ inputs.step-suffix }} + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 + with: + name: src_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }} diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml new file mode 100644 index 0000000000000..0d5c8c3beb645 --- /dev/null +++ b/.github/actions/checkout/action.yml @@ -0,0 +1,181 @@ +name: 'Checkout' +description: 'Checks out Electron and stores it in the AKS Cache' +inputs: + generate-sas-token: + description: 'Whether to generate and persist a SAS token for the item in the cache' + required: false + default: 'false' + use-cache: + description: 'Whether to persist the cache to the shared drive' + required: false + default: 'true' +runs: + using: "composite" + steps: + - name: Set GIT_CACHE_PATH to make gclient to use the cache + shell: bash + run: | + echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Get Depot Tools + shell: bash + run: | + if [[ ! -d depot_tools ]]; then + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + fi + - name: Add Depot Tools to PATH + shell: bash + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Generate DEPS Hash + shell: bash + run: | + node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=v1-src-cache-$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Generate SAS Key + if: ${{ inputs.generate-sas-token == 'true' }} + shell: bash + run: | + curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$DEPSHASH.tar" > sas-token + - name: Save SAS Key + if: ${{ inputs.generate-sas-token == 'true' }} + uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 + with: + path: | + sas-token + key: sas-key-${{ github.run_number }}-${{ github.run_attempt }} + - name: Check If Cache Exists + id: check-cache + shell: bash + run: | + if [[ "${{ inputs.use-cache }}" == "false" ]]; then + echo "Not using cache this time..." + echo "cache_exists=false" >> $GITHUB_OUTPUT + else + cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar + echo "Using cache key: $DEPSHASH" + echo "Checking for cache in: $cache_path" + if [ ! -f "$cache_path" ] || [ `du $cache_path | cut -f1` = "0" ]; then + echo "cache_exists=false" >> $GITHUB_OUTPUT + echo "Cache Does Not Exist for $DEPSHASH" + else + echo "cache_exists=true" >> $GITHUB_OUTPUT + echo "Cache Already Exists for $DEPSHASH, Skipping.." + fi + fi + - name: Check cross instance cache disk space + if: steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' + shell: bash + run: | + # if there is less than 20 GB free space then creating the cache might fail so exit early + freespace=`df -m /mnt/cross-instance-cache | grep -w /mnt/cross-instance-cache | awk '{print $4}'` + freespace_human=`df -h /mnt/cross-instance-cache | grep -w /mnt/cross-instance-cache | awk '{print $4}'` + if [ $freespace -le 20000 ]; then + echo "The cross mount cache has $freespace_human free space which is not enough - exiting" + exit 1 + else + echo "The cross mount cache has $freespace_human free space - continuing" + fi + - name: Gclient Sync + if: steps.check-cache.outputs.cache_exists == 'false' + shell: bash + run: | + e d gclient config \ + --name "src/electron" \ + --unmanaged \ + ${GCLIENT_EXTRA_ARGS} \ + "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" + + if [ "$TARGET_OS" != "" ]; then + echo "target_os=['$TARGET_OS']" >> ./.gclient + fi + + ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 e d gclient sync --with_branch_heads --with_tags -vv + if [ "${{ inputs.is-release }}" != "true" && -n "${{ env.PATCH_UP_APP_CREDS }}" ]; then + # Re-export all the patches to check if there were changes. + python3 src/electron/script/export_all_patches.py src/electron/patches/config.json + cd src/electron + git update-index --refresh || true + if ! git diff-index --quiet HEAD --; then + # There are changes to the patches. Make a git commit with the updated patches + git add patches + GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>" + # Export it + mkdir -p ../../patches + git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch + if node ./script/push-patch.js; then + echo + echo "======================================================================" + echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch" + echo "A new CI job will kick off shortly" + echo "======================================================================" + exit 1 + else + echo + echo "======================================================================" + echo "There were changes to the patches when applying." + echo "Check the CI artifacts for a patch you can apply to fix it." + echo "======================================================================" + echo + cat ../../patches/update-patches.patch + exit 1 + fi + fi + fi + + # delete all .git directories under src/ except for + # third_party/angle/ and third_party/dawn/ because of build time generation of files + # gen/angle/commit.h depends on third_party/angle/.git/HEAD + # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 + # and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD + # https://dawn-review.googlesource.com/c/dawn/+/83901 + # TODO: maybe better to always leave out */.git/HEAD file for all targets ? + - name: Delete .git directories under src to free space + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + cd src + ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf + - name: Minimize Cache Size for Upload + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + rm -rf src/android_webview + rm -rf src/ios/chrome + rm -rf src/third_party/blink/web_tests + rm -rf src/third_party/blink/perf_tests + rm -rf src/chrome/test/data/xr/webvr_info + rm -rf src/third_party/angle/third_party/VK-GL-CTS/src + rm -rf src/third_party/swift-toolchain + rm -rf src/third_party/swiftshader/tests/regres/testlists + cp src/electron/.github/actions/checkout/action.yml ./ + rm -rf src/electron + mkdir -p src/electron/.github/actions/checkout + mv action.yml src/electron/.github/actions/checkout + - name: Compress Src Directory + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')" + tar -cf $DEPSHASH.tar src + echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')" + cp ./$DEPSHASH.tar /mnt/cross-instance-cache/ + - name: Persist Src Cache + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + final_cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar + echo "Using cache key: $DEPSHASH" + echo "Checking path: $final_cache_path" + if [ ! -f "$final_cache_path" ]; then + echo "Cache key not found" + exit 1 + else + echo "Cache key persisted in $final_cache_path" + fi diff --git a/.github/actions/fix-sync-macos/action.yml b/.github/actions/fix-sync-macos/action.yml new file mode 100644 index 0000000000000..e9e2c922280bd --- /dev/null +++ b/.github/actions/fix-sync-macos/action.yml @@ -0,0 +1,61 @@ +name: 'Fix Sync macOS' +description: 'Checks out Electron and stores it in the AKS Cache' +runs: + using: "composite" + steps: + - name: Fix Sync + shell: bash + # This step is required to correct for differences between "gclient sync" + # on Linux and the expected state on macOS. This requires: + # 1. Fixing Clang Install (wrong binary) + # 2. Fixing esbuild (wrong binary) + # 3. Fixing rustc (wrong binary) + # 4. Fixing gn (wrong binary) + # 5. Fix reclient (wrong binary) + # 6. Fixing dsymutil (wrong binary) + # 7. Ensuring we are using the correct ninja and adding it to PATH + # 8. Fixing angle (wrong remote) + run : | + SEDOPTION="-i ''" + rm -rf src/third_party/llvm-build + python3 src/tools/clang/scripts/update.py + + echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file + # Remove extra output from calling gclient getdep which always calls update_depot_tools + sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file + cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file + + rm -rf src/third_party/rust-toolchain + python3 src/tools/rust/update_rust.py + + # Prevent calling gclient getdep which always calls update_depot_tools + echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file + sed -i '' "s/Updating depot_tools... //g" gn_ensure_file + cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file + + # Prevent calling gclient getdep which always calls update_depot_tools + echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file + sed -i '' "s/Updating depot_tools... //g" gn_ensure_file + cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file + python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch + + if [ "${{ env.TARGET_ARCH }}" == "arm64" ]; then + DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1 + else + DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1 + fi + python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil + + echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file + sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file + cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file + + echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH + + cd src/third_party/angle + rm -f .git/objects/info/alternates + git remote set-url origin https://chromium.googlesource.com/angle/angle.git + cp .git/config .git/config.backup + git remote remove origin + mv .git/config.backup .git/config + git fetch diff --git a/.github/actions/free-space-macos/action.yml b/.github/actions/free-space-macos/action.yml new file mode 100644 index 0000000000000..75350ca796bad --- /dev/null +++ b/.github/actions/free-space-macos/action.yml @@ -0,0 +1,65 @@ +name: 'Free Space macOS' +description: 'Checks out Electron and stores it in the AKS Cache' +runs: + using: "composite" + steps: + - name: Free Space on MacOS + shell: bash + run: | + sudo mkdir -p $TMPDIR/del-target + + tmpify() { + if [ -d "$1" ]; then + sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) + fi + } + + strip_universal_deep() { + opwd=$(pwd) + cd $1 + f=$(find . -perm +111 -type f) + for fp in $f + do + if [[ $(file "$fp") == *"universal binary"* ]]; then + if [ "`arch`" == "arm64" ]; then + if [[ $(file "$fp") == *"x86_64"* ]]; then + sudo lipo -remove x86_64 "$fp" -o "$fp" || true + fi + else + if [[ $(file "$fp") == *"arm64e)"* ]]; then + sudo lipo -remove arm64e "$fp" -o "$fp" || true + fi + if [[ $(file "$fp") == *"arm64)"* ]]; then + sudo lipo -remove arm64 "$fp" -o "$fp" || true + fi + fi + fi + done + + cd $opwd + } + + tmpify /Library/Developer/CoreSimulator + tmpify ~/Library/Developer/CoreSimulator + tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform + tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform + tmpify $(xcode-select -p)/Platforms/WatchOS.platform + tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform + tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform + tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0 + tmpify ~/.rubies + tmpify ~/Library/Caches/Homebrew + tmpify /usr/local/Homebrew + + sudo rm -rf $TMPDIR/del-target + + sudo rm -rf /Applications/Safari.app + sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data + sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS + + # lipo off some huge binaries arm64 versions to save space + strip_universal_deep $(xcode-select -p)/../SharedFrameworks + # strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr \ No newline at end of file diff --git a/.github/actions/generate-types/action.yml b/.github/actions/generate-types/action.yml new file mode 100644 index 0000000000000..9909fba912c2b --- /dev/null +++ b/.github/actions/generate-types/action.yml @@ -0,0 +1,24 @@ +name: 'Generate Types for Archaeologist Dig' +description: 'Generate Types for Archaeologist Dig' +inputs: + sha-file: + description: 'File containing sha' + required: true + filename: + description: 'Filename to write types to' + required: true +runs: + using: "composite" + steps: + - name: Generating Types for SHA in ${{ inputs.sha-file }} + shell: bash + run: | + git checkout $(cat ${{ inputs.sha-file }}) + rm -rf node_modules + yarn install --frozen-lockfile --ignore-scripts + echo "#!/usr/bin/env node\nglobal.x=1" > node_modules/typescript/bin/tsc + node node_modules/.bin/electron-docs-parser --dir=./ --outDir=./ --moduleVersion=0.0.0-development + node node_modules/.bin/electron-typescript-definitions --api=electron-api.json --outDir=artifacts + mv artifacts/electron.d.ts artifacts/${{ inputs.filename }} + git checkout . + working-directory: ./electron diff --git a/.github/actions/install-build-tools/action.yml b/.github/actions/install-build-tools/action.yml new file mode 100644 index 0000000000000..0dca6d013010e --- /dev/null +++ b/.github/actions/install-build-tools/action.yml @@ -0,0 +1,20 @@ +name: 'Install Build Tools' +description: 'Installs an exact SHA of build tools' +runs: + using: "composite" + steps: + - name: Install Build Tools + shell: bash + run: | + if [ "$(expr substr $(uname -s) 1 10)" == "MSYS_NT-10" ]; then + git config --global core.filemode false + git config --global core.autocrlf false + git config --global branch.autosetuprebase always + fi + export BUILD_TOOLS_SHA=8246e57791b0af4ae5975eb96f09855f9269b1cd + npm i -g @electron/build-tools + e auto-update disable + if [ "$(expr substr $(uname -s) 1 10)" == "MSYS_NT-10" ]; then + e d cipd.bat --version + cp "C:\Python311\python.exe" "C:\Python311\python3.exe" + fi diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml new file mode 100644 index 0000000000000..25f288c2a7fa1 --- /dev/null +++ b/.github/actions/install-dependencies/action.yml @@ -0,0 +1,21 @@ +name: 'Install Dependencies' +description: 'Installs yarn depdencies using cache when available' +runs: + using: "composite" + steps: + - name: Get yarn cache directory path + shell: bash + id: yarn-cache-dir-path + run: echo "dir=$(node src/electron/script/yarn cache dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('src/electron/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: Install Dependencies + shell: bash + run: | + cd src/electron + node script/yarn install --frozen-lockfile --prefer-offline diff --git a/.github/actions/restore-cache-aks/action.yml b/.github/actions/restore-cache-aks/action.yml new file mode 100644 index 0000000000000..70c67f1d1c91b --- /dev/null +++ b/.github/actions/restore-cache-aks/action.yml @@ -0,0 +1,41 @@ +name: 'Restore Cache AKS' +description: 'Restores Electron src cache via AKS' +runs: + using: "composite" + steps: + - name: Restore and Ensure Src Cache + shell: bash + run: | + cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar + echo "Using cache key: $DEPSHASH" + echo "Checking for cache in: $cache_path" + if [ ! -f "$cache_path" ]; then + echo "Cache Does Not Exist for $DEPSHASH - exiting" + exit 1 + else + echo "Found Cache for $DEPSHASH at $cache_path" + fi + + echo "Persisted cache is $(du -sh $cache_path | cut -f1)" + if [ `du $cache_path | cut -f1` = "0" ]; then + echo "Cache is empty - exiting" + exit 1 + fi + + mkdir temp-cache + tar -xf $cache_path -C temp-cache + echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)" + + if [ -d "temp-cache/src" ]; then + echo "Relocating Cache" + rm -rf src + mv temp-cache/src src + fi + + if [ ! -d "src/third_party/blink" ]; then + echo "Cache was not correctly restored - exiting" + exit 1 + fi + + echo "Wiping Electron Directory" + rm -rf src/electron diff --git a/.github/actions/restore-cache-azcopy/action.yml b/.github/actions/restore-cache-azcopy/action.yml new file mode 100644 index 0000000000000..0ccfd851ea4d2 --- /dev/null +++ b/.github/actions/restore-cache-azcopy/action.yml @@ -0,0 +1,71 @@ +name: 'Restore Cache AZCopy' +description: 'Restores Electron src cache via AZCopy' +runs: + using: "composite" + steps: + - name: Obtain SAS Key + continue-on-error: true + uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 + with: + path: | + sas-token + key: sas-key-${{ github.run_number }}-1 + - name: Obtain SAS Key + continue-on-error: true + uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 + with: + path: | + sas-token + key: sas-key-${{ github.run_number }}-${{ github.run_attempt }} + - name: Download Src Cache from AKS + # The cache will always exist here as a result of the checkout job + # Either it was uploaded to Azure in the checkout job for this commit + # or it was uploaded in the checkout job for a previous commit. + uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 + with: + timeout_minutes: 30 + max_attempts: 3 + retry_on: error + command: | + sas_token=$(cat sas-token) + if [ -z $sas-token ]; then + echo "SAS Token not found; exiting src cache download early..." + exit 1 + fi + azcopy copy --log-level=ERROR \ + "https://${{ env.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar + env: + AZURE_AKS_CACHE_STORAGE_ACCOUNT: f723719aa87a34622b5f7f3 + AZURE_AKS_CACHE_SHARE_NAME: pvc-f6a4089f-b082-4bee-a3f9-c3e1c0c02d8f + - name: Clean SAS Key + shell: bash + run: rm -f sas-token + - name: Unzip and Ensure Src Cache + shell: bash + run: | + echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)" + if [ `du $DEPSHASH.tar | cut -f1` = "0" ]; then + echo "Cache is empty - exiting" + exit 1 + fi + + mkdir temp-cache + tar -xf $DEPSHASH.tar -C temp-cache + echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)" + + if [ -d "temp-cache/src" ]; then + echo "Relocating Cache" + rm -rf src + mv temp-cache/src src + + echo "Deleting zip file" + rm -rf $DEPSHASH.tar + fi + + if [ ! -d "src/third_party/blink" ]; then + echo "Cache was not correctly restored - exiting" + exit 1 + fi + + echo "Wiping Electron Directory" + rm -rf src/electron \ No newline at end of file diff --git a/.github/config.yml b/.github/config.yml index b6bb25d021b24..e1b6e49e1777b 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -2,6 +2,8 @@ newPRWelcomeComment: | 💖 Thanks for opening this pull request! 💖 + ### Semantic PR titles + We use [semantic commit messages](https://github.com/electron/electron/blob/main/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix. Examples of commit messages with semantic prefixes: @@ -10,6 +12,13 @@ newPRWelcomeComment: | - `feat: add app.isPackaged() method` - `docs: app.isDefaultProtocolClient is now available on Linux` + ### Commit signing + + This repo enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) for all incoming PRs. + To sign your commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key). + + ### PR tips + Things that will help get your PR across the finish line: - Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/main/docs/development/coding-style.md). @@ -25,17 +34,3 @@ newPRWelcomeComment: | # Comment to be posted to on pull requests merged by a first time user firstPRMergeComment: > Congrats on merging your first pull request! 🎉🎉🎉 - -# Users authorized to run manual trop backports -authorizedUsers: - - alexeykuzmin - - ckerr - - codebytere - - deepak1556 - - jkleinsc - - loc - - MarshallOfSound - - miniak - - mlaurencin - - nornagon - - zcbenz diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..04a32c3587dd0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,68 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - "no-backport" + - "semver/none" + target-branch: main + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "no-backport" + open-pull-requests-limit: 2 + target-branch: main + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 33-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 32-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 31-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 30-x-y \ No newline at end of file diff --git a/.github/semantic.yml b/.github/semantic.yml deleted file mode 100644 index 4168a3cdeed9e..0000000000000 --- a/.github/semantic.yml +++ /dev/null @@ -1,2 +0,0 @@ -# Always validate the PR title, and ignore the commits -titleOnly: true diff --git a/.github/workflows/archaeologist-dig.yml b/.github/workflows/archaeologist-dig.yml new file mode 100644 index 0000000000000..f9bf7d04bd3d8 --- /dev/null +++ b/.github/workflows/archaeologist-dig.yml @@ -0,0 +1,65 @@ +name: Archaeologist + +on: + pull_request: + +jobs: + archaeologist-dig: + name: Archaeologist Dig + runs-on: ubuntu-latest + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2 + with: + fetch-depth: 0 + - name: Setup Node.js/npm + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a + with: + node-version: 20.11.x + - name: Setting Up Dig Site + run: | + echo "remote: ${{ github.event.pull_request.head.repo.clone_url }}" + echo "sha ${{ github.event.pull_request.head.sha }}" + echo "base ref ${{ github.event.pull_request.base.ref }}" + git clone https://github.com/electron/electron.git electron + cd electron + mkdir -p artifacts + git remote add fork ${{ github.event.pull_request.head.repo.clone_url }} && git fetch fork + git checkout ${{ github.event.pull_request.head.sha }} + git merge-base origin/${{ github.event.pull_request.base.ref }} HEAD > .dig-old + echo ${{ github.event.pull_request.head.sha }} > .dig-new + cp .dig-old artifacts + + - name: Generating Types for SHA in .dig-new + uses: ./.github/actions/generate-types + with: + sha-file: .dig-new + filename: electron.new.d.ts + - name: Generating Types for SHA in .dig-old + uses: ./.github/actions/generate-types + with: + sha-file: .dig-old + filename: electron.old.d.ts + - name: Upload artifacts + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 #v4.6.0 + with: + name: artifacts + path: electron/artifacts + include-hidden-files: true + - name: Set job output + run: | + git diff --no-index electron.old.d.ts electron.new.d.ts > patchfile || true + if [ -s patchfile ]; then + echo "Changes Detected" + echo "## Changes Detected" > $GITHUB_STEP_SUMMARY + echo "Looks like the \`electron.d.ts\` file changed." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`\`\`\`diff" >> $GITHUB_STEP_SUMMARY + cat patchfile >> $GITHUB_STEP_SUMMARY + echo "\`\`\`\`\`\`" >> $GITHUB_STEP_SUMMARY + else + echo "No Changes Detected" + echo "## No Changes" > $GITHUB_STEP_SUMMARY + echo "We couldn't see any changes in the \`electron.d.ts\` artifact" >> $GITHUB_STEP_SUMMARY + fi + working-directory: ./electron/artifacts diff --git a/.github/workflows/branch-created.yml b/.github/workflows/branch-created.yml new file mode 100644 index 0000000000000..c55d9b067e914 --- /dev/null +++ b/.github/workflows/branch-created.yml @@ -0,0 +1,127 @@ +name: Branch Created + +on: + workflow_dispatch: + inputs: + branch-name: + description: Branch name (e.g. `29-x-y`) + required: true + type: string + create: + +permissions: {} + +jobs: + release-branch-created: + name: Release Branch Created + if: ${{ github.event_name == 'workflow_dispatch' || (github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') && !startsWith(github.event.ref, 'roller')) }} + permissions: + contents: read + pull-requests: write + repository-projects: write # Required for labels + runs-on: ubuntu-latest + steps: + - name: Determine Major Version + id: check-major-version + env: + BRANCH_NAME: ${{ github.event.inputs.branch-name || github.event.ref }} + run: | + if [[ "$BRANCH_NAME" =~ ^([0-9]+)-x-y$ ]]; then + echo "MAJOR=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" + else + echo "Not a release branch: $BRANCH_NAME" + fi + - name: New Release Branch Tasks + if: ${{ steps.check-major-version.outputs.MAJOR }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: electron/electron + MAJOR: ${{ steps.check-major-version.outputs.MAJOR }} + NUM_SUPPORTED_VERSIONS: 3 + run: | + PREVIOUS_MAJOR=$((MAJOR - 1)) + UNSUPPORTED_MAJOR=$((MAJOR - NUM_SUPPORTED_VERSIONS - 1)) + + # Create new labels + gh label create $MAJOR-x-y --color 8d9ee8 || true + gh label create target/$MAJOR-x-y --color ad244f --description "PR should also be added to the \"${MAJOR}-x-y\" branch." || true + gh label create merged/$MAJOR-x-y --color 61a3c6 --description "PR was merged to the \"${MAJOR}-x-y\" branch." || true + gh label create in-flight/$MAJOR-x-y --color db69a6 || true + gh label create needs-manual-bp/$MAJOR-x-y --color 8b5dba || true + + # Change color of old labels + gh label edit $UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit target/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit merged/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit in-flight/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit needs-manual-bp/$UNSUPPORTED_MAJOR-x-y --color ededed || true + + # Add the new target label to any PRs which: + # * target the previous major + # * are in-flight for the previous major + # * need manual backport for the previous major + for PREVIOUS_MAJOR_LABEL in target/$PREVIOUS_MAJOR-x-y in-flight/$PREVIOUS_MAJOR-x-y needs-manual-bp/$PREVIOUS_MAJOR-x-y; do + PULL_REQUESTS=$(gh pr list --label $PREVIOUS_MAJOR_LABEL --jq .[].number --json number --limit 500) + if [[ $PULL_REQUESTS ]]; then + echo $PULL_REQUESTS | xargs -n 1 gh pr edit --add-label target/$MAJOR-x-y || true + fi + done + - name: Generate GitHub App token + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Generate Release Project Board Metadata + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: generate-project-metadata + with: + script: | + const major = ${{ steps.check-major-version.outputs.MAJOR }} + const nextMajor = major + 1 + const prevMajor = major - 1 + + core.setOutput("major", major) + core.setOutput("next-major", nextMajor) + core.setOutput("prev-major", prevMajor) + core.setOutput("prev-prev-major", prevMajor - 1) + core.setOutput("template-view", JSON.stringify({ + major, + "next-major": nextMajor, + "prev-major": prevMajor, + })) + - name: Create Release Project Board + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/copy-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + id: create-release-board + with: + drafts: true + project-number: 64 + # TODO - Set to public once GitHub fixes their GraphQL bug + # public: true + # TODO - Enable once GitHub doesn't require overly broad, read + # and write permission for repo "Contents" to link + # link-to-repository: electron/electron + template-view: ${{ steps.generate-project-metadata.outputs.template-view }} + title: ${{ steps.generate-project-metadata.outputs.major }}-x-y + token: ${{ steps.generate-token.outputs.token }} + - name: Dump Release Project Board Contents + if: ${{ steps.check-major-version.outputs.MAJOR }} + run: gh project item-list ${{ steps.create-release-board.outputs.number }} --owner electron --format json | jq + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + - name: Find Previous Release Project Board + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/find-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + id: find-prev-release-board + with: + title: ${{ steps.generate-project-metadata.outputs.prev-prev-major }}-x-y + token: ${{ steps.generate-token.outputs.token }} + - name: Close Previous Release Project Board + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/close-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + project-number: ${{ steps.find-prev-release-board.outputs.number }} + token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000..bdfff61f5ebf5 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,384 @@ +name: Build + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: 'bc2f48b2415a670de18d13605b1cf0eb5fdbaae1' + required: true + skip-macos: + type: boolean + description: 'Skip macOS builds' + default: false + required: false + skip-linux: + type: boolean + description: 'Skip Linux builds' + default: false + required: false + skip-windows: + type: boolean + description: 'Skip Windows builds' + default: false + required: false + skip-lint: + type: boolean + description: 'Skip lint check' + default: false + required: false + push: + branches: + - main + - '[1-9][0-9]-x-y' + pull_request: + +defaults: + run: + shell: bash + +jobs: + setup: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + docs: ${{ steps.filter.outputs.docs }} + src: ${{ steps.filter.outputs.src }} + build-image-sha: ${{ steps.set-output.outputs.build-image-sha }} + docs-only: ${{ steps.set-output.outputs.docs-only }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: filter + with: + filters: | + docs: + - 'docs/**' + src: + - '!docs/**' + - name: Set Outputs for Build Image SHA & Docs Only + id: set-output + run: | + if [ -z "${{ inputs.build-image-sha }}" ]; then + echo "build-image-sha=bc2f48b2415a670de18d13605b1cf0eb5fdbaae1" >> "$GITHUB_OUTPUT" + else + echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT" + fi + echo "docs-only=${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.src == 'false' }}" >> "$GITHUB_OUTPUT" + + # Lint Jobs + lint: + needs: setup + if: ${{ !inputs.skip-lint }} + uses: ./.github/workflows/pipeline-electron-lint.yml + with: + container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}' + secrets: inherit + + # Docs Only Jobs + docs-only: + needs: setup + if: ${{ needs.setup.outputs.docs-only == 'true' }} + uses: ./.github/workflows/pipeline-electron-docs-only.yml + with: + container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}' + secrets: inherit + + # Checkout Jobs + checkout-macos: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}} + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + + checkout-linux: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-linux}} + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + PATCH_UP_APP_CREDS: ${{ secrets.PATCH_UP_APP_CREDS }} + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha}} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + + checkout-windows: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root --device /dev/fuse --cap-add SYS_ADMIN + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' + TARGET_OS: 'win' + ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1' + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha}} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + + # GN Check Jobs + macos-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + needs: checkout-macos + with: + target-platform: macos + target-archs: x64 arm64 + check-runs-on: macos-14 + gn-build-type: testing + secrets: inherit + + linux-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + needs: checkout-linux + with: + target-platform: linux + target-archs: x64 arm arm64 + check-runs-on: electron-arc-linux-amd64-8core + check-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + gn-build-type: testing + secrets: inherit + + windows-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + needs: checkout-windows + with: + target-platform: win + target-archs: x64 x86 arm64 + check-runs-on: electron-arc-linux-amd64-8core + check-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-windows.outputs.build-image-sha }}","options":"--user root --device /dev/fuse --cap-add SYS_ADMIN","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + gn-build-type: testing + secrets: inherit + + # Build Jobs - These cascade into testing jobs + macos-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-macos + with: + build-runs-on: macos-14-xlarge + test-runs-on: macos-13 + target-platform: macos + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + macos-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-macos + with: + build-runs-on: macos-14-xlarge + test-runs-on: macos-14 + target-platform: macos + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + linux-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test-and-nan.yml + needs: checkout-linux + with: + build-runs-on: electron-arc-linux-amd64-32core + test-runs-on: electron-arc-linux-amd64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + linux-x64-asan: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + with: + build-runs-on: electron-arc-linux-amd64-32core + test-runs-on: electron-arc-linux-amd64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + is-asan: true + secrets: inherit + + linux-arm: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + with: + build-runs-on: electron-arc-linux-amd64-32core + test-runs-on: electron-arc-linux-arm64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}' + target-platform: linux + target-arch: arm + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + linux-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + with: + build-runs-on: electron-arc-linux-amd64-32core + test-runs-on: electron-arc-linux-arm64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + windows-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-windows-amd64-16core + test-runs-on: windows-latest + target-platform: win + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + windows-x86: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-windows-amd64-16core + test-runs-on: windows-latest + target-platform: win + target-arch: x86 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + windows-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-windows-amd64-16core + test-runs-on: electron-hosted-windows-arm64-4core + target-platform: win + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + gha-done: + name: GitHub Actions Completed + runs-on: ubuntu-latest + needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64] + if: always() && !contains(needs.*.result, 'failure') + steps: + - name: GitHub Actions Jobs Done + run: | + echo "All GitHub Actions Jobs are done" diff --git a/.github/workflows/clean-src-cache.yml b/.github/workflows/clean-src-cache.yml new file mode 100644 index 0000000000000..73af458ba7303 --- /dev/null +++ b/.github/workflows/clean-src-cache.yml @@ -0,0 +1,21 @@ +name: Clean Source Cache + +on: + schedule: + - cron: "0 0 * * SUN" # Run at midnight every Sunday + +jobs: + clean-src-cache: + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1 + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + steps: + - name: Cleanup Source Cache + shell: bash + run: | + df -h /mnt/cross-instance-cache + find /mnt/cross-instance-cache -type f -mtime +30 -delete + df -h /mnt/cross-instance-cache diff --git a/.github/workflows/electron_woa_testing.yml b/.github/workflows/electron_woa_testing.yml deleted file mode 100644 index 01c2b9a08ca71..0000000000000 --- a/.github/workflows/electron_woa_testing.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Electron WOA Testing - -on: - push: - branches: '**' - workflow_dispatch: - inputs: - appveyor_job_id: - description: 'Job Id of Appveyor WOA job to test' - type: text - required: true - -jobs: - electron-woa-init: - if: ${{ github.event_name == 'push' && github.repository == 'electron/electron' }} - runs-on: ubuntu-latest - steps: - - name: Dummy step for push event - run: | - echo "This job is a needed initialization step for Electron WOA testing. Another test result will appear once the electron-woa-testing build is done." - - electron-woa-testing: - if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'electron/electron' }} - runs-on: [self-hosted, woa] - permissions: - checks: write - pull-requests: write - steps: - - uses: LouisBrunner/checks-action@v1.1.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - status: in_progress - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Test In Progress","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - name: Clean Workspace - run: | - Remove-Item * -Recurse -Force - shell: powershell - - name: Checkout - uses: actions/checkout@v3 - with: - path: src\electron - fetch-depth: 0 - - name: Yarn install - run: | - cd src\electron - node script/yarn.js install --frozen-lockfile - - name: Download and extract dist.zip for test - run: | - $localArtifactPath = "$pwd\dist.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/dist.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\Default -y $localArtifactPath - shell: powershell - - name: Download and extract native test executables for test - run: | - $localArtifactPath = "src\out\Default\shell_browser_ui_unittests.exe" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/shell_browser_ui_unittests.exe" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - shell: powershell - - name: Download and extract ffmpeg.zip for test - run: | - $localArtifactPath = "$pwd\ffmpeg.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/ffmpeg.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\ffmpeg $localArtifactPath - shell: powershell - - name: Download node headers for test - run: | - $localArtifactPath = "src\node_headers.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/node_headers.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - cd src - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip - shell: powershell - - name: Download electron.lib for test - run: | - $localArtifactPath = "src\out\Default\electron.lib" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/electron.lib" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - shell: powershell - # Uncomment the following block if pdb files are needed to debug issues - # - name: Download pdb files for detailed stacktraces - # if: ${{ github.event_name == 'workflow_dispatch' }} - # run: | - # try { - # $localArtifactPath = "src\pdb.zip" - # $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/pdb.zip" - # Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - # cd src - # & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip - # } catch { - # Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message - # } finally { - # $global:LASTEXITCODE = 0 - # } - # shell: powershell - - name: Setup node headers - run: | - New-Item src\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path src\out\Default\electron.lib -destination src\out\Default\gen\node_headers\Release\node.lib - shell: powershell - - name: Run Electron Main process tests - run: | - cd src - set npm_config_nodedir=%cd%\out\Default\gen\node_headers - set npm_config_arch=arm64 - cd electron - node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion - env: - ELECTRON_ENABLE_STACK_DUMPING: true - ELECTRON_OUT_DIR: Default - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_SKIP_NATIVE_MODULE_TESTS: true - - name: Run Electron Remote based tests - if: ${{ success() || failure() }} - run: | - cd src - set npm_config_nodedir=%cd%\out\Default\gen\node_headers - set npm_config_arch=arm64 - cd electron - node script/yarn test --runners=remote --enable-logging --disable-features=CalculateNativeWinOcclusion - env: - ELECTRON_OUT_DIR: Default - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_SKIP_NATIVE_MODULE_TESTS: true - - name: Verify ffmpeg - run: | - cd src - echo "Verifying non proprietary ffmpeg" - python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg - shell: cmd - - name: Kill processes left running from last test run - if: ${{ always() }} - run: | - Get-Process | Where Name -Like "electron*" | Stop-Process - Get-Process | Where Name -Like "msedge*" | Stop-Process - shell: powershell - - name: Delete user app data directories - if: ${{ always() }} - run: | - Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore - shell: powershell - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"${{ job.status }}","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Job Succeeded","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ ! success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Job Failed","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} \ No newline at end of file diff --git a/.github/workflows/issue-commented.yml b/.github/workflows/issue-commented.yml new file mode 100644 index 0000000000000..a3dc5a3741e4f --- /dev/null +++ b/.github/workflows/issue-commented.yml @@ -0,0 +1,26 @@ +name: Issue Commented + +on: + issue_comment: + types: + - created + +permissions: {} + +jobs: + issue-commented: + name: Remove blocked/{need-info,need-repro} on comment + if: ${{ (contains(github.event.issue.labels.*.name, 'blocked/need-repro') || contains(github.event.issue.labels.*.name, 'blocked/need-info ❌')) && !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) && github.event.comment.user.type != 'Bot' }} + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Remove label + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + ISSUE_URL: ${{ github.event.issue.html_url }} + run: | + gh issue edit $ISSUE_URL --remove-label 'blocked/need-repro','blocked/need-info ❌' diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 0000000000000..11e46e58ea5f3 --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,88 @@ +name: Issue Labeled + +on: + issues: + types: [labeled] + +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + +jobs: + issue-labeled-with-status: + name: status/{confirmed,reviewed} label added + if: github.event.label.name == 'status/confirmed' || github.event.label.name == 'status/reviewed' + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: ✅ Triaged + fail-if-item-not-found: false + issue-labeled-blocked: + name: blocked/* label added + if: startsWith(github.event.label.name, 'blocked/') + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: 🛑 Blocked + fail-if-item-not-found: false + issue-labeled-blocked-need-repro: + name: blocked/need-repro label added + if: github.event.label.name == 'blocked/need-repro' + permissions: + issues: write # for actions-cool/issues-helper to update issues + runs-on: ubuntu-latest + steps: + - name: Check if comment needed + id: check-for-comment + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: electron/electron + run: | + set -eo pipefail + COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("")) ] | length') + if [[ $COMMENT_COUNT -eq 0 ]]; then + echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT" + fi + - name: Generate GitHub App token + if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Create comment + if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} + uses: actions-cool/issues-helper@a610082f8ac0cf03e357eb8dd0d5e2ba075e017e # v3.6.0 + with: + actions: 'create-comment' + token: ${{ steps.generate-token.outputs.token }} + body: | + + + Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better! + + Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use. + + Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests. + + Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-repro label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed. diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml new file mode 100644 index 0000000000000..bd8ec413f6f9d --- /dev/null +++ b/.github/workflows/issue-opened.yml @@ -0,0 +1,145 @@ +name: Issue Opened + +on: + issues: + types: + - opened + +permissions: {} + +jobs: + add-to-issue-triage: + if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Add to Issue Triage + uses: dsanders11/project-actions/add-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + field: Reporter + field-value: ${{ github.event.issue.user.login }} + project-number: 90 + token: ${{ steps.generate-token.outputs.token }} + set-labels: + if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - run: npm install @electron/fiddle-core@1.3.3 mdast-util-from-markdown@2.0.0 unist-util-select@5.1.0 semver@7.6.0 + - name: Add labels + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: add-labels + env: + ISSUE_BODY: ${{ github.event.issue.body }} + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const { fromMarkdown } = await import('${{ github.workspace }}/node_modules/mdast-util-from-markdown/index.js'); + const { select } = await import('${{ github.workspace }}/node_modules/unist-util-select/index.js'); + const semver = await import('${{ github.workspace }}/node_modules/semver/index.js'); + + const [ owner, repo ] = '${{ github.repository }}'.split('/'); + const issue_number = ${{ github.event.issue.number }}; + + const tree = fromMarkdown(process.env.ISSUE_BODY); + + const labels = []; + + const electronVersion = select('heading:has(> text[value="Electron Version"]) + paragraph > text', tree)?.value.trim(); + if (electronVersion !== undefined) { + // It's possible for multiple versions to be listed - + // for now check for comma or space separated version. + const versions = electronVersion.split(/, | /); + for (const version of versions) { + const major = semver.coerce(version, { loose: true })?.major; + if (major) { + const versionLabel = `${major}-x-y`; + let labelExists = false; + + try { + await github.rest.issues.getLabel({ + owner, + repo, + name: versionLabel, + }); + labelExists = true; + } catch {} + + if (labelExists) { + // Check if it's an unsupported major + const { ElectronVersions } = await import('${{ github.workspace }}/node_modules/@electron/fiddle-core/dist/index.js'); + const versions = await ElectronVersions.create(undefined, { ignoreCache: true }); + + const validVersions = [...versions.supportedMajors, ...versions.prereleaseMajors]; + if (validVersions.includes(major)) { + labels.push(versionLabel); + } + } + } + } + if (labels.length === 0) { + core.setOutput('unsupportedMajor', true); + labels.push('blocked/need-info ❌'); + } + } + + const operatingSystems = select('heading:has(> text[value="What operating system(s) are you using?"]) + paragraph > text', tree)?.value.trim().split(', '); + const platformLabels = new Set(); + for (const operatingSystem of (operatingSystems ?? [])) { + switch (operatingSystem) { + case 'Windows': + platformLabels.add('platform/windows'); + break; + case 'macOS': + platformLabels.add('platform/macOS'); + break; + case 'Ubuntu': + case 'Other Linux': + platformLabels.add('platform/linux'); + break; + } + } + + if (platformLabels.size === 3) { + labels.push('platform/all'); + } else { + labels.push(...platformLabels); + } + + const gistUrl = select('heading:has(> text[value="Testcase Gist URL"]) + paragraph > text', tree)?.value.trim(); + if (gistUrl !== undefined && gistUrl.startsWith('https://gist.github.com/')) { + labels.push('has-repro-gist'); + } + + if (labels.length) { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number, + labels, + }); + } + - name: Create unsupported major comment + if: ${{ steps.add-labels.outputs.unsupportedMajor }} + uses: actions-cool/issues-helper@a610082f8ac0cf03e357eb8dd0d5e2ba075e017e # v3.6.0 + with: + actions: 'create-comment' + token: ${{ steps.generate-token.outputs.token }} + body: | + + + Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better! + + The version of Electron reported in this issue has reached end-of-life and is [no longer supported](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline). If you're still experiencing this issue on a [supported version](https://www.electronjs.org/releases/stable) of Electron, please update this issue to reflect that version of Electron. + + Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-info%20%E2%9D%8C label for this reason. This issue will be closed in 10 days if the above is not addressed. diff --git a/.github/workflows/issue-transferred.yml b/.github/workflows/issue-transferred.yml new file mode 100644 index 0000000000000..824cb69a2c9f3 --- /dev/null +++ b/.github/workflows/issue-transferred.yml @@ -0,0 +1,27 @@ +name: Issue Transferred + +on: + issues: + types: [transferred] + +permissions: {} + +jobs: + issue-transferred: + name: Issue Transferred + runs-on: ubuntu-latest + if: ${{ !github.event.changes.new_repository.private }} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Remove from issue triage + uses: dsanders11/project-actions/delete-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + item: ${{ github.event.changes.new_issue.html_url }} + fail-if-item-not-found: false diff --git a/.github/workflows/issue-unlabeled.yml b/.github/workflows/issue-unlabeled.yml new file mode 100644 index 0000000000000..6337e3d91740f --- /dev/null +++ b/.github/workflows/issue-unlabeled.yml @@ -0,0 +1,39 @@ +name: Issue Unlabeled + +on: + issues: + types: [unlabeled] + +permissions: + contents: read + +jobs: + issue-unlabeled-blocked: + name: All blocked/* labels removed + if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open' + runs-on: ubuntu-latest + steps: + - name: Check for any blocked labels + id: check-for-blocked-labels + run: | + set -eo pipefail + BLOCKED_LABEL_COUNT=$(echo '${{ toJSON(github.event.issue.labels.*.name) }}' | jq '[ .[] | select(startswith("blocked/")) ] | length') + if [[ $BLOCKED_LABEL_COUNT -eq 0 ]]; then + echo "NOT_BLOCKED=1" >> "$GITHUB_OUTPUT" + fi + - name: Generate GitHub App token + if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }} + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }} + uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: 📥 Was Blocked + fail-if-item-not-found: false diff --git a/.github/workflows/linux-publish.yml b/.github/workflows/linux-publish.yml new file mode 100644 index 0000000000000..cfba90632237e --- /dev/null +++ b/.github/workflows/linux-publish.yml @@ -0,0 +1,86 @@ +name: Publish Linux + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: 'bc2f48b2415a670de18d13605b1cf0eb5fdbaae1' + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-linux-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +jobs: + checkout-linux: + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + + publish-x64: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-linux + with: + environment: production-release + build-runs-on: electron-arc-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: x64 + is-release: true + gn-build-type: release + generate-symbols: true + strip-binaries: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-linux + with: + environment: production-release + build-runs-on: electron-arc-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: arm + is-release: true + gn-build-type: release + generate-symbols: true + strip-binaries: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-linux + with: + environment: production-release + build-runs-on: electron-arc-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: arm64 + is-release: true + gn-build-type: release + generate-symbols: true + strip-binaries: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.github/workflows/macos-publish.yml b/.github/workflows/macos-publish.yml new file mode 100644 index 0000000000000..34baead94a33b --- /dev/null +++ b/.github/workflows/macos-publish.yml @@ -0,0 +1,101 @@ +name: Publish MacOS + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: 'bc2f48b2415a670de18d13605b1cf0eb5fdbaae1' + required: true + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-macos-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +jobs: + checkout-macos: + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + + publish-x64-darwin: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-14-xlarge + target-platform: macos + target-arch: x64 + target-variant: darwin + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-x64-mas: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-14-xlarge + target-platform: macos + target-arch: x64 + target-variant: mas + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-darwin: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-14-xlarge + target-platform: macos + target-arch: arm64 + target-variant: darwin + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-mas: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-14-xlarge + target-platform: macos + target-arch: arm64 + target-variant: mas + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.github/workflows/non-maintainer-dependency-change.yml b/.github/workflows/non-maintainer-dependency-change.yml new file mode 100644 index 0000000000000..4fef73fe2136e --- /dev/null +++ b/.github/workflows/non-maintainer-dependency-change.yml @@ -0,0 +1,37 @@ +name: Check for Non-Maintainer Dependency Change + +on: + pull_request_target: + paths: + - 'yarn.lock' + - 'spec/yarn.lock' + +permissions: {} + +jobs: + check-for-non-maintainer-dependency-change: + name: Check for non-maintainer dependency change + if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.pull_request.author_association) && github.event.pull_request.user.type != 'Bot' && !github.event.pull_request.draft }} + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Check for existing review + id: check-for-review + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + set -eo pipefail + REVIEW_COUNT=$(gh pr view $PR_URL --json reviews | jq '[ .reviews[] | select(.author.login == "github-actions") | select(.body | startswith("")) ] | length') + if [[ $REVIEW_COUNT -eq 0 ]]; then + echo "SHOULD_REVIEW=1" >> "$GITHUB_OUTPUT" + fi + - name: Request changes + if: ${{ steps.check-for-review.outputs.SHOULD_REVIEW }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + printf "\n\nHello @${{ github.event.pull_request.user.login }}! It looks like this pull request touches one of our dependency files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs." | gh pr review $PR_URL -r --body-file=- diff --git a/.github/workflows/pipeline-electron-build-and-test-and-nan.yml b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml new file mode 100644 index 0000000000000..066faac2549c4 --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml @@ -0,0 +1,93 @@ +name: Electron Build & Test (+ Node + NaN) Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux.' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + +concurrency: + group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + secrets: inherit + nn-test: + uses: ./.github/workflows/pipeline-segment-node-nan-test.yml + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + gn-build-type: ${{ inputs.gn-build-type }} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-build-and-test.yml b/.github/workflows/pipeline-electron-build-and-test.yml new file mode 100644 index 0000000000000..f55bbfb387014 --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-test.yml @@ -0,0 +1,90 @@ +name: Electron Build & Test Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + +concurrency: + group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +permissions: + contents: read + issues: read + pull-requests: read + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + is-asan: ${{ inputs.is-asan}} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + is-asan: ${{ inputs.is-asan}} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-docs-only.yml b/.github/workflows/pipeline-electron-docs-only.yml new file mode 100644 index 0000000000000..eb5441d148222 --- /dev/null +++ b/.github/workflows/pipeline-electron-docs-only.yml @@ -0,0 +1,42 @@ +name: Electron Docs Compile + +on: + workflow_call: + inputs: + container: + required: true + description: 'Container to run the docs-only ts compile in' + type: string + +concurrency: + group: electron-docs-only-${{ github.ref }} + cancel-in-progress: true + +jobs: + docs-only: + name: Docs Only Compile + runs-on: electron-arc-linux-amd64-4core + timeout-minutes: 20 + container: ${{ fromJSON(inputs.container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Run TS/JS compile + shell: bash + run: | + cd src/electron + node script/yarn create-typescript-definitions + node script/yarn tsc -p tsconfig.default_app.json --noEmit + for f in build/webpack/*.js + do + out="${f:29}" + if [ "$out" != "base.js" ]; then + node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development + fi + done diff --git a/.github/workflows/pipeline-electron-lint.yml b/.github/workflows/pipeline-electron-lint.yml new file mode 100644 index 0000000000000..166060e396be0 --- /dev/null +++ b/.github/workflows/pipeline-electron-lint.yml @@ -0,0 +1,76 @@ +name: Electron Lint + +on: + workflow_call: + inputs: + container: + required: true + description: 'Container to run lint in' + type: string + +concurrency: + group: electron-lint-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +jobs: + lint: + name: Lint + runs-on: electron-arc-linux-amd64-4core + timeout-minutes: 20 + container: ${{ fromJSON(inputs.container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Setup third_party Depot Tools + shell: bash + run: | + # "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file. + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools + echo "$(pwd)/src/third_party/depot_tools" >> $GITHUB_PATH + - name: Download GN Binary + shell: bash + run: | + chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" + gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)" + + cipd ensure -ensure-file - -root . <<-CIPD + \$ServiceURL https://chrome-infra-packages.appspot.com/ + @Subdir src/buildtools/linux64 + gn/gn/linux-amd64 $gn_version + CIPD + + buildtools_path="$(pwd)/src/buildtools" + echo "CHROMIUM_BUILDTOOLS_PATH=$buildtools_path" >> $GITHUB_ENV + - name: Download clang-format Binary + shell: bash + run: | + chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" + + mkdir -p src/buildtools + curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS + + gclient sync --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]" + - name: Run Lint + shell: bash + run: | + # gn.py tries to find a gclient root folder starting from the current dir. + # When it fails and returns "None" path, the whole script fails. Let's "fix" it. + touch .gclient + # Another option would be to checkout "buildtools" inside the Electron checkout, + # but then we would lint its contents (at least gn format), and it doesn't pass it. + + cd src/electron + node script/yarn install --frozen-lockfile + node script/yarn lint + - name: Run Script Typechecker + shell: bash + run: | + cd src/electron + node script/yarn tsc -p tsconfig.script.json + diff --git a/.github/workflows/pipeline-segment-electron-build.yml b/.github/workflows/pipeline-segment-electron-build.yml new file mode 100644 index 0000000000000..4731c21db0736 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-build.yml @@ -0,0 +1,220 @@ +name: Pipeline Segment - Electron Build + +on: + workflow_call: + inputs: + environment: + description: using the production or testing environment + required: false + type: string + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64, ia32 or arm' + required: true + target-variant: + type: string + description: 'Variant to build for, no effect on non-macOS target platforms. Can be darwin, mas or all.' + default: all + build-runs-on: + type: string + description: 'What host to run the build' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + strip-binaries: + description: 'Strip the binaries before release (Linux only)' + required: false + type: boolean + default: false + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + + +concurrency: + group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +env: + ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }} + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }} + SUDOWOODO_EXCHANGE_TOKEN: ${{ secrets.SUDOWOODO_EXCHANGE_TOKEN }} + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || inputs.target-platform == 'win' && '--custom-var=checkout_win=True' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }} + ELECTRON_OUT_DIR: Default + +jobs: + build: + defaults: + run: + shell: bash + runs-on: ${{ inputs.build-runs-on }} + container: ${{ fromJSON(inputs.build-container) }} + environment: ${{ inputs.environment }} + env: + TARGET_ARCH: ${{ inputs.target-arch }} + steps: + - name: Create src dir + run: | + mkdir src + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Setup Node.js/npm + if: ${{ inputs.target-platform == 'macos' }} + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a + with: + node-version: 20.11.x + cache: yarn + cache-dependency-path: src/electron/yarn.lock + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Install AZCopy + if: ${{ inputs.target-platform == 'macos' }} + run: brew install azcopy + - name: Set GN_EXTRA_ARGS for Linux + if: ${{ inputs.target-platform == 'linux' }} + run: | + if [ "${{ inputs.target-arch }}" = "arm" ]; then + if [ "${{ inputs.is-release }}" = true ]; then + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1' + else + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false' + fi + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false' + elif [ "${{ inputs.is-asan }}" = true ]; then + GN_EXTRA_ARGS='is_asan=true' + fi + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Get Depot Tools + timeout-minutes: 5 + run: | + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git + + SEDOPTION="-i" + if [ "`uname`" = "Darwin" ]; then + SEDOPTION="-i ''" + fi + + # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems + sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja + + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + - name: Add Depot Tools to PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v1-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' }} + uses: ./src/electron/.github/actions/restore-cache-aks + - name: Checkout src via gclient sync + if: ${{ inputs.target-platform == 'win' }} + uses: ./src/electron/.github/actions/checkout + with: + use-cache: 'false' + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} + - name: Run Electron Only Hooks + run: | + e d gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" + - name: Regenerate DEPS Hash + run: | + (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Fix Sync (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/fix-sync-macos + - name: Setup Number of Ninja Processes + run: | + echo "NUMBER_OF_NINJA_PROCESSES=${{ inputs.target-platform != 'macos' && '300' || '200' }}" >> $GITHUB_ENV + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Build Electron + if: ${{ inputs.target-platform != 'macos' || (inputs.target-variant == 'all' || inputs.target-variant == 'darwin') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: ${{ inputs.target-platform == 'macos' && 'darwin' || inputs.target-platform }} + is-release: '${{ inputs.is-release }}' + generate-symbols: '${{ inputs.generate-symbols }}' + strip-binaries: '${{ inputs.strip-binaries }}' + upload-to-storage: '${{ inputs.upload-to-storage }}' + is-asan: '${{ inputs.is-asan }}' + - name: Set GN_EXTRA_ARGS for MAS Build + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || inputs.target-variant == 'mas') }} + run: | + echo "MAS_BUILD=true" >> $GITHUB_ENV + GN_EXTRA_ARGS='is_mas_build=true' + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Build Electron (MAS) + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || inputs.target-variant == 'mas') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: 'mas' + is-release: '${{ inputs.is-release }}' + generate-symbols: '${{ inputs.generate-symbols }}' + upload-to-storage: '${{ inputs.upload-to-storage }}' + step-suffix: '(mas)' diff --git a/.github/workflows/pipeline-segment-electron-gn-check.yml b/.github/workflows/pipeline-segment-electron-gn-check.yml new file mode 100644 index 0000000000000..550cd42b7a859 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-gn-check.yml @@ -0,0 +1,156 @@ +name: Pipeline Segment - Electron GN Check + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-archs: + type: string + description: 'Archs to check for, can be x64, x86, arm64 or arm space separated' + required: true + check-runs-on: + type: string + description: 'What host to run the tests on' + required: true + check-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + +concurrency: + group: electron-gn-check-${{ inputs.target-platform }}-${{ github.ref }} + cancel-in-progress: true + +env: + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || (inputs.target-platform == 'linux' && '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' || '--custom-var=checkout_win=True') }} + ELECTRON_OUT_DIR: Default + +jobs: + gn-check: + defaults: + run: + shell: bash + runs-on: ${{ inputs.check-runs-on }} + container: ${{ fromJSON(inputs.check-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Cleanup disk space on macOS + if: ${{ inputs.target-platform == 'macos' }} + shell: bash + run: | + sudo mkdir -p $TMPDIR/del-target + + tmpify() { + if [ -d "$1" ]; then + sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) + fi + } + tmpify /Library/Developer/CoreSimulator + tmpify ~/Library/Developer/CoreSimulator + sudo rm -rf $TMPDIR/del-target + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Enable windows toolchain + if: ${{ inputs.target-platform == 'win' }} + run: | + echo "ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN=1" >> $GITHUB_ENV + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v1-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' || inputs.target-platform == 'win' }} + uses: ./src/electron/.github/actions/restore-cache-aks + - name: Run Electron Only Hooks + run: | + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" > tmpgclient + if [ "${{ inputs.target-platform }}" = "win" ]; then + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False,'install_sysroot':False,'checkout_win':True},'managed':False}]" > tmpgclient + echo "target_os=['win']" >> tmpgclient + fi + e d gclient runhooks --gclientfile=tmpgclient + + # Fix VS Toolchain + if [ "${{ inputs.target-platform }}" = "win" ]; then + rm -rf src/third_party/depot_tools/win_toolchain/vs_files + e d python3 src/build/vs_toolchain.py update --force + fi + - name: Regenerate DEPS Hash + run: | + (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Default GN gen + run: | + cd src/electron + git pack-refs + - name: Run GN Check for ${{ inputs.target-archs }} + run: | + for target_cpu in ${{ inputs.target-archs }} + do + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu $target_cpu + cd src + export GN_EXTRA_ARGS="target_cpu=\"$target_cpu\"" + if [ "${{ inputs.target-platform }}" = "linux" ]; then + if [ "$target_cpu" = "arm" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS build_tflite_with_xnnpack=false" + elif [ "$target_cpu" = "arm64" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS fatal_linker_warnings=false enable_linux_installer=false" + fi + fi + if [ "${{ inputs.target-platform }}" = "win" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS use_v8_context_snapshot=true target_os=\"win\"" + fi + + e build --only-gen + + e d gn check out/Default //electron:electron_lib + e d gn check out/Default //electron:electron_app + e d gn check out/Default //electron/shell/common:mojo + e d gn check out/Default //electron/shell/common:plugin + + # Check the hunspell filenames + node electron/script/gen-hunspell-filenames.js --check + node electron/script/gen-libc++-filenames.js --check + cd .. + done + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pipeline-segment-electron-test.yml b/.github/workflows/pipeline-segment-electron-test.yml new file mode 100644 index 0000000000000..27e40a218de12 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-test.yml @@ -0,0 +1,254 @@ +name: Pipeline Segment - Electron Test + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + test-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + +concurrency: + group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +permissions: + contents: read + issues: read + pull-requests: read + +env: + ELECTRON_OUT_DIR: Default + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + +jobs: + test: + defaults: + run: + shell: bash + runs-on: ${{ inputs.test-runs-on }} + container: ${{ fromJSON(inputs.test-container) }} + strategy: + fail-fast: false + matrix: + build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || (inputs.target-platform == 'win' && fromJSON('["win"]') || fromJSON('["linux"]')) }} + shard: ${{ inputs.target-platform == 'linux' && fromJSON('[1, 2, 3]') || fromJSON('[1, 2]') }} + env: + BUILD_TYPE: ${{ matrix.build-type }} + TARGET_ARCH: ${{ inputs.target-arch }} + ARTIFACT_KEY: ${{ matrix.build-type }}_${{ inputs.target-arch }} + steps: + - name: Fix node20 on arm32 runners + if: ${{ inputs.target-arch == 'arm' && inputs.target-platform == 'linux' }} + run: | + cp $(which node) /mnt/runner-externals/node20/bin/ + - name: Install Git on Windows arm64 runners + if: ${{ inputs.target-arch == 'arm64' && inputs.target-platform == 'win' }} + shell: powershell + run: | + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + choco install -y --no-progress git.install --params "'/GitAndUnixToolsOnPath'" + choco install -y --no-progress git + choco install -y --no-progress python --version 3.11.9 + choco install -y --no-progress visualstudio2022-workload-vctools --package-parameters "--add Microsoft.VisualStudio.Component.VC.Tools.ARM64" + echo "C:\Program Files\Git\cmd" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "C:\Program Files\Git\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "C:\Python311" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Setup Node.js/npm + if: ${{ inputs.target-platform == 'win' }} + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a + with: + node-version: 20.11.x + - name: Add TCC permissions on macOS + if: ${{ inputs.target-platform == 'macos' }} + run: | + configure_user_tccdb () { + local values=$1 + local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db" + local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);" + sqlite3 "$dbPath" "$sqlQuery" + } + + configure_sys_tccdb () { + local values=$1 + local dbPath="/Library/Application Support/com.apple.TCC/TCC.db" + local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);" + sudo sqlite3 "$dbPath" "$sqlQuery" + } + + userValuesArray=( + "'kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + ) + for values in "${userValuesArray[@]}"; do + # Sonoma and higher have a few extra values + # Ref: https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-tccdb-macos.sh + if [ "$OSTYPE" = "darwin23" ]; then + configure_user_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}" + configure_sys_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}" + else + configure_user_tccdb "$values" + configure_sys_tccdb "$values" + fi + done + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Get Depot Tools + timeout-minutes: 5 + run: | + git config --global core.filemode false + git config --global core.autocrlf false + git config --global branch.autosetuprebase always + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + - name: Add Depot Tools to PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Load ASan specific environment variables + if: ${{ inputs.is-asan == true }} + run: | + echo "ARTIFACT_KEY=${{ matrix.build-type }}_${{ inputs.target-arch }}_asan" >> $GITHUB_ENV + echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV + echo "IS_ASAN=true" >> $GITHUB_ENV + - name: Download Generated Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: generated_artifacts_${{ env.ARTIFACT_KEY }} + path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} + - name: Download Src Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: src_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist, Mksnapshot & Chromedriver (win) + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + run: | + Set-ExecutionPolicy Bypass -Scope Process -Force + cd src/out/Default + Expand-Archive -Force dist.zip -DestinationPath ./ + Expand-Archive -Force chromedriver.zip -DestinationPath ./ + Expand-Archive -Force mksnapshot.zip -DestinationPath ./ + - name: Unzip Dist, Mksnapshot & Chromedriver (unix) + if: ${{ inputs.target-platform != 'win' }} + run: | + cd src/out/Default + unzip -:o dist.zip + unzip -:o chromedriver.zip + unzip -:o mksnapshot.zip + - name: Import & Trust Self-Signed Codesigning Cert on MacOS + if: ${{ inputs.target-platform == 'macos' && inputs.target-arch == 'x64' }} + run: | + sudo security authorizationdb write com.apple.trust-settings.admin allow + cd src/electron + ./script/codesign/generate-identity.sh + - name: Install Datadog CLI + run: | + cd src/electron + node script/yarn global add @datadog/datadog-ci + - name: Run Electron Tests + shell: bash + env: + MOCHA_REPORTER: mocha-multi-reporters + MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap + ELECTRON_DISABLE_SECURITY_WARNINGS: 1 + ELECTRON_SKIP_NATIVE_MODULE_TESTS: true + DISPLAY: ':99.0' + NPM_CONFIG_MSVS_VERSION: '2022' + run: | + cd src/electron + export ELECTRON_TEST_RESULTS_DIR=`pwd`/junit + # Get which tests are on this shard + tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ inputs.target-platform == 'linux' && 3 || 2 }}) + + # Run tests + if [ "${{ inputs.target-platform }}" != "linux" ]; then + echo "About to start tests" + if [ "${{ inputs.target-platform }}" = "win" ]; then + if [ "${{ inputs.target-arch }}" = "x86" ]; then + export npm_config_arch="ia32" + fi + if [ "${{ inputs.target-arch }}" = "arm64" ]; then + export ELECTRON_FORCE_TEST_SUITE_EXIT="true" + fi + fi + node script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files + else + chown :builduser .. && chmod g+w .. + chown -R :builduser . && chmod -R g+w . + chmod 4755 ../out/Default/chrome-sandbox + runuser -u builduser -- git config --global --add safe.directory $(pwd) + if [ "${{ inputs.is-asan }}" == "true" ]; then + cd .. + ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron" + export ASAN_OPTIONS="symbolize=0 handle_abort=1" + export G_SLICE=always-malloc + export NSS_DISABLE_ARENA_FREE_LIST=1 + export NSS_DISABLE_UNLOAD=1 + export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer + export MOCHA_TIMEOUT=180000 + echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)" + cd electron + runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE + else + runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files + fi + fi + - name: Upload Test results to Datadog + env: + DD_ENV: ci + DD_SERVICE: electron + DD_API_KEY: ${{ secrets.DD_API_KEY }} + DD_CIVISIBILITY_LOGS_ENABLED: true + DD_TAGS: "os.architecture:${{ inputs.target-arch }},os.family:${{ inputs.target-platform }},os.platform:${{ inputs.target-platform }},asan:${{ inputs.is-asan }}" + run: | + if ! [ -z $DD_API_KEY ] && [ -f src/electron/junit/test-results-main.xml ]; then + export DATADOG_PATH=`node src/electron/script/yarn global bin` + $DATADOG_PATH/datadog-ci junit upload src/electron/junit/test-results-main.xml + fi + if: always() && !cancelled() + - name: Upload Test Artifacts + if: always() && !cancelled() + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 + with: + name: test_artifacts_${{ env.ARTIFACT_KEY }}_${{ matrix.shard }} + path: src/electron/spec/artifacts + if-no-files-found: ignore + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pipeline-segment-node-nan-test.yml b/.github/workflows/pipeline-segment-node-nan-test.yml new file mode 100644 index 0000000000000..093bcf9e5d94b --- /dev/null +++ b/.github/workflows/pipeline-segment-node-nan-test.yml @@ -0,0 +1,159 @@ +name: Pipeline Segment - Node/Nan Test + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + test-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + +concurrency: + group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }} + +env: + ELECTRON_OUT_DIR: Default + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + +jobs: + node-tests: + name: Run Node.js Tests + runs-on: electron-arc-linux-amd64-8core + timeout-minutes: 20 + env: + TARGET_ARCH: ${{ inputs.target-arch }} + BUILD_TYPE: linux + container: ${{ fromJSON(inputs.test-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Get Depot Tools + timeout-minutes: 5 + run: | + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + - name: Add Depot Tools to PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Download Generated Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + - name: Download Src Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: src_artifacts_linux_${{ env.TARGET_ARCH }} + path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist + run: | + cd src/out/Default + unzip -:o dist.zip + - name: Setup Linux for Headless Testing + run: sh -e /etc/init.d/xvfb start + - name: Run Node.js Tests + run: | + cd src + node electron/script/node-spec-runner.js --default --jUnitDir=junit + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done + nan-tests: + name: Run Nan Tests + runs-on: electron-arc-linux-amd64-4core + timeout-minutes: 20 + env: + TARGET_ARCH: ${{ inputs.target-arch }} + BUILD_TYPE: linux + container: ${{ fromJSON(inputs.test-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Get Depot Tools + timeout-minutes: 5 + run: | + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + - name: Add Depot Tools to PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Download Generated Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + - name: Download Src Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: src_artifacts_linux_${{ env.TARGET_ARCH }} + path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist + run: | + cd src/out/Default + unzip -:o dist.zip + - name: Setup Linux for Headless Testing + run: sh -e /etc/init.d/xvfb start + - name: Run Nan Tests + run: | + cd src + node electron/script/nan-spec-runner.js + - name: Wait for active SSH sessions + shell: bash + if: always() && !cancelled() + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pull-request-labeled.yml b/.github/workflows/pull-request-labeled.yml new file mode 100644 index 0000000000000..f17524034ef69 --- /dev/null +++ b/.github/workflows/pull-request-labeled.yml @@ -0,0 +1,41 @@ +name: Pull Request Labeled + +on: + pull_request_target: + types: [labeled] + +permissions: {} + +jobs: + pull-request-labeled-backport-requested: + name: backport/requested label added + if: github.event.label.name == 'backport/requested 🗳' + runs-on: ubuntu-latest + steps: + - name: Trigger Slack workflow + uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + with: + payload: | + { + "url": "${{ github.event.pull_request.html_url }}" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.BACKPORT_REQUESTED_SLACK_WEBHOOK_URL }} + pull-request-labeled-deprecation-review-complete: + name: deprecation-review/complete label added + if: github.event.label.name == 'deprecation-review/complete ✅' + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 94 + field: Status + field-value: ✅ Reviewed diff --git a/.github/workflows/release_dependency_versions.yml b/.github/workflows/release_dependency_versions.yml deleted file mode 100644 index d03cf272cc30f..0000000000000 --- a/.github/workflows/release_dependency_versions.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Trigger Major Release Dependency Updates - -on: - release: - types: [published] - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -jobs: - check_tag: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Check Tag - run: | - if [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.0\.0$ ]]; then - echo ::set-output name=should_release::true - fi - trigger: - runs-on: ubuntu-latest - needs: check_tag - if: jobs.check_tag.outputs.should_release == 'true' - steps: - - uses: actions/checkout@v3 - - name: Trigger New chromedriver Release - run: | - gh api /repos/:owner/chromedriver/actions/workflows/release.yml/dispatches --input - <<< '{"ref":"main","inputs":{"version":"${{ github.event.release.tag_name }}"}}' - - name: Trigger New mksnapshot Release - run: | - gh api /repos/:owner/mksnapshot/actions/workflows/release.yml/dispatches --input - <<< '{"ref":"main","inputs":{"version":"${{ github.event.release.tag_name }}"}}' diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 0000000000000..60e018326d593 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,55 @@ +name: Scorecards supply-chain security +on: + # Only the default branch is supported. + branch_protection_rule: + schedule: + - cron: '44 17 * * 0' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecards analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Used to receive a badge. + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + # This is a pre-submit / pre-release. + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + + # Publish the results for public repositories to enable scorecard badges. For more details, see + # https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories, `publish_results` will automatically be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@17a820bf2e43b47be2c72b39cc905417bc1ab6d0 # v3.28.6 + with: + sarif_file: results.sarif diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml index 6158b510bb03b..1b96a50153e41 100644 --- a/.github/workflows/semantic.yml +++ b/.github/workflows/semantic.yml @@ -1,7 +1,7 @@ name: "Check Semantic Commit" on: - pull_request_target: + pull_request: types: - opened - edited @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: semantic-pull-request - uses: amannn/action-semantic-pull-request@v4 + uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/stable-prep-items.yml b/.github/workflows/stable-prep-items.yml new file mode 100644 index 0000000000000..64b463630ddd2 --- /dev/null +++ b/.github/workflows/stable-prep-items.yml @@ -0,0 +1,35 @@ +name: Check Stable Prep Items + +on: + schedule: + - cron: '0 */12 * * *' + workflow_dispatch: + +permissions: {} + +jobs: + check-stable-prep-items: + name: Check Stable Prep Items + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Find Newest Release Project Board + id: find-project-number + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + set -eo pipefail + PROJECT_NUMBER=$(gh project list --owner electron --format json | jq -r '.projects | map(select(.title | test("^[0-9]+-x-y$"))) | max_by(.number) | .number') + echo "PROJECT_NUMBER=$PROJECT_NUMBER" >> "$GITHUB_OUTPUT" + - name: Update Completed Stable Prep Items + uses: dsanders11/project-actions/completed-by@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1 + with: + field: Prep Status + field-value: ✅ Complete + project-number: ${{ steps.find-project-number.outputs.PROJECT_NUMBER }} + token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000000..746cc1228e54f --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,52 @@ +name: 'Close stale issues' +on: + workflow_dispatch: + schedule: + # 1:30am every day + - cron: '30 1 * * *' + +permissions: {} + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # tag: v9.1.0 + with: + repo-token: ${{ steps.generate-token.outputs.token }} + days-before-stale: 90 + days-before-close: 30 + stale-issue-label: stale + operations-per-run: 1750 + stale-issue-message: > + This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment! + close-issue-message: > + This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue. + exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed,stale-exempt" + only-pr-labels: not-a-real-label + pending-repro: + runs-on: ubuntu-latest + if: ${{ always() }} + needs: stale + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # tag: v9.1.0 + with: + repo-token: ${{ steps.generate-token.outputs.token }} + days-before-stale: -1 + days-before-close: 10 + remove-stale-when-updated: false + stale-issue-label: blocked/need-repro + stale-pr-label: not-a-real-label + operations-per-run: 1750 + close-issue-message: > + Unfortunately, without a way to reproduce this issue, we're unable to continue investigation. This issue has been closed and will not be monitored further. If you're able to provide a minimal test case that reproduces this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue. diff --git a/.github/workflows/update_appveyor_image.yml b/.github/workflows/update_appveyor_image.yml new file mode 100644 index 0000000000000..efb9e50c7dbb6 --- /dev/null +++ b/.github/workflows/update_appveyor_image.yml @@ -0,0 +1,78 @@ +name: Update AppVeyor Image + +# Run chron daily Mon-Fri +on: + workflow_dispatch: + schedule: + - cron: '0 8 * * 1-5' # runs 8:00 every business day (see https://crontab.guru) + +permissions: {} + +jobs: + bake-appveyor-image: + name: Bake AppVeyor Image + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 + id: generate-token + with: + creds: ${{ secrets.APPVEYOR_UPDATER_GH_APP_CREDS }} + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + token: ${{ steps.generate-token.outputs.token }} + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup Node.js + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + with: + node-version: 20.11.x + - name: Yarn install + run: | + node script/yarn.js install --frozen-lockfile + - name: Set Repo for Commit + run: git config --global --add safe.directory $GITHUB_WORKSPACE + - name: Check AppVeyor Image + env: + APPVEYOR_TOKEN: ${{ secrets.APPVEYOR_TOKEN }} + run: | + node ./script/prepare-appveyor + if [ -f ./image_version.txt ]; then + echo "APPVEYOR_IMAGE_VERSION="$(cat image_version.txt)"" >> $GITHUB_ENV + rm image_version.txt + fi + - name: (Optionally) Update Appveyor Image + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + uses: mikefarah/yq@8bf425b4d1344db7cd469a8d10a390876e0c77fd # v4.45.1 + with: + cmd: | + yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml" + yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor-woa.yml" > "appveyor-woa2.yml" + - name: (Optionally) Generate Commit Diff + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + run: | + diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true + patch -f appveyor.yml < appveyor.diff + rm appveyor2.yml appveyor.diff + git add appveyor.yml + - name: (Optionally) Generate Commit Diff for WOA + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + run: | + diff -w -B appveyor-woa.yml appveyor-woa2.yml > appveyor-woa.diff || true + patch -f appveyor-woa.yml < appveyor-woa.diff + rm appveyor-woa2.yml appveyor-woa.diff + git add appveyor-woa.yml + - name: (Optionally) Commit to Branch + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + uses: dsanders11/github-app-commit-action@43de6da2f4d927e997c0784c7a0b61bd19ad6aac # v1.5.0 + with: + message: 'build: update appveyor image to latest version' + ref: bump-appveyor-image + token: ${{ steps.generate-token.outputs.token }} + - name: (Optionally) Create Pull Request + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + run: | + printf "This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.\n\nNotes: none" | gh pr create --head bump-appveyor-image --label no-backport --label semver/none --title 'build: update appveyor image to latest version' --body-file=- + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/windows-publish.yml b/.github/workflows/windows-publish.yml new file mode 100644 index 0000000000000..1ee5845eaff40 --- /dev/null +++ b/.github/workflows/windows-publish.yml @@ -0,0 +1,84 @@ +name: Publish Windows + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: 'bc2f48b2415a670de18d13605b1cf0eb5fdbaae1' + required: true + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-windows-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +jobs: + checkout-windows: + runs-on: electron-arc-linux-amd64-32core + container: + image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + options: --user root --device /dev/fuse --cap-add SYS_ADMIN + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + env: + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' + TARGET_OS: 'win' + ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1' + outputs: + build-image-sha: ${{ inputs.build-image-sha }} + steps: + - name: Checkout Electron + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + + publish-x64-win: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-windows + with: + environment: production-release + build-runs-on: electron-arc-windows-amd64-16core + target-platform: win + target-arch: x64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-win: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-windows + with: + environment: production-release + build-runs-on: electron-arc-windows-amd64-16core + target-platform: win + target-arch: arm64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-x86-win: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + needs: checkout-windows + with: + environment: production-release + build-runs-on: electron-arc-windows-amd64-16core + target-platform: win + target-arch: x86 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.gitignore b/.gitignore index e2168896e2ce0..88d3b8b0a9870 100644 --- a/.gitignore +++ b/.gitignore @@ -41,16 +41,15 @@ spec/.hash .eslintcache* # Generated native addon files -/spec-main/fixtures/native-addon/echo/build/ +/spec/fixtures/native-addon/echo/build/ # If someone runs tsc this is where stuff will end up ts-gen # Used to accelerate CI builds .depshash -.depshash-target # Used to accelerate builds after sync patches/mtime-cache.json -spec/fixtures/logo.png \ No newline at end of file +spec/fixtures/logo.png diff --git a/.lint-roller.json b/.lint-roller.json new file mode 100644 index 0000000000000..bdbbd9172cff0 --- /dev/null +++ b/.lint-roller.json @@ -0,0 +1,13 @@ +{ + "markdown-ts-check": { + "defaultImports": [ + "import * as childProcess from 'node:child_process'", + "import * as fs from 'node:fs'", + "import * as path from 'node:path'", + "import { app, autoUpdater, contextBridge, crashReporter, dialog, BrowserWindow, ipcMain, ipcRenderer, Menu, MessageChannelMain, nativeImage, net, protocol, session, systemPreferences, Tray, utilityProcess, webFrame, webFrameMain } from 'electron'" + ], + "typings": [ + "../electron.d.ts" + ] + } +} diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000000000..aa44ae70b8780 --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,31 @@ +{ + "config": { + "extends": "@electron/lint-roller/configs/markdownlint.json", + "link-image-style": { + "autolink": false, + "shortcut": false + }, + "MD049": { + "style": "underscore" + }, + "no-angle-brackets": true, + "no-curly-braces": true, + "no-inline-html": { + "allowed_elements": [ + "br", + "details", + "img", + "li", + "summary", + "ul", + "unknown", + "Tabs", + "TabItem" + ] + }, + "no-newline-in-links": true + }, + "customRules": [ + "@electron/lint-roller/markdownlint-rules/" + ] +} diff --git a/.markdownlint.autofix.json b/.markdownlint.autofix.json deleted file mode 100644 index 7bb678b286387..0000000000000 --- a/.markdownlint.autofix.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "default": false, - "no-trailing-spaces": { - "br_spaces": 0 - } -} diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index 495df656c2cd3..0000000000000 --- a/.markdownlint.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "commands-show-output": false, - "first-line-h1": false, - "header-increment": false, - "line-length": { - "code_blocks": false, - "tables": false, - "stern": true, - "line_length": -1 - }, - "no-bare-urls": false, - "no-blanks-blockquote": false, - "no-duplicate-header": { - "allow_different_nesting": true - }, - "no-emphasis-as-header": false, - "no-hard-tabs": { - "code_blocks": false - }, - "no-space-in-emphasis": false, - "no-trailing-punctuation": false, - "no-trailing-spaces": { - "br_spaces": 0 - }, - "single-h1": false, - "no-inline-html": false -} diff --git a/.nvmrc b/.nvmrc index 8351c19397f4f..209e3ef4b6247 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14 +20 diff --git a/BUILD.gn b/BUILD.gn index e1a99dfadb4d9..fdd722ea68cca 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,7 +1,7 @@ import("//build/config/locales.gni") import("//build/config/ui.gni") import("//build/config/win/manifest.gni") -import("//components/os_crypt/features.gni") +import("//components/os_crypt/sync/features.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//content/public/app/mac_helpers.gni") import("//extensions/buildflags/buildflags.gni") @@ -9,6 +9,7 @@ import("//pdf/features.gni") import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") import("//testing/test.gni") +import("//third_party/electron_node/node.gni") import("//third_party/ffmpeg/ffmpeg_options.gni") import("//tools/generate_library_loader/generate_library_loader.gni") import("//tools/grit/grit_rule.gni") @@ -28,16 +29,16 @@ import("filenames.gni") import("filenames.hunspell.gni") import("filenames.libcxx.gni") import("filenames.libcxxabi.gni") +import("js2c_toolchain.gni") if (is_mac) { import("//build/config/mac/rules.gni") import("//third_party/icu/config.gni") - import("//ui/gl/features.gni") import("//v8/gni/v8.gni") import("build/rules.gni") assert( - mac_deployment_target == "10.13", + mac_deployment_target == "11.0", "Chromium has updated the mac_deployment_target, please update this assert, update the supported versions documentation (docs/tutorial/support.md) and flag this as a breaking change") } @@ -73,23 +74,19 @@ if (is_linux) { "notify_notification_set_image_from_pixbuf", "notify_notification_set_timeout", "notify_notification_set_urgency", - "notify_notification_set_hint_string", + "notify_notification_set_hint", "notify_notification_show", "notify_notification_close", ] } - # Generates electron_gtk_stubs.h header which contains - # stubs for extracting function ptrs from the gtk library. - # Function signatures for which stubs are required should be - # declared in electron_gtk.sigs, currently this file contains - # signatures for the functions used with native file chooser - # implementation. In future, this file can be extended to contain - # gtk4 stubs to switch gtk version in runtime. + # Generates headers which contain stubs for extracting function ptrs + # from the gtk library. Function signatures for which stubs are + # required should be declared in the sig files. generate_stubs("electron_gtk_stubs") { sigs = [ + "shell/browser/ui/electron_gdk.sigs", "shell/browser/ui/electron_gdk_pixbuf.sigs", - "shell/browser/ui/electron_gtk.sigs", ] extra_header = "shell/browser/ui/electron_gtk.fragment" output_name = "electron_gtk_stubs" @@ -99,15 +96,31 @@ if (is_linux) { } } -declare_args() { - use_prebuilt_v8_context_snapshot = false -} - branding = read_file("shell/app/BRANDING.json", "json") electron_project_name = branding.project_name electron_product_name = branding.product_name electron_mac_bundle_id = branding.mac_bundle_id +if (override_electron_version != "") { + electron_version = override_electron_version +} else { + # When building from source code tarball there is no git tag available and + # builders must explicitly pass override_electron_version in gn args. + # This read_file call will assert if there is no git information, without it + # gn will generate a malformed build configuration and ninja will get into + # infinite loop. + read_file(".git/packed-refs", "string") + + # Set electron version from git tag. + electron_version = exec_script("script/get-git-version.py", + [], + "trim string", + [ + ".git/packed-refs", + ".git/HEAD", + ]) +} + if (is_mas_build) { assert(is_mac, "It doesn't make sense to build a MAS build on a non-mac platform") @@ -148,15 +161,6 @@ npm_action("build_electron_definitions") { outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ] } -webpack_build("electron_asar_bundle") { - deps = [ ":build_electron_definitions" ] - - inputs = auto_filenames.asar_bundle_deps - - config_file = "//electron/build/webpack/webpack.config.asar.js" - out_file = "$target_gen_dir/js2c/asar_bundle.js" -} - webpack_build("electron_browser_bundle") { deps = [ ":build_electron_definitions" ] @@ -202,32 +206,57 @@ webpack_build("electron_isolated_renderer_bundle") { out_file = "$target_gen_dir/js2c/isolated_bundle.js" } +webpack_build("electron_node_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.node_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.node.js" + out_file = "$target_gen_dir/js2c/node_init.js" +} + +webpack_build("electron_utility_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.utility_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.utility.js" + out_file = "$target_gen_dir/js2c/utility_init.js" +} + action("electron_js2c") { deps = [ - ":electron_asar_bundle", ":electron_browser_bundle", ":electron_isolated_renderer_bundle", + ":electron_node_bundle", ":electron_renderer_bundle", ":electron_sandboxed_renderer_bundle", + ":electron_utility_bundle", ":electron_worker_bundle", + "//third_party/electron_node:node_js2c($electron_js2c_toolchain)", ] sources = [ - "$target_gen_dir/js2c/asar_bundle.js", "$target_gen_dir/js2c/browser_init.js", "$target_gen_dir/js2c/isolated_bundle.js", + "$target_gen_dir/js2c/node_init.js", "$target_gen_dir/js2c/renderer_init.js", "$target_gen_dir/js2c/sandbox_bundle.js", + "$target_gen_dir/js2c/utility_init.js", "$target_gen_dir/js2c/worker_init.js", ] - inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ] + inputs = sources outputs = [ "$root_gen_dir/electron_natives.cc" ] script = "build/js2c.py" - args = [ rebase_path("//third_party/electron_node") ] + - rebase_path(outputs, root_build_dir) + - rebase_path(sources, root_build_dir) + out_dir = + get_label_info(":anything($electron_js2c_toolchain)", "root_out_dir") + args = [ + rebase_path("$out_dir/node_js2c"), + rebase_path("$root_gen_dir"), + ] + rebase_path(outputs, root_gen_dir) + + rebase_path(sources, root_gen_dir) } action("generate_config_gypi") { @@ -302,12 +331,9 @@ npm_action("electron_version_args") { outputs = [ "$target_gen_dir/electron_version.args" ] - args = rebase_path(outputs) + args = rebase_path(outputs) + [ "$electron_version" ] - inputs = [ - "ELECTRON_VERSION", - "script/generate-version-json.js", - ] + inputs = [ "script/generate-version-json.js" ] } templated_file("electron_version_header") { @@ -319,6 +345,39 @@ templated_file("electron_version_header") { args_files = get_target_outputs(":electron_version_args") } +templated_file("electron_win_rc") { + deps = [ ":electron_version_args" ] + + template = "build/templates/electron_rc.tmpl" + output = "$target_gen_dir/win-resources/electron.rc" + + args_files = get_target_outputs(":electron_version_args") +} + +copy("electron_win_resource_files") { + sources = [ + "shell/browser/resources/win/electron.ico", + "shell/browser/resources/win/resource.h", + ] + outputs = [ "$target_gen_dir/win-resources/{{source_file_part}}" ] +} + +templated_file("electron_version_file") { + deps = [ ":electron_version_args" ] + + template = "build/templates/version_string.tmpl" + output = "$root_build_dir/version" + + args_files = get_target_outputs(":electron_version_args") +} + +group("electron_win32_resources") { + public_deps = [ + ":electron_win_rc", + ":electron_win_resource_files", + ] +} + action("electron_fuses") { script = "build/fuses/build.py" @@ -350,8 +409,10 @@ action("electron_generate_node_defines") { } source_set("electron_lib") { - configs += [ "//v8:external_startup_data" ] - configs += [ "//third_party/electron_node:node_internals" ] + configs += [ + "//v8:external_startup_data", + "//third_party/electron_node:node_external_config", + ] public_configs = [ ":branding", @@ -367,7 +428,9 @@ source_set("electron_lib") { "buildflags", "chromium_src:chrome", "chromium_src:chrome_spellchecker", - "shell/common/api:mojo", + "shell/common:mojo", + "shell/common:plugin", + "shell/services/node/public/mojom", "//base:base_static", "//base/allocator:buildflags", "//chrome:strings", @@ -375,7 +438,9 @@ source_set("electron_lib") { "//chrome/app/resources:platform_locale_settings", "//components/autofill/core/common:features", "//components/certificate_transparency", + "//components/compose:buildflags", "//components/embedder_support:browser_util", + "//components/input:input", "//components/language/core/browser", "//components/net_log", "//components/network_hints/browser", @@ -383,7 +448,9 @@ source_set("electron_lib") { "//components/network_hints/renderer", "//components/network_session_configurator/common", "//components/omnibox/browser:buildflags", - "//components/os_crypt", + "//components/os_crypt/async/browser", + "//components/os_crypt/async/browser:key_provider_interface", + "//components/os_crypt/sync", "//components/pref_registry", "//components/prefs", "//components/security_state/content", @@ -402,36 +469,39 @@ source_set("electron_lib") { "//gin", "//media/capture/mojom:video_capture", "//media/mojo/mojom", + "//media/mojo/mojom:web_speech_recognition", "//net:extras", "//net:net_resources", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/shared_impl", "//printing/buildflags", + "//services/device/public/cpp/bluetooth:bluetooth", "//services/device/public/cpp/geolocation", "//services/device/public/cpp/hid", "//services/device/public/mojom", "//services/proxy_resolver:lib", "//services/video_capture/public/mojom:constants", "//services/viz/privileged/mojom/compositing", + "//services/viz/public/mojom", "//skia", "//third_party/blink/public:blink", "//third_party/blink/public:blink_devtools_inspector_resources", "//third_party/blink/public/platform/media", "//third_party/boringssl", - "//third_party/electron_node:node_lib", + "//third_party/electron_node:libnode", "//third_party/inspector_protocol:crdtp", "//third_party/leveldatabase", "//third_party/libyuv", "//third_party/webrtc_overrides:webrtc_component", "//third_party/widevine/cdm:headers", "//third_party/zlib/google:zip", + "//ui/base:ozone_buildflags", "//ui/base/idle", + "//ui/compositor", "//ui/events:dom_keycode_converter", "//ui/gl", "//ui/native_theme", "//ui/shell_dialogs", "//ui/views", + "//ui/views/controls/webview", "//v8", "//v8:v8_libplatform", ] @@ -451,7 +521,10 @@ source_set("electron_lib") { "//third_party/blink/renderer", ] - defines = [ "V8_DEPRECATION_WARNINGS" ] + defines = [ + "BLINK_MOJO_IMPL=1", + "V8_DEPRECATION_WARNINGS", + ] libs = [] if (is_linux) { @@ -465,6 +538,8 @@ source_set("electron_lib") { ] } + deps += [ "//electron/build/config:generate_mas_config" ] + sources = filenames.lib_sources if (is_win) { sources += filenames.lib_sources_win @@ -493,18 +568,11 @@ source_set("electron_lib") { ] } - if (is_linux) { - deps += [ - "//components/crash/content/browser", - "//ui/gtk:gtk_config", - ] - } - if (is_mac) { deps += [ "//components/remote_cocoa/app_shim", "//components/remote_cocoa/browser", - "//content/common:mac_helpers", + "//content/browser:mac_helpers", "//ui/accelerated_widget_mac", ] @@ -513,6 +581,7 @@ source_set("electron_lib") { } frameworks = [ + "AuthenticationServices.framework", "AVFoundation.framework", "Carbon.framework", "LocalAuthentication.framework", @@ -533,7 +602,6 @@ source_set("electron_lib") { if (is_mas_build) { sources += [ "shell/browser/api/electron_api_app_mas.mm" ] sources -= [ "shell/browser/auto_updater_mac.mm" ] - defines += [ "MAS_BUILD" ] sources -= [ "shell/app/electron_crash_reporter_client.cc", "shell/app/electron_crash_reporter_client.h", @@ -562,14 +630,16 @@ source_set("electron_lib") { ":electron_gtk_stubs", ":libnotify_loader", "//build/config/linux/gtk", + "//components/crash/content/browser", "//dbus", "//device/bluetooth", + "//third_party/crashpad/crashpad/client", "//ui/base/ime/linux", "//ui/events/devices/x11", "//ui/events/platform/x11", + "//ui/gtk:gtk_config", "//ui/linux:linux_ui", "//ui/linux:linux_ui_factory", - "//ui/views/controls/webview", "//ui/wm", ] if (ozone_platform_x11) { @@ -588,26 +658,17 @@ source_set("electron_lib") { sources += [ "shell/browser/certificate_manager_model.cc", "shell/browser/certificate_manager_model.h", - "shell/browser/ui/gtk/app_indicator_icon.cc", - "shell/browser/ui/gtk/app_indicator_icon.h", - "shell/browser/ui/gtk/app_indicator_icon_menu.cc", - "shell/browser/ui/gtk/app_indicator_icon_menu.h", - "shell/browser/ui/gtk/gtk_status_icon.cc", - "shell/browser/ui/gtk/gtk_status_icon.h", - "shell/browser/ui/gtk/menu_util.cc", - "shell/browser/ui/gtk/menu_util.h", - "shell/browser/ui/gtk/status_icon.cc", - "shell/browser/ui/gtk/status_icon.h", "shell/browser/ui/gtk_util.cc", "shell/browser/ui/gtk_util.h", ] } if (is_win) { libs += [ "dwmapi.lib" ] + sources += [ "shell/common/asar/archive_win.cc" ] deps += [ + "//components/app_launch_prefetch", "//components/crash/core/app:crash_export_thunks", "//ui/native_theme:native_theme_browser", - "//ui/views/controls/webview", "//ui/wm", "//ui/wm/public", ] @@ -618,64 +679,20 @@ source_set("electron_lib") { } if (enable_plugins) { - deps += [ "chromium_src:plugins" ] - sources += [ - "shell/renderer/pepper_helper.cc", - "shell/renderer/pepper_helper.h", - ] - } - - if (enable_run_as_node) { - sources += [ - "shell/app/node_main.cc", - "shell/app/node_main.h", - ] - } - - if (enable_osr) { - sources += [ - "shell/browser/osr/osr_host_display_client.cc", - "shell/browser/osr/osr_host_display_client.h", - "shell/browser/osr/osr_render_widget_host_view.cc", - "shell/browser/osr/osr_render_widget_host_view.h", - "shell/browser/osr/osr_video_consumer.cc", - "shell/browser/osr/osr_video_consumer.h", - "shell/browser/osr/osr_view_proxy.cc", - "shell/browser/osr/osr_view_proxy.h", - "shell/browser/osr/osr_web_contents_view.cc", - "shell/browser/osr/osr_web_contents_view.h", - ] - if (is_mac) { - sources += [ - "shell/browser/osr/osr_host_display_client_mac.mm", - "shell/browser/osr/osr_web_contents_view_mac.mm", - ] - } - deps += [ - "//components/viz/service", - "//services/viz/public/mojom", - "//ui/compositor", - ] - } - - if (enable_desktop_capturer) { sources += [ - "shell/browser/api/electron_api_desktop_capturer.cc", - "shell/browser/api/electron_api_desktop_capturer.h", + "shell/browser/electron_plugin_info_host_impl.cc", + "shell/browser/electron_plugin_info_host_impl.h", + "shell/common/plugin_info.cc", + "shell/common/plugin_info.h", ] } - if (enable_views_api) { - sources += [ - "shell/browser/api/views/electron_api_image_view.cc", - "shell/browser/api/views/electron_api_image_view.h", - ] - } - - if (enable_basic_printing) { + if (enable_printing) { sources += [ "shell/browser/printing/print_view_manager_electron.cc", "shell/browser/printing/print_view_manager_electron.h", + "shell/browser/printing/printing_utils.cc", + "shell/browser/printing/printing_utils.h", "shell/renderer/printing/print_render_frame_helper_delegate.cc", "shell/renderer/printing/print_render_frame_helper_delegate.h", ] @@ -695,10 +712,11 @@ source_set("electron_lib") { "shell/common/extensions/api", "shell/common/extensions/api:extensions_features", "//chrome/browser/resources:component_extension_resources", + "//components/guest_view/common:mojom", "//components/update_client:update_client", "//components/zoom", "//extensions/browser", - "//extensions/browser:core_api_provider", + "//extensions/browser/api:api_provider", "//extensions/browser/updater", "//extensions/common", "//extensions/common:core_api_provider", @@ -719,13 +737,17 @@ source_set("electron_lib") { "//chrome/browser/resources/pdf:resources", "//components/pdf/browser", "//components/pdf/browser:interceptors", - "//components/pdf/common", + "//components/pdf/common:constants", + "//components/pdf/common:util", "//components/pdf/renderer", "//pdf", + "//pdf:content_restriction", ] sources += [ - "shell/browser/electron_pdf_web_contents_helper_client.cc", - "shell/browser/electron_pdf_web_contents_helper_client.h", + "shell/browser/electron_pdf_document_helper_client.cc", + "shell/browser/electron_pdf_document_helper_client.h", + "shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc", + "shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h", ] } @@ -750,21 +772,11 @@ if (is_mac) { electron_helper_name = "$electron_product_name Helper" electron_login_helper_name = "$electron_product_name Login Helper" electron_framework_version = "A" - electron_version = read_file("ELECTRON_VERSION", "trim string") mac_xib_bundle_data("electron_xibs") { sources = [ "shell/common/resources/mac/MainMenu.xib" ] } - action("fake_v8_context_snapshot_generator") { - script = "build/fake_v8_context_snapshot_generator.py" - args = [ - rebase_path("$root_out_dir/$v8_context_snapshot_filename"), - rebase_path("$root_out_dir/fake/$v8_context_snapshot_filename"), - ] - outputs = [ "$root_out_dir/fake/$v8_context_snapshot_filename" ] - } - bundle_data("electron_framework_resources") { public_deps = [ ":packed_resources" ] sources = [] @@ -775,13 +787,8 @@ if (is_mac) { if (v8_use_external_startup_data) { public_deps += [ "//v8" ] if (use_v8_context_snapshot) { - if (use_prebuilt_v8_context_snapshot) { - sources += [ "$root_out_dir/fake/$v8_context_snapshot_filename" ] - public_deps += [ ":fake_v8_context_snapshot_generator" ] - } else { - sources += [ "$root_out_dir/$v8_context_snapshot_filename" ] - public_deps += [ "//tools/v8_context_snapshot" ] - } + sources += [ "$root_out_dir/$v8_context_snapshot_filename" ] + public_deps += [ "//tools/v8_context_snapshot" ] } else { sources += [ "$root_out_dir/snapshot_blob.bin" ] } @@ -801,37 +808,33 @@ if (is_mac) { group("electron_framework_libraries") { } } - if (use_egl) { - # Add the ANGLE .dylibs in the Libraries directory of the Framework. - bundle_data("electron_angle_binaries") { - sources = [ - "$root_out_dir/egl_intermediates/libEGL.dylib", - "$root_out_dir/egl_intermediates/libGLESv2.dylib", - ] - outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] - public_deps = [ "//ui/gl:angle_library_copy" ] - } - # Add the SwiftShader .dylibs in the Libraries directory of the Framework. - bundle_data("electron_swiftshader_binaries") { - sources = [ - "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib", - "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json", - ] - outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] - public_deps = [ "//ui/gl:swiftshader_vk_library_copy" ] - } + # Add the ANGLE .dylibs in the Libraries directory of the Framework. + bundle_data("electron_angle_binaries") { + sources = [ + "$root_out_dir/egl_intermediates/libEGL.dylib", + "$root_out_dir/egl_intermediates/libGLESv2.dylib", + ] + outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] + public_deps = [ "//ui/gl:angle_library_copy" ] } + + # Add the SwiftShader .dylibs in the Libraries directory of the Framework. + bundle_data("electron_swiftshader_binaries") { + sources = [ + "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib", + "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json", + ] + outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] + public_deps = [ "//ui/gl:swiftshader_vk_library_copy" ] + } + group("electron_angle_library") { - if (use_egl) { - deps = [ ":electron_angle_binaries" ] - } + deps = [ ":electron_angle_binaries" ] } group("electron_swiftshader_library") { - if (use_egl) { - deps = [ ":electron_swiftshader_binaries" ] - } + deps = [ ":electron_swiftshader_binaries" ] } bundle_data("electron_crashpad_helper") { @@ -844,7 +847,7 @@ if (is_mac) { if (is_asan) { # crashpad_handler requires the ASan runtime at its @executable_path. sources += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ] - public_deps += [ "//build/config/sanitizers:copy_asan_runtime" ] + public_deps += [ "//build/config/sanitizers:copy_sanitizer_runtime" ] } } @@ -868,6 +871,7 @@ if (is_mac) { ":electron_framework_resources", ":electron_swiftshader_library", ":electron_xibs", + "//third_party/electron_node:libnode", ] if (!is_mas_build) { deps += [ ":electron_crashpad_helper" ] @@ -881,11 +885,7 @@ if (is_mac) { include_dirs = [ "." ] sources = filenames.framework_sources - frameworks = [] - - if (enable_osr) { - frameworks += [ "IOSurface.framework" ] - } + frameworks = [ "IOSurface.framework" ] ldflags = [ "-Wl,-install_name,@rpath/$output_name.framework/$output_name", @@ -917,7 +917,7 @@ if (is_mac) { output_name = electron_helper_name + invoker.helper_name_suffix deps = [ ":electron_framework+link", - "//base/allocator:early_zone_registration_mac", + "//electron/build/config:generate_mas_config", ] if (!is_mas_build) { deps += [ "//sandbox/mac:seatbelt" ] @@ -927,7 +927,6 @@ if (is_mac) { "shell/app/electron_main_mac.cc", "shell/app/uv_stdio_fix.cc", "shell/app/uv_stdio_fix.h", - "shell/common/electron_constants.cc", ] include_dirs = [ "." ] info_plist = "shell/renderer/resources/mac/Info.plist" @@ -1078,7 +1077,7 @@ if (is_mac) { ":electron_app_plist", ":electron_app_resources", ":electron_fuses", - "//base/allocator:early_zone_registration_mac", + "//electron/build/config:generate_mas_config", "//electron/buildflags", ] if (is_mas_build) { @@ -1191,10 +1190,12 @@ if (is_mac) { ":default_app_asar", ":electron_app_manifest", ":electron_lib", + ":electron_win32_resources", ":packed_resources", "//components/crash/core/app", "//content:sandbox_helper_win", "//electron/buildflags", + "//third_party/electron_node:libnode", "//ui/strings", ] @@ -1224,13 +1225,12 @@ if (is_mac) { if (is_win) { sources += [ - # TODO: we should be generating our .rc files more like how chrome does - "shell/browser/resources/win/electron.rc", + "$target_gen_dir/win-resources/electron.rc", "shell/browser/resources/win/resource.h", ] deps += [ - "//components/browser_watcher:browser_watcher_client", + "//chrome/app:exit_code_watcher", "//components/crash/core/app:run_as_crashpad_handler", ] @@ -1329,25 +1329,6 @@ if (is_mac) { } } -test("shell_browser_ui_unittests") { - sources = [ - "//electron/shell/browser/ui/accelerator_util_unittests.cc", - "//electron/shell/browser/ui/run_all_unittests.cc", - ] - - configs += [ ":electron_lib_config" ] - - deps = [ - ":electron_lib", - "//base", - "//base/test:test_support", - "//testing/gmock", - "//testing/gtest", - "//ui/base", - "//ui/strings", - ] -} - template("dist_zip") { _runtime_deps_target = "${target_name}__deps" _runtime_deps_file = @@ -1407,15 +1388,10 @@ group("licenses") { ] } -copy("electron_version") { - sources = [ "ELECTRON_VERSION" ] - outputs = [ "$root_build_dir/version" ] -} - dist_zip("electron_dist_zip") { data_deps = [ ":electron_app", - ":electron_version", + ":electron_version_file", ":licenses", ] if (is_linux) { @@ -1433,7 +1409,7 @@ dist_zip("electron_ffmpeg_zip") { electron_chromedriver_deps = [ ":licenses", - "//chrome/test/chromedriver", + "//chrome/test/chromedriver:chromedriver_server", "//electron/buildflags", ] @@ -1482,8 +1458,10 @@ dist_zip("hunspell_dictionaries_zip") { } copy("libcxx_headers") { - sources = libcxx_headers + libcxx_licenses + - [ "//buildtools/third_party/libc++/__config_site" ] + sources = libcxx_headers + libcxx_licenses + [ + "//buildtools/third_party/libc++/__assertion_handler", + "//buildtools/third_party/libc++/__config_site", + ] outputs = [ "$target_gen_dir/electron_libcxx_include/{{source_root_relative_dir}}/{{source_file_part}}" ] } @@ -1491,8 +1469,9 @@ dist_zip("libcxx_headers_zip") { data_deps = [ ":libcxx_headers" ] deps = data_deps flatten = true - flatten_relative_to = rebase_path( - "$target_gen_dir/electron_libcxx_include/buildtools/third_party/libc++/trunk", + flatten_relative_to = + rebase_path( + "$target_gen_dir/electron_libcxx_include/third_party/libc++/src", "$root_out_dir") outputs = [ "$root_build_dir/libcxx_headers.zip" ] @@ -1508,7 +1487,7 @@ dist_zip("libcxxabi_headers_zip") { deps = data_deps flatten = true flatten_relative_to = rebase_path( - "$target_gen_dir/electron_libcxxabi_include/buildtools/third_party/libc++abi/trunk", + "$target_gen_dir/electron_libcxxabi_include/third_party/libc++abi/src", "$root_out_dir") outputs = [ "$root_build_dir/libcxxabi_headers.zip" ] @@ -1524,3 +1503,64 @@ action("libcxx_objects_zip") { group("electron") { public_deps = [ ":electron_app" ] } + +##### node_headers + +node_dir = "../third_party/electron_node" +node_headers_dir = "$root_gen_dir/node_headers" + +copy("zlib_headers") { + sources = [ + "$node_dir/deps/zlib/zconf.h", + "$node_dir/deps/zlib/zlib.h", + ] + outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ] +} + +copy("node_gypi_headers") { + deps = [ ":generate_config_gypi" ] + sources = [ + "$node_dir/common.gypi", + "$root_gen_dir/config.gypi", + ] + outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ] +} + +action("node_version_header") { + inputs = [ "$node_dir/src/node_version.h" ] + outputs = [ "$node_headers_dir/include/node/node_version.h" ] + script = "script/node/generate_node_version_header.py" + args = rebase_path(inputs) + rebase_path(outputs) + if (node_module_version != "") { + args += [ "$node_module_version" ] + } +} + +action("generate_node_headers") { + deps = [ ":generate_config_gypi" ] + script = "script/node/generate_node_headers.py" + outputs = [ "$root_gen_dir/node_headers.json" ] +} + +action("tar_node_headers") { + deps = [ ":copy_node_headers" ] + outputs = [ "$root_gen_dir/node_headers.tar.gz" ] + script = "script/tar.py" + args = [ + rebase_path("$root_gen_dir/node_headers"), + rebase_path(outputs[0]), + ] +} + +group("copy_node_headers") { + public_deps = [ + ":generate_node_headers", + ":node_gypi_headers", + ":node_version_header", + ":zlib_headers", + ] +} + +group("node_headers") { + public_deps = [ ":tar_node_headers" ] +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 3a65cd1249f8a..819fb406e6ef1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -125,8 +125,8 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). [homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c1223308ee58..3cc4fcca3a2c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ propose changes to this document in a pull request. ## [Issues](https://electronjs.org/docs/development/issues) -Issues are created [here](https://github.com/electron/electron/issues/new). +Issues are created [here](https://github.com/electron/electron/issues/new/choose). * [How to Contribute in Issues](https://electronjs.org/docs/development/issues#how-to-contribute-in-issues) * [Asking for General Help](https://electronjs.org/docs/development/issues#asking-for-general-help) @@ -28,7 +28,7 @@ _If an issue has been closed and you still feel it's relevant, feel free to ping ### Languages -We accept issues in *any* language. +We accept issues in _any_ language. When an issue is posted in a language besides English, it is acceptable and encouraged to post an English-translated copy as a reply. Anyone may post the translated reply. In most cases, a quick pass through translation software is sufficient. @@ -60,6 +60,10 @@ dependencies, and tools contained in the `electron/electron` repository. * [Step 11: Landing](https://electronjs.org/docs/development/pull-requests#step-11-landing) * [Continuous Integration Testing](https://electronjs.org/docs/development/pull-requests#continuous-integration-testing) +### Dependencies Upgrades Policy + +Dependencies in Electron's `package.json` or `yarn.lock` files should only be altered by maintainers. For security reasons, we will not accept PRs that alter our `package.json` or `yarn.lock` files. We invite contributors to make requests updating these files in our issue tracker. If the change is significantly complicated, draft PRs are welcome, with the understanding that these PRs will be closed in favor of a duplicate PR submitted by an Electron maintainer. + ## Style Guides See [Coding Style](https://electronjs.org/docs/development/coding-style) for information about which standards Electron adheres to in different parts of its codebase. diff --git a/DEPS b/DEPS index a0ce155d6a56e..e5df91a3c6257 100644 --- a/DEPS +++ b/DEPS @@ -2,13 +2,19 @@ gclient_gn_args_from = 'src' vars = { 'chromium_version': - '105.0.5187.0', + '134.0.6968.0', 'node_version': - 'v16.16.0', + 'v22.11.0', 'nan_version': - '16fa32231e2ccd89d2804b3f765319128b20c4ac', + 'e14bdcd1f72d62bca1d541b66da43130384ec213', 'squirrel.mac_version': '0e5d146ba13101a1302d59ea6e6e0b3cace4ae38', + 'reactiveobjc_version': + '74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', + 'mantle_version': + '78d3966b3c331292ea29ec38661b25df0a245948', + 'engflow_reclient_configs_version': + '955335c30a752e9ef7bff375baab5e0819b6c00d', 'pyyaml_version': '3.12', @@ -17,6 +23,12 @@ vars = { 'nodejs_git': 'https://github.com/nodejs', 'yaml_git': 'https://github.com/yaml', 'squirrel_git': 'https://github.com/Squirrel', + 'reactiveobjc_git': 'https://github.com/ReactiveCocoa', + 'mantle_git': 'https://github.com/Mantle', + 'engflow_git': 'https://github.com/EngFlow', + + # The path of the sysroots.json file. + 'sysroots_json_path': 'electron/script/sysroots.json', # KEEP IN SYNC WITH utils.js FILE 'yarn_version': '1.15.2', @@ -36,6 +48,9 @@ vars = { # It's only needed to parse the native tests configurations. 'checkout_pyyaml': False, + # Can be used to disable the sysroot hooks. + 'install_sysroot': True, + 'use_rts': False, 'mac_xcode_version': 'default', @@ -87,12 +102,16 @@ deps = { 'condition': 'process_deps', }, 'src/third_party/squirrel.mac/vendor/ReactiveObjC': { - 'url': 'https://github.com/ReactiveCocoa/ReactiveObjC.git@74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', + 'url': Var("reactiveobjc_git") + '/ReactiveObjC.git@' + Var("reactiveobjc_version"), 'condition': 'process_deps' }, 'src/third_party/squirrel.mac/vendor/Mantle': { - 'url': 'https://github.com/Mantle/Mantle.git@78d3966b3c331292ea29ec38661b25df0a245948', + 'url': Var("mantle_git") + '/Mantle.git@' + Var("mantle_version"), 'condition': 'process_deps', + }, + 'src/third_party/engflow-reclient-configs': { + 'url': Var("engflow_git") + '/reclient-configs.git@' + Var("engflow_reclient_configs_version"), + 'condition': 'process_deps' } } @@ -145,9 +164,56 @@ hooks = [ 'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python3", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);', ], }, + { + 'name': 'sysroot_arm', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_arm', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=arm'], + }, + { + 'name': 'sysroot_arm64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_arm64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=arm64'], + }, + { + 'name': 'sysroot_x86', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and (checkout_x86 or checkout_x64)', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=x86'], + }, + { + 'name': 'sysroot_mips', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_mips', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=mips'], + }, + { + 'name': 'sysroot_mips64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_mips64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=mips64el'], + }, + { + 'name': 'sysroot_x64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_x64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=x64'], + }, ] recursedeps = [ 'src', - 'src/third_party/squirrel.mac', ] diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION deleted file mode 100644 index b762cd1442d3a..0000000000000 --- a/ELECTRON_VERSION +++ /dev/null @@ -1 +0,0 @@ -22.0.0-nightly.20220811 \ No newline at end of file diff --git a/README.md b/README.md index 0b1f4636332ea..7d5f9cc87013a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org) -[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/main.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/main) +[![GitHub Actions Build Status](https://github.com/electron/electron/actions/workflows/build.yml/badge.svg)](https://github.com/electron/electron/actions/workflows/build.yml) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/main?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main) [![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs) @@ -9,10 +9,10 @@ View these docs in other languages on our [Crowdin](https://crowdin.com/project/ The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and -[Chromium](https://www.chromium.org) and is used by the [Atom -editor](https://github.com/atom/atom) and many other [apps](https://electronjs.org/apps). +[Chromium](https://www.chromium.org) and is used by the +[Visual Studio Code](https://github.com/Microsoft/vscode/) and many other [apps](https://electronjs.org/apps). -Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important +Follow [@electronjs](https://twitter.com/electronjs) on Twitter for important announcements. This project adheres to the Contributor Covenant @@ -38,12 +38,12 @@ For more installation options and troubleshooting tips, see Each Electron release provides binaries for macOS, Windows, and Linux. -* macOS (El Capitan and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11. -* Windows (Windows 7 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. +* macOS (Big Sur and up): Electron provides 64-bit Intel and Apple Silicon / ARM binaries for macOS. +* Windows (Windows 10 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. Support for Windows 7, 8 and 8.1 was [removed in Electron 23, in line with Chromium's Windows deprecation policy](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). * Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on: - * Ubuntu 14.04 and newer - * Fedora 24 and newer - * Debian 8 and newer + * Ubuntu 18.04 and newer + * Fedora 32 and newer + * Debian 10 and newer ## Quick start & Electron Fiddle @@ -78,7 +78,7 @@ binary. Use this to spawn Electron from Node scripts: ```javascript const electron = require('electron') -const proc = require('child_process') +const proc = require('node:child_process') // will print something similar to /Users/maf/.../Electron console.log(electron) @@ -112,4 +112,4 @@ and more can be found on the [Community page](https://www.electronjs.org/communi [MIT](https://github.com/electron/electron/blob/main/LICENSE) -When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf). +When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/). diff --git a/SECURITY.md b/SECURITY.md index 43129ea52c03e..ebf5d628d18ee 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ The Electron team and community take security bugs in Electron seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. -To report a security issue, email [security@electronjs.org](mailto:security@electronjs.org) and include the word "SECURITY" in the subject line. +To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/electron/electron/security/advisories/new) tab. The Electron team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b4593261bde6b..0000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,246 +0,0 @@ -# The config expects the following environment variables to be set: -# - "GN_CONFIG" Build type. One of {'testing', 'release'}. -# - "GN_EXTRA_ARGS" Additional gn arguments for a build config, -# e.g. 'target_cpu="x86"' to build for a 32bit platform. -# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu -# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly -# if you pass a custom value for 'target_cpu'. -# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success. -# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules. -# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "TARGET_ARCH" value. -# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}. -# Is used in some publishing scripts, but does NOT affect the Electron binary. -# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value. -# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket. -# Otherwise the release will be uploaded to the GitHub Releases. -# (The value is only checked if "ELECTRON_RELEASE" is defined.) -# -# The publishing scripts expect access tokens to be defined as env vars, -# but those are not covered here. -# -# AppVeyor docs on variables: -# https://www.appveyor.com/docs/environment-variables/ -# https://www.appveyor.com/docs/build-configuration/#secure-variables -# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables - -version: 1.0.{build} -build_cloud: electron-16-core -image: vs2019bt-16.16.11 -environment: - GIT_CACHE_PATH: C:\Users\electron\libcc_cache - ELECTRON_OUT_DIR: Default - ELECTRON_ENABLE_STACK_DUMPING: 1 - ELECTRON_ALSO_LOG_TO_STDERR: 1 - MOCHA_REPORTER: mocha-multi-reporters - MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap - GOMA_FALLBACK_ON_AUTH_FAILURE: true -build_script: - - ps: >- - if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) { - Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild - } else { - node script/yarn.js install --frozen-lockfile - - $result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH - Write-Output $result - if ($result.ExitCode -eq 0) { - Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild - } - } - - echo "Building $env:GN_CONFIG build" - - git config --global core.longpaths true - - cd .. - - mkdir src - - update_depot_tools.bat - - ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" - $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE - } - - git clone https://github.com/electron/build-tools.git - - cd build-tools - - npm install - - mkdir third_party - - ps: >- - node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" - - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" - - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" - - cd .. - - ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info - if ($goma_login -eq 'Login as Fermi Planck') { - Write-warning "Goma authentication is correct"; - } else { - Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; - $host.SetShouldExit(1) - } - } - - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" - - ps: >- - if ($env:GN_CONFIG -ne 'release') { - $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " - } - - >- - gclient config - --name "src\electron" - --unmanaged - %GCLIENT_EXTRA_ARGS% - "https://github.com/electron/electron" - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - $env:RUN_GCLIENT_SYNC="true" - } else { - cd src\electron - node script\generate-deps-hash.js - $depshash = Get-Content .\.depshash -Raw - $zipfile = "Z:\$depshash.7z" - cd ..\.. - if (Test-Path -Path $zipfile) { - # file exists, unzip and then gclient sync - 7z x -y $zipfile -mmt=30 -aoa - if (-not (Test-Path -Path "src\buildtools")) { - # the zip file must be corrupt - resync - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" - } - } else { - # update angle - cd src\third_party\angle - git remote set-url origin https://chromium.googlesource.com/angle/angle.git - git fetch - cd ..\..\.. - } - } else { - # file does not exist, gclient sync, then zip - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" - } - } - } - - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync ) - - ps: >- - if ($env:SAVE_GCLIENT_SRC -eq 'true') { - # archive current source for future use - # only run on x64/woa to avoid contention saving - $(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30) - if ($LASTEXITCODE -ne 0) { - Write-warning "Could not save source to shared drive; continuing anyway" - } - # build time generation of file gen/angle/angle_commit.h depends on - # third_party/angle/.git - # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 - $(7z a $zipfile src\third_party\angle\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\angle\.git; continuing anyway" - } - # build time generation of file dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD - # https://dawn-review.googlesource.com/c/dawn/+/83901 - $(7z a $zipfile src\third_party\dawn\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\dawn\.git; continuing anyway" - } - } - - cd src - - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn - - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " - - gn check out/Default //electron:electron_lib - - gn check out/Default //electron:electron_app - - gn check out/Default //electron/shell/common/api:mojo - - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) - - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) - - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" - - ninja -C out/ffmpeg electron:electron_ffmpeg_zip - - ninja -C out/Default electron:electron_dist_zip - - ninja -C out/Default shell_browser_ui_unittests - - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - - ninja -C out/Default electron:electron_mksnapshot_zip - - cd out\Default - - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S - - cd ..\.. - - ninja -C out/Default electron:hunspell_dictionaries_zip - - ninja -C out/Default electron:electron_chromedriver_zip - - ninja -C out/Default third_party/electron_node:headers - - python %LOCAL_GOMA_DIR%\goma_ctl.py stat - - python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json - - 7z a node_headers.zip out\Default\gen\node_headers - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - # Needed for msdia140.dll on 64-bit windows - $env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin" - ninja -C out/Default electron:electron_symbols - } - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - python electron\script\zip-symbols.py - appveyor-retry appveyor PushArtifact out/Default/symbols.zip - } else { - # It's useful to have pdb files when debugging testing builds that are - # built on CI. - 7z a pdb.zip out\Default\*.pdb - } - - python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest -test_script: - # Workaround for https://github.com/appveyor/ci/issues/2420 - - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" - - ps: >- - if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) { - $env:RUN_TESTS="true" - } - - ps: >- - if ($env:RUN_TESTS -eq 'true') { - New-Item .\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib - } else { - echo "Skipping tests for $env:GN_CONFIG build" - } - - cd electron - - if "%RUN_TESTS%"=="true" ( echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log ) - - if "%RUN_TESTS%"=="true" ( echo Running remote test suite & node script/yarn test -- --trace-uncaught --runners=remote --runTestFilesSeparately --enable-logging=file --log-file=%cd%\electron.log ) - - if "%RUN_TESTS%"=="true" ( echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log ) - - cd .. - - if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg ) - - echo "About to verify mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying chromedriver" -deploy_script: - - cd electron - - ps: >- - if (Test-Path Env:\ELECTRON_RELEASE) { - if (Test-Path Env:\UPLOAD_TO_STORAGE) { - Write-Output "Uploading Electron release distribution to azure" - & python script\release\uploaders\upload.py --verbose --upload_to_storage - } else { - Write-Output "Uploading Electron release distribution to github releases" - & python script\release\uploaders\upload.py --verbose - } - } elseif (Test-Path Env:\TEST_WOA) { - node script/release/ci-release-build.js --job=electron-woa-testing --ci=GHA --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH - } -on_finish: - # Uncomment this lines to enable RDP - #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - - cd .. - - if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json ) - - if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip) - - if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe) - - if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip) - - if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip) - - if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip) - - if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip) - - if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip) - - if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib) - - ps: >- - if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) { - appveyor-retry appveyor PushArtifact pdb.zip - } - - - if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log ) diff --git a/build/.eslintrc.json b/build/.eslintrc.json new file mode 100644 index 0000000000000..dc7dde78dc189 --- /dev/null +++ b/build/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + "unicorn" + ], + "rules": { + "unicorn/prefer-node-protocol": "error" + } +} diff --git a/build/args/all.gn b/build/args/all.gn index 0a02f0c15b27f..2fbcfaaa8875d 100644 --- a/build/args/all.gn +++ b/build/args/all.gn @@ -1,8 +1,8 @@ is_electron_build = true root_extra_deps = [ "//electron" ] -# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json -node_module_version = 109 +# Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json +node_module_version = 133 v8_promise_internal_field_count = 1 v8_embedder_string = "-electron.0" @@ -10,23 +10,24 @@ v8_embedder_string = "-electron.0" # TODO: this breaks mksnapshot v8_enable_snapshot_native_code_counters = false -# TODO(codebytere): remove when Node.js handles https://chromium-review.googlesource.com/c/v8/v8/+/3211575 -v8_scriptormodule_legacy_lifetime = true - # we use this api v8_enable_javascript_promise_hooks = true enable_cdm_host_verification = false -proprietary_codecs = true ffmpeg_branding = "Chrome" +proprietary_codecs = true -enable_basic_printing = true +enable_printing = true # Removes DLLs from the build, which are only meant to be used for Chromium development. # See https://github.com/electron/electron/pull/17985 angle_enable_vulkan_validation_layers = false dawn_enable_vulkan_validation_layers = false +# Removes dxc dll's that are only used experimentally. +# See https://bugs.chromium.org/p/chromium/issues/detail?id=1474897 +dawn_use_built_dxc = false + # These are disabled because they cause the zip manifest to differ between # testing and release builds. # See https://chromium-review.googlesource.com/c/chromium/src/+/2774898. @@ -45,3 +46,37 @@ enable_cet_shadow_stack = false # V8 in the browser process. # Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=281 is_cfi = false + +# TODO: fix this once sysroots have been updated. +use_qt = false + +# Disables the builtins PGO for V8 +v8_builtins_profiling_log_file = "" + +# https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md +# TODO(vertedinde): hunt down dangling pointers on Linux +enable_dangling_raw_ptr_checks = false +enable_dangling_raw_ptr_feature_flag = false + +# This flag speeds up the performance of fork/execve on linux systems. +# Ref: https://chromium-review.googlesource.com/c/v8/v8/+/4602858 +v8_enable_private_mapping_fork_optimization = true + +# Expose public V8 symbols for native modules. +v8_expose_public_symbols = true + +# Disables unsafe-buffers-usage plugin due to incompatibilities with our reclient implementation +# Ref: https://chromium-review.googlesource.com/c/chromium/src/+/5426599 +# Ref: https://github.com/electron/electron/commit/8e20f16ea35eeaeb149ae63bad3703d782665f6a +clang_unsafe_buffers_paths = "" + +# Disable snapshotting a page when printing for its content to be analyzed for +# sensitive content by enterprise users. +enterprise_cloud_content_analysis = false + +# TODO: remove dependency on legacy ipc +# https://issues.chromium.org/issues/40943039 +content_enable_legacy_ipc = true + +# Electron has its own unsafe-buffers enforcement directories. +clang_unsafe_buffers_paths = "//electron/electron_unsafe_buffers_paths.txt" diff --git a/build/args/ffmpeg.gn b/build/args/ffmpeg.gn index 3ccd99d6be6f1..c25abfd25fa4b 100644 --- a/build/args/ffmpeg.gn +++ b/build/args/ffmpeg.gn @@ -1,7 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_component_build = false is_component_ffmpeg = true is_official_build = true -proprietary_codecs = false ffmpeg_branding = "Chromium" enable_dsyms = false +proprietary_codecs = false diff --git a/build/args/native_tests.gn b/build/args/native_tests.gn index 416b9556cc19d..26d6bf3dce4f3 100644 --- a/build/args/native_tests.gn +++ b/build/args/native_tests.gn @@ -1,4 +1,4 @@ -root_extra_deps = [ "//electron/spec" ] +root_extra_deps = [ "//electron/spec-chromium:spec" ] dcheck_always_on = true is_debug = false diff --git a/build/args/release.gn b/build/args/release.gn index e5017f6e16f9c..77351cc181ad9 100644 --- a/build/args/release.gn +++ b/build/args/release.gn @@ -1,14 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_component_build = false is_official_build = true -# This may be guarded behind is_chrome_branded alongside -# proprietary_codecs https://webrtc-review.googlesource.com/c/src/+/36321, -# explicitly override here to build OpenH264 encoder/FFmpeg decoder. -# The initialization of the decoder depends on whether ffmpeg has -# been built with H.264 support. -rtc_use_h264 = proprietary_codecs - # By default, Electron builds ffmpeg with proprietary codecs enabled. In order # to facilitate users who don't want to ship proprietary codecs in ffmpeg, or # who have an LGPL requirement to ship ffmpeg as a dynamically linked library, diff --git a/build/args/testing.gn b/build/args/testing.gn index 8f62af6e4b95f..395734c594329 100644 --- a/build/args/testing.gn +++ b/build/args/testing.gn @@ -1,14 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_debug = false is_component_build = false is_component_ffmpeg = true is_official_build = false dcheck_always_on = true symbol_level = 1 - -# This may be guarded behind is_chrome_branded alongside -# proprietary_codecs https://webrtc-review.googlesource.com/c/src/+/36321, -# explicitly override here to build OpenH264 encoder/FFmpeg decoder. -# The initialization of the decoder depends on whether ffmpeg has -# been built with H.264 support. -rtc_use_h264 = proprietary_codecs diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 31ff2dc8bb246..a82a0d7e316ee 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -1,6 +1,11 @@ -# For MAS build, we force defining "MAS_BUILD". -config("mas_build") { +action("generate_mas_config") { + outputs = [ "$target_gen_dir/../../mas.h" ] + script = "../../script/generate-mas-config.py" if (is_mas_build) { - defines = [ "MAS_BUILD" ] + args = [ "true" ] + } else { + args = [ "false" ] } + + args += rebase_path(outputs) } diff --git a/build/dump_syms.py b/build/dump_syms.py index 68cea6394bcd1..8b38944928e59 100644 --- a/build/dump_syms.py +++ b/build/dump_syms.py @@ -1,4 +1,4 @@ -from __future__ import print_function +#!/usr/bin/env python3 import collections import os diff --git a/build/extract_symbols.gni b/build/extract_symbols.gni index 2f98aa466ba15..8d6c2e72b9386 100644 --- a/build/extract_symbols.gni +++ b/build/extract_symbols.gni @@ -24,11 +24,8 @@ template("extract_symbols") { assert(defined(invoker.binary), "Need binary to dump") assert(defined(invoker.symbol_dir), "Need directory for symbol output") - if (host_os == "win" && target_cpu == "x86") { - dump_syms_label = "//third_party/breakpad:dump_syms(//build/toolchain/win:win_clang_x64)" - } else { - dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)" - } + dump_syms_label = + "//third_party/breakpad:dump_syms($host_system_allocator_toolchain)" dump_syms_binary = get_label_info(dump_syms_label, "root_out_dir") + "/dump_syms$_host_executable_suffix" diff --git a/build/fake_v8_context_snapshot_generator.py b/build/fake_v8_context_snapshot_generator.py deleted file mode 100644 index 2309b22484bac..0000000000000 --- a/build/fake_v8_context_snapshot_generator.py +++ /dev/null @@ -1,8 +0,0 @@ -import os -import shutil -import sys - -if os.path.exists(sys.argv[2]): - os.remove(sys.argv[2]) - -shutil.copy(sys.argv[1], sys.argv[2]) diff --git a/build/fuses/build.py b/build/fuses/build.py index f5c9b89417a60..77f269f6e837d 100755 --- a/build/fuses/build.py +++ b/build/fuses/build.py @@ -32,6 +32,12 @@ TEMPLATE_CC = """ #include "electron/fuses.h" +#include "base/dcheck_is_on.h" + +#if DCHECK_IS_ON() +#include "base/command_line.h" +#include +#endif namespace electron::fuses { @@ -66,9 +72,20 @@ getters_h += "FUSE_EXPORT bool Is{name}Enabled();\n".replace("{name}", name) getters_cc += """ bool Is{name}Enabled() { +#if DCHECK_IS_ON() + // RunAsNode is checked so early that base::CommandLine isn't yet + // initialized, so guard here to avoid a CHECK. + if (base::CommandLine::InitializedForCurrentProcess()) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch("{switch_name}")) { + std::string switch_value = command_line->GetSwitchValueASCII("{switch_name}"); + return switch_value == "1"; + } + } +#endif return kFuseWire[{index}] == '1'; } -""".replace("{name}", name).replace("{index}", str(index)) +""".replace("{name}", name).replace("{switch_name}", f"set-fuse-{fuse.lower()}").replace("{index}", str(index)) def c_hex(n): s = hex(n)[2:] diff --git a/build/fuses/fuses.json5 b/build/fuses/fuses.json5 index f4984aa2a17b4..3b5916ec7e1fb 100644 --- a/build/fuses/fuses.json5 +++ b/build/fuses/fuses.json5 @@ -7,5 +7,7 @@ "node_options": "1", "node_cli_inspect": "1", "embedded_asar_integrity_validation": "0", - "only_load_app_from_asar": "0" + "only_load_app_from_asar": "0", + "load_browser_process_specific_v8_snapshot": "0", + "grant_file_protocol_extra_privileges": "1" } diff --git a/build/generate_node_defines.py b/build/generate_node_defines.py index f2004abb9fe8e..31e43d3c66b3a 100755 --- a/build/generate_node_defines.py +++ b/build/generate_node_defines.py @@ -2,9 +2,9 @@ import re import sys -DEFINE_EXTRACT_REGEX = re.compile('^ *# *define (\w*)', re.MULTILINE) +DEFINE_EXTRACT_REGEX = re.compile(r'^ *# *define (\w*)', re.MULTILINE) -def main(outDir, headers): +def main(out_dir, headers): defines = [] for filename in headers: with open(filename, 'r') as f: @@ -15,13 +15,13 @@ def main(outDir, headers): for define in defines: push_and_undef += '#pragma push_macro("%s")\n' % define push_and_undef += '#undef %s\n' % define - with open(os.path.join(outDir, 'push_and_undef_node_defines.h'), 'w') as o: + with open(os.path.join(out_dir, 'push_and_undef_node_defines.h'), 'w') as o: o.write(push_and_undef) pop = '' for define in defines: pop += '#pragma pop_macro("%s")\n' % define - with open(os.path.join(outDir, 'pop_node_defines.h'), 'w') as o: + with open(os.path.join(out_dir, 'pop_node_defines.h'), 'w') as o: o.write(pop) def read_defines(content): diff --git a/build/js2c.py b/build/js2c.py old mode 100755 new mode 100644 index 4abcdabb58141..1529d3d0365d4 --- a/build/js2c.py +++ b/build/js2c.py @@ -4,32 +4,14 @@ import subprocess import sys -TEMPLATE = """ -#include "node_native_module.h" -#include "node_internals.h" - -namespace node::native_module {{ - -{definitions} - -void NativeModuleLoader::LoadEmbedderJavaScriptSource() {{ - {initializers} -}} - -}} // namespace node::native_module -""" - def main(): - node_path = os.path.abspath(sys.argv[1]) - natives = os.path.abspath(sys.argv[2]) - js_source_files = sys.argv[3:] + js2c = sys.argv[1] + root = sys.argv[2] + natives = sys.argv[3] + js_source_files = sys.argv[4:] - js2c = os.path.join(node_path, 'tools', 'js2c.py') subprocess.check_call( - [sys.executable, js2c] + - js_source_files + - ['--only-js', '--target', natives]) - + [js2c, natives] + js_source_files + ['--only-js', "--root", root]) if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) \ No newline at end of file diff --git a/build/npm-run.py b/build/npm-run.py index 49a6abac65d07..2fcf649f10627 100644 --- a/build/npm-run.py +++ b/build/npm-run.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -from __future__ import print_function + import os import subprocess import sys diff --git a/build/profile_toolchain.py b/build/profile_toolchain.py index 4251315e0a16a..f2ef85e1cab0c 100755 --- a/build/profile_toolchain.py +++ b/build/profile_toolchain.py @@ -1,12 +1,10 @@ -from __future__ import unicode_literals +#!/usr/bin/env python3 import contextlib import sys import os import optparse import json -import re -import subprocess sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__))) @@ -36,56 +34,10 @@ def calculate_hash(root): return CalculateHash('.', None) def windows_installed_software(): - powershell_command = [ - "Get-CimInstance", - "-Namespace", - "root\cimv2", - "-Class", - "Win32_product", - "|", - "Select", - "vendor,", - "description,", - "@{l='install_location';e='InstallLocation'},", - "@{l='install_date';e='InstallDate'},", - "@{l='install_date_2';e='InstallDate2'},", - "caption,", - "version,", - "name,", - "@{l='sku_number';e='SKUNumber'}", - "|", - "ConvertTo-Json", - ] - - proc = subprocess.Popen( - ["powershell.exe", "-Command", "-"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - - stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8")) - - if proc.returncode != 0: - raise RuntimeError("Failed to get list of installed software") - - # On AppVeyor there's other output related to PSReadline, - # so grab only the JSON output and ignore everything else - json_match = re.match( - r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL - ) - - if not json_match: - raise RuntimeError( - "Couldn't find JSON output for list of installed software" - ) - - # Filter out missing keys - return list( - map( - lambda info: {k: info[k] for k in info if info[k]}, - json.loads(json_match.group(1)), - ) - ) + # file_path = os.path.join(os.getcwd(), 'installed_software.json') + # return json.loads(open('installed_software.json').read().decode('utf-8')) + f = open('installed_software.json', encoding='utf-8-sig') + return json.load(f) def windows_profile(): diff --git a/build/rules.gni b/build/rules.gni index 557f0b8193c20..c9619d05ec018 100644 --- a/build/rules.gni +++ b/build/rules.gni @@ -29,7 +29,7 @@ template("compile_ib_files") { _output_extension = invoker.output_extension - script = "//build/config/ios/compile_ib_files.py" + script = "//build/config/apple/compile_ib_files.py" sources = invoker.sources outputs = [ "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", diff --git a/build/run-in-dir.py b/build/run-in-dir.py index 25fcb21a03b29..ededac1804b3b 100644 --- a/build/run-in-dir.py +++ b/build/run-in-dir.py @@ -1,10 +1,11 @@ import sys import os +import subprocess def main(argv): - cwd = argv[1] - os.chdir(cwd) - os.execv(sys.executable, [sys.executable] + argv[2:]) + os.chdir(argv[1]) + p = subprocess.Popen(argv[2:]) + return p.wait() if __name__ == '__main__': - main(sys.argv) + sys.exit(main(sys.argv)) diff --git a/build/templates/electron_rc.tmpl b/build/templates/electron_rc.tmpl new file mode 100644 index 0000000000000..2f75d9003b84b --- /dev/null +++ b/build/templates/electron_rc.tmpl @@ -0,0 +1,107 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION $major,$minor,$patch,$prerelease_number + PRODUCTVERSION $major,$minor,$patch,$prerelease_number + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "GitHub, Inc." + VALUE "FileDescription", "Electron" + VALUE "FileVersion", "$major.$minor.$patch" + VALUE "InternalName", "electron.exe" + VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." + VALUE "OriginalFilename", "electron.exe" + VALUE "ProductName", "Electron" + VALUE "ProductVersion", "$major.$minor.$patch" + VALUE "SquirrelAwareVersion", "1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +IDR_MAINFRAME ICON "electron.ico" +///////////////////////////////////////////////////////////////////////////// diff --git a/build/templates/version_string.tmpl b/build/templates/version_string.tmpl new file mode 100644 index 0000000000000..02e5f9c0d4f9f --- /dev/null +++ b/build/templates/version_string.tmpl @@ -0,0 +1 @@ +$full_version \ No newline at end of file diff --git a/build/webpack/webpack.config.asar.js b/build/webpack/webpack.config.asar.js deleted file mode 100644 index 83443f467cad2..0000000000000 --- a/build/webpack/webpack.config.asar.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = require('./webpack.config.base')({ - target: 'asar', - alwaysHasNode: true, - targetDeletesNodeGlobals: true -}); diff --git a/build/webpack/webpack.config.base.js b/build/webpack/webpack.config.base.js index e0d8e516e5e83..b806e43535ce1 100644 --- a/build/webpack/webpack.config.base.js +++ b/build/webpack/webpack.config.base.js @@ -1,9 +1,10 @@ -const fs = require('fs'); -const path = require('path'); -const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); +const webpack = require('webpack'); const WrapperPlugin = require('wrapper-webpack-plugin'); +const fs = require('node:fs'); +const path = require('node:path'); + const electronRoot = path.resolve(__dirname, '../..'); class AccessDependenciesPlugin { @@ -53,20 +54,6 @@ module.exports = ({ const ignoredModules = []; - if (defines.ENABLE_DESKTOP_CAPTURER === 'false') { - ignoredModules.push( - '@electron/internal/browser/desktop-capturer', - '@electron/internal/browser/api/desktop-capturer', - '@electron/internal/renderer/api/desktop-capturer' - ); - } - - if (defines.ENABLE_VIEWS_API === 'false') { - ignoredModules.push( - '@electron/internal/browser/api/views/image-view.js' - ); - } - const plugins = []; if (onlyPrintingGraph) { diff --git a/build/webpack/webpack.config.node.js b/build/webpack/webpack.config.node.js new file mode 100644 index 0000000000000..875ec4bacb2be --- /dev/null +++ b/build/webpack/webpack.config.node.js @@ -0,0 +1,4 @@ +module.exports = require('./webpack.config.base')({ + target: 'node', + alwaysHasNode: true +}); diff --git a/build/webpack/webpack.config.utility.js b/build/webpack/webpack.config.utility.js new file mode 100644 index 0000000000000..a80775d18ebab --- /dev/null +++ b/build/webpack/webpack.config.utility.js @@ -0,0 +1,4 @@ +module.exports = require('./webpack.config.base')({ + target: 'utility', + alwaysHasNode: true +}); diff --git a/build/zip.py b/build/zip.py index bfaf27c08b24b..86e1ea7c563dc 100644 --- a/build/zip.py +++ b/build/zip.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -from __future__ import print_function + import os import subprocess import sys @@ -10,7 +10,13 @@ '.mojom.js', '.mojom-lite.js', '.info', - '.m.js' + '.m.js', + + # These are only needed for Chromium tests we don't run. Listed in + # 'extensions' because the mksnapshot zip has these under a subdirectory, and + # the PATHS_TO_SKIP is checked with |startswith|. + 'dbgcore.dll', + 'dbghelp.dll', ] PATHS_TO_SKIP = [ @@ -34,7 +40,7 @@ # Skip because these are outputs that we don't need. 'resources/inspector', 'gen/third_party/devtools-frontend/src', - 'gen/ui/webui' + 'gen/ui/webui', ] def skip_path(dep, dist_zip, target_cpu): @@ -53,7 +59,7 @@ def skip_path(dep, dist_zip, target_cpu): and dep == "snapshot_blob.bin" ) ) - if should_skip: + if should_skip and os.environ.get('ELECTRON_DEBUG_ZIP_SKIP') == '1': print("Skipping {}".format(dep)) return should_skip diff --git a/build/zip_libcxx.py b/build/zip_libcxx.py index daa94fc8fb8a5..77e69e9172a52 100644 --- a/build/zip_libcxx.py +++ b/build/zip_libcxx.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -from __future__ import print_function + import os import subprocess import sys @@ -44,4 +44,4 @@ def main(argv): z.write(object_file, os.path.relpath(object_file, base_path_libcxxabi)) if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) \ No newline at end of file + sys.exit(main(sys.argv[1:])) diff --git a/buildflags/BUILD.gn b/buildflags/BUILD.gn index a37d752dba360..ef00ad27f6085 100644 --- a/buildflags/BUILD.gn +++ b/buildflags/BUILD.gn @@ -9,16 +9,20 @@ buildflag_header("buildflags") { header = "buildflags.h" flags = [ - "ENABLE_DESKTOP_CAPTURER=$enable_desktop_capturer", - "ENABLE_RUN_AS_NODE=$enable_run_as_node", - "ENABLE_OSR=$enable_osr", - "ENABLE_VIEWS_API=$enable_views_api", "ENABLE_PDF_VIEWER=$enable_pdf_viewer", - "ENABLE_TTS=$enable_tts", - "ENABLE_COLOR_CHOOSER=$enable_color_chooser", "ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions", "ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker", - "ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture", "OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider", ] + + if (electron_vendor_version != "") { + result = string_split(electron_vendor_version, ":") + flags += [ + "HAS_VENDOR_VERSION=true", + "VENDOR_VERSION_NAME=\"${result[0]}\"", + "VENDOR_VERSION_VALUE=\"${result[1]}\"", + ] + } else { + flags += [ "HAS_VENDOR_VERSION=false" ] + } } diff --git a/buildflags/buildflags.gni b/buildflags/buildflags.gni index 6a6a7d59fefe3..801732cb2595b 100644 --- a/buildflags/buildflags.gni +++ b/buildflags/buildflags.gni @@ -3,23 +3,8 @@ # found in the LICENSE file. declare_args() { - enable_desktop_capturer = true - - # Allow running Electron as a node binary. - enable_run_as_node = true - - enable_osr = true - - enable_views_api = true - enable_pdf_viewer = true - enable_tts = true - - enable_color_chooser = true - - enable_picture_in_picture = true - # Provide a fake location provider for mocking # the geolocation responses. Disable it if you # need to test with chromium's location provider. @@ -31,4 +16,15 @@ declare_args() { # Enable Spellchecker support enable_builtin_spellchecker = true + + # The version of Electron. + # Packagers and vendor builders should set this in gn args to avoid running + # the script that reads git tag. + override_electron_version = "" + + # Define an extra item that will show in process.versions, the value must + # be in the format of "key:value". + # Packagers and vendor builders can set this in gn args to attach extra info + # about the build in the binary. + electron_vendor_version = "" } diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index bfd971e576a85..90dc377d3ee0e 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -13,8 +13,8 @@ import("//third_party/widevine/cdm/widevine.gni") static_library("chrome") { visibility = [ "//electron:electron_lib" ] sources = [ - "//chrome/browser/accessibility/accessibility_ui.cc", - "//chrome/browser/accessibility/accessibility_ui.h", + "//ash/style/rounded_rect_cutout_path_builder.cc", + "//ash/style/rounded_rect_cutout_path_builder.h", "//chrome/browser/app_mode/app_mode_utils.cc", "//chrome/browser/app_mode/app_mode_utils.h", "//chrome/browser/browser_features.cc", @@ -30,18 +30,46 @@ static_library("chrome") { "//chrome/browser/devtools/devtools_file_system_indexer.cc", "//chrome/browser/devtools/devtools_file_system_indexer.h", "//chrome/browser/devtools/devtools_settings.h", - "//chrome/browser/extensions/global_shortcut_listener.cc", - "//chrome/browser/extensions/global_shortcut_listener.h", + "//chrome/browser/devtools/features.cc", + "//chrome/browser/devtools/features.h", + "//chrome/browser/devtools/visual_logging.cc", + "//chrome/browser/devtools/visual_logging.h", + "//chrome/browser/file_system_access/file_system_access_features.cc", + "//chrome/browser/file_system_access/file_system_access_features.h", "//chrome/browser/icon_loader.cc", "//chrome/browser/icon_loader.h", "//chrome/browser/icon_manager.cc", "//chrome/browser/icon_manager.h", + "//chrome/browser/media/webrtc/delegated_source_list_capturer.cc", + "//chrome/browser/media/webrtc/delegated_source_list_capturer.h", + "//chrome/browser/media/webrtc/desktop_capturer_wrapper.cc", + "//chrome/browser/media/webrtc/desktop_capturer_wrapper.h", + "//chrome/browser/media/webrtc/desktop_media_list.cc", + "//chrome/browser/media/webrtc/desktop_media_list.h", + "//chrome/browser/media/webrtc/desktop_media_list_base.cc", + "//chrome/browser/media/webrtc/desktop_media_list_base.h", + "//chrome/browser/media/webrtc/desktop_media_list_observer.h", + "//chrome/browser/media/webrtc/native_desktop_media_list.cc", + "//chrome/browser/media/webrtc/native_desktop_media_list.h", + "//chrome/browser/media/webrtc/thumbnail_capturer.cc", + "//chrome/browser/media/webrtc/thumbnail_capturer.h", + "//chrome/browser/media/webrtc/window_icon_util.h", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h", "//chrome/browser/net/proxy_config_monitor.cc", "//chrome/browser/net/proxy_config_monitor.h", "//chrome/browser/net/proxy_service_factory.cc", "//chrome/browser/net/proxy_service_factory.h", + "//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.h", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker_observer.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker_observer.h", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h", + "//chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.cc", + "//chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h", "//chrome/browser/platform_util.cc", "//chrome/browser/platform_util.h", "//chrome/browser/predictors/preconnect_manager.cc", @@ -55,62 +83,89 @@ static_library("chrome") { "//chrome/browser/process_singleton.h", "//chrome/browser/process_singleton_internal.cc", "//chrome/browser/process_singleton_internal.h", + "//chrome/browser/themes/browser_theme_pack.cc", + "//chrome/browser/themes/browser_theme_pack.h", + "//chrome/browser/themes/custom_theme_supplier.cc", + "//chrome/browser/themes/custom_theme_supplier.h", + "//chrome/browser/themes/theme_properties.cc", + "//chrome/browser/themes/theme_properties.h", + "//chrome/browser/ui/color/chrome_color_mixers.cc", + "//chrome/browser/ui/color/chrome_color_mixers.h", "//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc", "//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h", "//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc", "//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h", "//chrome/browser/ui/exclusive_access/exclusive_access_manager.cc", "//chrome/browser/ui/exclusive_access/exclusive_access_manager.h", + "//chrome/browser/ui/exclusive_access/exclusive_access_permission_manager.cc", + "//chrome/browser/ui/exclusive_access/exclusive_access_permission_manager.h", "//chrome/browser/ui/exclusive_access/fullscreen_controller.cc", "//chrome/browser/ui/exclusive_access/fullscreen_controller.h", "//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.cc", "//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h", "//chrome/browser/ui/exclusive_access/keyboard_lock_controller.cc", "//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h", - "//chrome/browser/ui/exclusive_access/mouse_lock_controller.cc", - "//chrome/browser/ui/exclusive_access/mouse_lock_controller.h", - "//chrome/browser/ui/native_window_tracker.h", + "//chrome/browser/ui/exclusive_access/pointer_lock_controller.cc", + "//chrome/browser/ui/exclusive_access/pointer_lock_controller.h", + "//chrome/browser/ui/frame/window_frame_util.cc", + "//chrome/browser/ui/frame/window_frame_util.h", + "//chrome/browser/ui/ui_features.cc", + "//chrome/browser/ui/ui_features.h", + "//chrome/browser/ui/view_ids.h", "//chrome/browser/ui/views/eye_dropper/eye_dropper.cc", "//chrome/browser/ui/views/eye_dropper/eye_dropper.h", - "//chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc", - "//chrome/browser/ui/views/eye_dropper/eye_dropper_view.h", + "//chrome/browser/ui/views/overlay/back_to_tab_button.cc", + "//chrome/browser/ui/views/overlay/back_to_tab_button.h", + "//chrome/browser/ui/views/overlay/back_to_tab_label_button.cc", + "//chrome/browser/ui/views/overlay/close_image_button.cc", + "//chrome/browser/ui/views/overlay/close_image_button.h", + "//chrome/browser/ui/views/overlay/constants.h", + "//chrome/browser/ui/views/overlay/hang_up_button.cc", + "//chrome/browser/ui/views/overlay/hang_up_button.h", + "//chrome/browser/ui/views/overlay/minimize_button.cc", + "//chrome/browser/ui/views/overlay/minimize_button.h", + "//chrome/browser/ui/views/overlay/overlay_window_image_button.cc", + "//chrome/browser/ui/views/overlay/overlay_window_image_button.h", + "//chrome/browser/ui/views/overlay/playback_image_button.cc", + "//chrome/browser/ui/views/overlay/playback_image_button.h", + "//chrome/browser/ui/views/overlay/resize_handle_button.cc", + "//chrome/browser/ui/views/overlay/resize_handle_button.h", + "//chrome/browser/ui/views/overlay/simple_overlay_window_image_button.cc", + "//chrome/browser/ui/views/overlay/simple_overlay_window_image_button.h", + "//chrome/browser/ui/views/overlay/skip_ad_label_button.cc", + "//chrome/browser/ui/views/overlay/skip_ad_label_button.h", + "//chrome/browser/ui/views/overlay/toggle_camera_button.cc", + "//chrome/browser/ui/views/overlay/toggle_camera_button.h", + "//chrome/browser/ui/views/overlay/toggle_microphone_button.cc", + "//chrome/browser/ui/views/overlay/toggle_microphone_button.h", + "//chrome/browser/ui/views/overlay/video_overlay_window_views.cc", + "//chrome/browser/ui/views/overlay/video_overlay_window_views.h", + "//chrome/browser/ui/webui/accessibility/accessibility_ui.cc", + "//chrome/browser/ui/webui/accessibility/accessibility_ui.h", "//extensions/browser/app_window/size_constraints.cc", "//extensions/browser/app_window/size_constraints.h", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h", + "//ui/views/native_window_tracker.h", ] if (is_posix) { sources += [ "//chrome/browser/process_singleton_posix.cc" ] } - if (is_mac) { - sources += [ - "//chrome/browser/extensions/global_shortcut_listener_mac.h", - "//chrome/browser/extensions/global_shortcut_listener_mac.mm", - "//chrome/browser/icon_loader_mac.mm", - "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h", - "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm", - "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h", - "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm", - "//chrome/browser/media/webrtc/window_icon_util_mac.mm", - "//chrome/browser/platform_util_mac.mm", - "//chrome/browser/process_singleton_mac.mm", - "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h", - "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm", - ] - } - if (is_win) { sources += [ - "//chrome/browser/extensions/global_shortcut_listener_win.cc", - "//chrome/browser/extensions/global_shortcut_listener_win.h", "//chrome/browser/icon_loader_win.cc", "//chrome/browser/media/webrtc/window_icon_util_win.cc", "//chrome/browser/process_singleton_win.cc", - "//chrome/browser/ui/frame/window_frame_util.h", - "//chrome/browser/ui/view_ids.h", "//chrome/browser/win/chrome_process_finder.cc", "//chrome/browser/win/chrome_process_finder.h", + "//chrome/browser/win/chrome_select_file_dialog_factory.cc", + "//chrome/browser/win/chrome_select_file_dialog_factory.h", + "//chrome/browser/win/titlebar_config.cc", "//chrome/browser/win/titlebar_config.h", + "//chrome/browser/win/util_win_service.cc", + "//chrome/browser/win/util_win_service.h", "//chrome/child/v8_crashpad_support_win.cc", "//chrome/child/v8_crashpad_support_win.h", ] @@ -120,51 +175,64 @@ static_library("chrome") { sources += [ "//chrome/browser/media/webrtc/window_icon_util_ozone.cc" ] } - if (use_aura) { - sources += [ - "//chrome/browser/platform_util_aura.cc", - "//chrome/browser/ui/aura/native_window_tracker_aura.cc", - "//chrome/browser/ui/aura/native_window_tracker_aura.h", - "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.cc", - ] - } - public_deps = [ - "//chrome/browser:dev_ui_browser_resources", + "//chrome/browser/resources/accessibility:resources", + "//chrome/browser/ui/color:color_headers", + "//chrome/browser/ui/color:mixers", "//chrome/common", "//chrome/common:version_header", + "//components/global_media_controls", "//components/keyed_service/content", "//components/paint_preview/buildflags", "//components/proxy_config", - "//components/services/language_detection/public/mojom", "//content/public/browser", "//services/strings", ] deps = [ + "//chrome/app/vector_icons", "//chrome/browser:resource_prefetch_predictor_proto", - "//components/optimization_guide/proto:optimization_guide_proto", + "//chrome/browser/resource_coordinator:mojo_bindings", + "//chrome/browser/task_manager/common:impl", + "//chrome/browser/ui/webui/tab_search:mojo_bindings", + "//chrome/browser/web_applications/mojom:mojom_web_apps_enum", + "//components/enterprise/buildflags", + "//components/enterprise/common/proto:connectors_proto", + "//components/enterprise/obfuscation/core:enterprise_obfuscation", + "//components/safe_browsing/core/browser/db:safebrowsing_proto", + "//components/vector_icons:vector_icons", + "//ui/base/accelerators/global_accelerator_listener", + "//ui/snapshot", + "//ui/views/controls/webview", ] + if (use_aura) { + sources += [ + "//chrome/browser/platform_util_aura.cc", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_aura.cc", + "//ui/views/native_window_tracker_aura.cc", + "//ui/views/native_window_tracker_aura.h", + ] + deps += [ "//components/eye_dropper" ] + } + if (is_linux) { - sources += [ "//chrome/browser/icon_loader_auralinux.cc" ] - if (use_ozone) { - deps += [ "//ui/ozone" ] - sources += [ - "//chrome/browser/extensions/global_shortcut_listener_ozone.cc", - "//chrome/browser/extensions/global_shortcut_listener_ozone.h", - ] - } + sources += [ + "//chrome/browser/icon_loader_auralinux.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h", + ] sources += [ "//chrome/browser/ui/views/status_icons/concat_menu_model.cc", "//chrome/browser/ui/views/status_icons/concat_menu_model.h", "//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc", "//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h", ] - public_deps += [ - "//components/dbus/menu", - "//components/dbus/thread_linux", + sources += [ + "//chrome/browser/ui/views/dark_mode_manager_linux.cc", + "//chrome/browser/ui/views/dark_mode_manager_linux.h", ] + public_deps += [ "//components/dbus" ] } if (is_win) { @@ -172,21 +240,35 @@ static_library("chrome") { "//chrome/browser/win/icon_reader_service.cc", "//chrome/browser/win/icon_reader_service.h", ] - public_deps += [ "//chrome/services/util_win:lib" ] + public_deps += [ + "//chrome/browser/web_applications/proto", + "//chrome/services/util_win:lib", + "//components/webapps/common:mojo_bindings", + ] + deps += [ + "//chrome/services/util_win/public/mojom", + "//components/compose/core/browser:mojo_bindings", + "//components/segmentation_platform/public/proto", + ] } - if (enable_desktop_capturer) { + if (is_mac) { sources += [ - "//chrome/browser/media/webrtc/desktop_media_list.cc", - "//chrome/browser/media/webrtc/desktop_media_list.h", - "//chrome/browser/media/webrtc/desktop_media_list_base.cc", - "//chrome/browser/media/webrtc/desktop_media_list_base.h", - "//chrome/browser/media/webrtc/desktop_media_list_observer.h", - "//chrome/browser/media/webrtc/native_desktop_media_list.cc", - "//chrome/browser/media/webrtc/native_desktop_media_list.h", - "//chrome/browser/media/webrtc/window_icon_util.h", + "//chrome/browser/icon_loader_mac.mm", + "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h", + "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm", + "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h", + "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm", + "//chrome/browser/media/webrtc/thumbnail_capturer_mac.h", + "//chrome/browser/media/webrtc/thumbnail_capturer_mac.mm", + "//chrome/browser/media/webrtc/window_icon_util_mac.mm", + "//chrome/browser/permissions/system/media_authorization_wrapper_mac.h", + "//chrome/browser/platform_util_mac.mm", + "//chrome/browser/process_singleton_mac.mm", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm", ] - deps += [ "//ui/snapshot" ] + deps += [ ":system_media_capture_permissions_mac_conflict" ] } if (enable_widevine) { @@ -199,10 +281,14 @@ static_library("chrome") { deps += [ "//components/cdm/renderer" ] } - if (enable_basic_printing) { + if (enable_printing) { sources += [ "//chrome/browser/bad_message.cc", "//chrome/browser/bad_message.h", + "//chrome/browser/printing/prefs_util.cc", + "//chrome/browser/printing/prefs_util.h", + "//chrome/browser/printing/print_compositor_util.cc", + "//chrome/browser/printing/print_compositor_util.h", "//chrome/browser/printing/print_job.cc", "//chrome/browser/printing/print_job.h", "//chrome/browser/printing/print_job_manager.cc", @@ -215,14 +301,22 @@ static_library("chrome") { "//chrome/browser/printing/print_view_manager_base.h", "//chrome/browser/printing/printer_query.cc", "//chrome/browser/printing/printer_query.h", + "//chrome/browser/printing/printer_query_oop.cc", + "//chrome/browser/printing/printer_query_oop.h", "//chrome/browser/printing/printing_service.cc", "//chrome/browser/printing/printing_service.h", + "//components/printing/browser/print_to_pdf/pdf_print_job.cc", + "//components/printing/browser/print_to_pdf/pdf_print_job.h", + "//components/printing/browser/print_to_pdf/pdf_print_result.cc", + "//components/printing/browser/print_to_pdf/pdf_print_result.h", "//components/printing/browser/print_to_pdf/pdf_print_utils.cc", "//components/printing/browser/print_to_pdf/pdf_print_utils.h", ] if (enable_oop_printing) { sources += [ + "//chrome/browser/printing/oop_features.cc", + "//chrome/browser/printing/oop_features.h", "//chrome/browser/printing/print_backend_service_manager.cc", "//chrome/browser/printing/print_backend_service_manager.h", ] @@ -247,61 +341,25 @@ static_library("chrome") { sources += [ "//chrome/browser/printing/pdf_to_emf_converter.cc", "//chrome/browser/printing/pdf_to_emf_converter.h", + "//chrome/browser/printing/printer_xml_parser_impl.cc", + "//chrome/browser/printing/printer_xml_parser_impl.h", + "//chrome/browser/printing/xps_features.cc", + "//chrome/browser/printing/xps_features.h", ] + deps += [ "//printing:printing_base" ] } } - if (enable_picture_in_picture) { - sources += [ - "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc", - "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h", - "//chrome/browser/ui/views/overlay/back_to_tab_image_button.cc", - "//chrome/browser/ui/views/overlay/back_to_tab_image_button.h", - "//chrome/browser/ui/views/overlay/back_to_tab_label_button.cc", - "//chrome/browser/ui/views/overlay/close_image_button.cc", - "//chrome/browser/ui/views/overlay/close_image_button.h", - "//chrome/browser/ui/views/overlay/constants.h", - "//chrome/browser/ui/views/overlay/document_overlay_window_views.cc", - "//chrome/browser/ui/views/overlay/document_overlay_window_views.h", - "//chrome/browser/ui/views/overlay/hang_up_button.cc", - "//chrome/browser/ui/views/overlay/hang_up_button.h", - "//chrome/browser/ui/views/overlay/overlay_window_image_button.cc", - "//chrome/browser/ui/views/overlay/overlay_window_image_button.h", - "//chrome/browser/ui/views/overlay/overlay_window_views.cc", - "//chrome/browser/ui/views/overlay/overlay_window_views.h", - "//chrome/browser/ui/views/overlay/playback_image_button.cc", - "//chrome/browser/ui/views/overlay/playback_image_button.h", - "//chrome/browser/ui/views/overlay/resize_handle_button.cc", - "//chrome/browser/ui/views/overlay/resize_handle_button.h", - "//chrome/browser/ui/views/overlay/skip_ad_label_button.cc", - "//chrome/browser/ui/views/overlay/skip_ad_label_button.h", - "//chrome/browser/ui/views/overlay/toggle_camera_button.cc", - "//chrome/browser/ui/views/overlay/toggle_camera_button.h", - "//chrome/browser/ui/views/overlay/toggle_microphone_button.cc", - "//chrome/browser/ui/views/overlay/toggle_microphone_button.h", - "//chrome/browser/ui/views/overlay/track_image_button.cc", - "//chrome/browser/ui/views/overlay/track_image_button.h", - "//chrome/browser/ui/views/overlay/video_overlay_window_views.cc", - "//chrome/browser/ui/views/overlay/video_overlay_window_views.h", - ] - - deps += [ - "//chrome/app/vector_icons", - "//components/vector_icons:vector_icons", - "//ui/views/controls/webview", - ] - } - if (enable_electron_extensions) { sources += [ "//chrome/browser/extensions/chrome_url_request_util.cc", "//chrome/browser/extensions/chrome_url_request_util.h", "//chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc", "//chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h", - "//chrome/renderer/extensions/extension_hooks_delegate.cc", - "//chrome/renderer/extensions/extension_hooks_delegate.h", - "//chrome/renderer/extensions/tabs_hooks_delegate.cc", - "//chrome/renderer/extensions/tabs_hooks_delegate.h", + "//chrome/renderer/extensions/api/extension_hooks_delegate.cc", + "//chrome/renderer/extensions/api/extension_hooks_delegate.h", + "//chrome/renderer/extensions/api/tabs_hooks_delegate.cc", + "//chrome/renderer/extensions/api/tabs_hooks_delegate.h", ] if (enable_pdf_viewer) { @@ -310,8 +368,8 @@ static_library("chrome") { "//chrome/browser/pdf/chrome_pdf_stream_delegate.h", "//chrome/browser/pdf/pdf_extension_util.cc", "//chrome/browser/pdf/pdf_extension_util.h", - "//chrome/browser/pdf/pdf_frame_util.cc", - "//chrome/browser/pdf/pdf_frame_util.h", + "//chrome/browser/pdf/pdf_viewer_stream_manager.cc", + "//chrome/browser/pdf/pdf_viewer_stream_manager.h", "//chrome/browser/plugins/pdf_iframe_navigation_throttle.cc", "//chrome/browser/plugins/pdf_iframe_navigation_throttle.h", ] @@ -320,6 +378,34 @@ static_library("chrome") { "//components/pdf/renderer", ] } + } else { + # These are required by the webRequest module. + sources += [ + "//extensions/browser/api/declarative_net_request/request_action.cc", + "//extensions/browser/api/declarative_net_request/request_action.h", + "//extensions/browser/api/web_request/form_data_parser.cc", + "//extensions/browser/api/web_request/form_data_parser.h", + "//extensions/browser/api/web_request/upload_data_presenter.cc", + "//extensions/browser/api/web_request/upload_data_presenter.h", + "//extensions/browser/api/web_request/web_request_api_constants.cc", + "//extensions/browser/api/web_request/web_request_api_constants.h", + "//extensions/browser/api/web_request/web_request_info.cc", + "//extensions/browser/api/web_request/web_request_info.h", + "//extensions/browser/api/web_request/web_request_resource_type.cc", + "//extensions/browser/api/web_request/web_request_resource_type.h", + "//extensions/browser/extension_api_frame_id_map.cc", + "//extensions/browser/extension_api_frame_id_map.h", + "//extensions/browser/extension_navigation_ui_data.cc", + "//extensions/browser/extension_navigation_ui_data.h", + "//extensions/browser/extensions_browser_client.cc", + "//extensions/browser/extensions_browser_client.h", + "//extensions/browser/guest_view/web_view/web_view_renderer_state.cc", + "//extensions/browser/guest_view/web_view/web_view_renderer_state.h", + ] + + public_deps += [ + "//extensions/browser/api/declarative_net_request/flat:extension_ruleset", + ] } if (!is_mas_build) { @@ -334,41 +420,6 @@ static_library("chrome") { } } -source_set("plugins") { - sources = [] - deps = [] - frameworks = [] - - # browser side - sources += [ - "//chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc", - "//chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h", - "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc", - "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h", - ] - - # renderer side - sources += [ - "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc", - "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h", - "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", - "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", - ] - - deps += [ - "//components/strings", - "//media:media_buildflags", - "//ppapi/buildflags", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/proxy:ipc", - "//ppapi/shared_impl", - "//services/device/public/mojom", - "//skia", - "//storage/browser", - ] -} - # This source set is just so we don't have to depend on all of //chrome/browser # You may have to add new files here during the upgrade if //chrome/browser/spellchecker # gets more files @@ -380,8 +431,14 @@ source_set("chrome_spellchecker") { if (enable_builtin_spellchecker) { sources += [ + "//chrome/browser/profiles/profile_keyed_service_factory.cc", + "//chrome/browser/profiles/profile_keyed_service_factory.h", + "//chrome/browser/profiles/profile_selections.cc", + "//chrome/browser/profiles/profile_selections.h", "//chrome/browser/spellchecker/spell_check_host_chrome_impl.cc", "//chrome/browser/spellchecker/spell_check_host_chrome_impl.h", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.cc", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.h", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.h", "//chrome/browser/spellchecker/spellcheck_factory.cc", @@ -431,3 +488,16 @@ source_set("chrome_spellchecker") { "//components/spellcheck/renderer", ] } + +# These sources create an object file conflict with one in |:chrome|, so they +# must live in a separate target. +# Conflicting sources: +# //chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm +# //chrome/browser/permissions/system/system_media_capture_permissions_mac.mm +source_set("system_media_capture_permissions_mac_conflict") { + sources = [ + "//chrome/browser/permissions/system/system_media_capture_permissions_mac.h", + "//chrome/browser/permissions/system/system_media_capture_permissions_mac.mm", + ] + deps = [ "//chrome/common" ] +} diff --git a/default_app/.eslintrc.json b/default_app/.eslintrc.json new file mode 100644 index 0000000000000..dc7dde78dc189 --- /dev/null +++ b/default_app/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + "unicorn" + ], + "rules": { + "unicorn/prefer-node-protocol": "error" + } +} diff --git a/default_app/default_app.ts b/default_app/default_app.ts index 0bac020331730..6cd280bb555c0 100644 --- a/default_app/default_app.ts +++ b/default_app/default_app.ts @@ -1,7 +1,8 @@ import { shell } from 'electron/common'; import { app, dialog, BrowserWindow, ipcMain } from 'electron/main'; -import * as path from 'path'; -import * as url from 'url'; + +import * as path from 'node:path'; +import * as url from 'node:url'; let mainWindow: BrowserWindow | null = null; @@ -51,16 +52,17 @@ async function createWindow (backgroundColor?: string) { autoHideMenuBar: true, backgroundColor, webPreferences: { - preload: path.resolve(__dirname, 'preload.js'), + preload: url.fileURLToPath(new URL('preload.js', import.meta.url)), contextIsolation: true, - sandbox: true + sandbox: true, + nodeIntegration: false }, useContentSize: true, show: false }; if (process.platform === 'linux') { - options.icon = path.join(__dirname, 'icon.png'); + options.icon = url.fileURLToPath(new URL('icon.png', import.meta.url)); } mainWindow = new BrowserWindow(options); diff --git a/default_app/main.ts b/default_app/main.ts index f2834624f7430..38fb3b665d0ec 100644 --- a/default_app/main.ts +++ b/default_app/main.ts @@ -1,8 +1,10 @@ import * as electron from 'electron/main'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as url from 'url'; +import * as fs from 'node:fs'; +import { Module } from 'node:module'; +import * as path from 'node:path'; +import * as url from 'node:url'; + const { app, dialog } = electron; type DefaultAppOptions = { @@ -15,8 +17,6 @@ type DefaultAppOptions = { modules: string[]; } -const Module = require('module'); - // Parse command line options. const argv = process.argv.slice(1); @@ -71,10 +71,10 @@ if (nextArgIsRequire) { // Set up preload modules if (option.modules.length > 0) { - Module._preloadModules(option.modules); + (Module as any)._preloadModules(option.modules); } -function loadApplicationPackage (packagePath: string) { +async function loadApplicationPackage (packagePath: string) { // Add a flag indicating app is started from default app. Object.defineProperty(process, 'defaultApp', { configurable: false, @@ -83,17 +83,23 @@ function loadApplicationPackage (packagePath: string) { }); try { - // Override app name and version. + // Override app's package.json data. packagePath = path.resolve(packagePath); const packageJsonPath = path.join(packagePath, 'package.json'); let appPath; if (fs.existsSync(packageJsonPath)) { let packageJson; + const emitWarning = process.emitWarning; try { - packageJson = require(packageJsonPath); + process.emitWarning = () => {}; + packageJson = (await import(url.pathToFileURL(packageJsonPath).toString(), { + with: { type: 'json' } + })).default; } catch (e) { showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${(e as Error).message}`); return; + } finally { + process.emitWarning = emitWarning; } if (packageJson.version) { @@ -104,11 +110,23 @@ function loadApplicationPackage (packagePath: string) { } else if (packageJson.name) { app.name = packageJson.name; } + if (packageJson.desktopName) { + app.setDesktopName(packageJson.desktopName); + } else { + app.setDesktopName(`${app.name}.desktop`); + } + // Set v8 flags, deliberately lazy load so that apps that do not use this + // feature do not pay the price + if (packageJson.v8Flags) { + (await import('node:v8')).setFlagsFromString(packageJson.v8Flags); + } appPath = packagePath; } + let filePath: string; + try { - const filePath = Module._resolveFilename(packagePath, module, true); + filePath = (Module as any)._resolveFilename(packagePath, null, true); app.setAppPath(appPath || path.dirname(filePath)); } catch (e) { showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${(e as Error).message}`); @@ -116,7 +134,7 @@ function loadApplicationPackage (packagePath: string) { } // Run the app. - Module._load(packagePath, module, true); + await import(url.pathToFileURL(filePath).toString()); } catch (e) { console.error('App threw an error during load'); console.error((e as Error).stack || e); @@ -131,16 +149,16 @@ function showErrorMessage (message: string) { } async function loadApplicationByURL (appUrl: string) { - const { loadURL } = await import('./default_app'); + const { loadURL } = await import('./default_app.js'); loadURL(appUrl); } async function loadApplicationByFile (appPath: string) { - const { loadFile } = await import('./default_app'); + const { loadFile } = await import('./default_app.js'); loadFile(appPath); } -function startRepl () { +async function startRepl () { if (process.platform === 'win32') { console.error('Electron REPL not currently supported on Windows'); process.exit(1); @@ -161,8 +179,8 @@ function startRepl () { Using: Node.js ${nodeVersion} and Electron.js ${electronVersion} `); - const { REPLServer } = require('repl'); - const repl = new REPLServer({ + const { start } = await import('node:repl'); + const repl = start({ prompt: '> ' }).on('exit', () => { process.exit(0); @@ -215,8 +233,8 @@ function startRepl () { const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron']; - const defaultComplete = repl.completer; - repl.completer = (line: string, callback: Function) => { + const defaultComplete: Function = repl.completer; + (repl as any).completer = (line: string, callback: Function) => { const lastSpace = line.lastIndexOf(' '); const currentSymbol = line.substring(lastSpace + 1, repl.cursor); @@ -236,14 +254,15 @@ function startRepl () { // start the default app. if (option.file && !option.webdriver) { const file = option.file; + // eslint-disable-next-line n/no-deprecated-api const protocol = url.parse(file).protocol; const extension = path.extname(file); if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') { - loadApplicationByURL(file); + await loadApplicationByURL(file); } else if (extension === '.html' || extension === '.htm') { - loadApplicationByFile(path.resolve(file)); + await loadApplicationByFile(path.resolve(file)); } else { - loadApplicationPackage(file); + await loadApplicationPackage(file); } } else if (option.version) { console.log('v' + process.versions.electron); @@ -252,7 +271,7 @@ if (option.file && !option.webdriver) { console.log(process.versions.modules); process.exit(0); } else if (option.interactive) { - startRepl(); + await startRepl(); } else { if (!option.noHelp) { const welcomeMessage = ` @@ -275,5 +294,5 @@ Options: console.log(welcomeMessage); } - loadApplicationByFile('index.html'); + await loadApplicationByFile('index.html'); } diff --git a/default_app/package.json b/default_app/package.json index d6c736cbc5253..65fee98c59eb3 100644 --- a/default_app/package.json +++ b/default_app/package.json @@ -1,5 +1,6 @@ { "name": "electron", "productName": "Electron", - "main": "main.js" + "main": "main.js", + "type": "module" } diff --git a/default_app/preload.ts b/default_app/preload.ts index aedaa6e6b7aed..aa8c79ea11cca 100644 --- a/default_app/preload.ts +++ b/default_app/preload.ts @@ -1,4 +1,4 @@ -import { ipcRenderer, contextBridge } from 'electron/renderer'; +const { ipcRenderer, contextBridge } = require('electron/renderer'); const policy = window.trustedTypes.createPolicy('electron-default-app', { // we trust the SVG contents diff --git a/docs/README.md b/docs/README.md index e346d985d755d..98ae1ad9a79a4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,6 @@ an issue: ### Getting started * [Introduction](tutorial/introduction.md) -* [Quick Start](tutorial/quick-start.md) * [Process Model](tutorial/process-model.md) ### Learning the basics @@ -37,12 +36,13 @@ an issue: * [Offline/Online Detection](tutorial/online-offline-events.md) * [Represented File for macOS BrowserWindows](tutorial/represented-file.md) * [Native File Drag & Drop](tutorial/native-file-drag-drop.md) + * [Navigation History](tutorial/navigation-history.md) * [Offscreen Rendering](tutorial/offscreen-rendering.md) * [Dark Mode](tutorial/dark-mode.md) * [Web embeds in Electron](tutorial/web-embeds.md) * [Boilerplates and CLIs](tutorial/boilerplates-and-clis.md) * [Boilerplate vs CLI](tutorial/boilerplates-and-clis.md#boilerplate-vs-cli) - * [electron-forge](tutorial/boilerplates-and-clis.md#electron-forge) + * [Electron Forge](tutorial/boilerplates-and-clis.md#electron-forge) * [electron-builder](tutorial/boilerplates-and-clis.md#electron-builder) * [electron-react-boilerplate](tutorial/boilerplates-and-clis.md#electron-react-boilerplate) * [Other Tools and Boilerplates](tutorial/boilerplates-and-clis.md#other-tools-and-boilerplates) @@ -68,6 +68,7 @@ an issue: * [Mac App Store](tutorial/mac-app-store-submission-guide.md) * [Windows Store](tutorial/windows-store-guide.md) * [Snapcraft](tutorial/snapcraft.md) + * [ASAR Archives](tutorial/asar-archives.md) * [Updates](tutorial/updates.md) * [Getting Support](tutorial/support.md) @@ -82,7 +83,6 @@ These individual tutorials expand on topics discussed in the guide above. * Electron Releases & Developer Feedback * [Versioning Policy](tutorial/electron-versioning.md) * [Release Timelines](tutorial/electron-timelines.md) -* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md) --- @@ -90,7 +90,6 @@ These individual tutorials expand on topics discussed in the guide above. ## API References -* [Synopsis](api/synopsis.md) * [Process Object](api/process.md) * [Supported Command Line Switches](api/command-line-switches.md) * [Environment Variables](api/environment-variables.md) @@ -99,7 +98,6 @@ These individual tutorials expand on topics discussed in the guide above. ### Custom DOM Elements: -* [`File` Object](api/file-object.md) * [`` Tag](api/webview-tag.md) * [`window.open` Function](api/window-open.md) @@ -107,9 +105,10 @@ These individual tutorials expand on topics discussed in the guide above. * [app](api/app.md) * [autoUpdater](api/auto-updater.md) -* [BrowserView](api/browser-view.md) +* [BaseWindow](api/base-window.md) * [BrowserWindow](api/browser-window.md) * [contentTracing](api/content-tracing.md) +* [desktopCapturer](api/desktop-capturer.md) * [dialog](api/dialog.md) * [globalShortcut](api/global-shortcut.md) * [inAppPurchase](api/in-app-purchase.md) @@ -118,21 +117,27 @@ These individual tutorials expand on topics discussed in the guide above. * [MenuItem](api/menu-item.md) * [MessageChannelMain](api/message-channel-main.md) * [MessagePortMain](api/message-port-main.md) +* [nativeTheme](api/native-theme.md) * [net](api/net.md) * [netLog](api/net-log.md) -* [nativeTheme](api/native-theme.md) * [Notification](api/notification.md) * [powerMonitor](api/power-monitor.md) * [powerSaveBlocker](api/power-save-blocker.md) * [protocol](api/protocol.md) +* [pushNotifications](api/push-notifications.md) +* [safeStorage](api/safe-storage.md) * [screen](api/screen.md) +* [ServiceWorkerMain](api/service-worker-main.md) * [session](api/session.md) * [ShareMenu](api/share-menu.md) * [systemPreferences](api/system-preferences.md) * [TouchBar](api/touch-bar.md) * [Tray](api/tray.md) +* [utilityProcess](api/utility-process.md) +* [View](api/view.md) * [webContents](api/web-contents.md) * [webFrameMain](api/web-frame-main.md) +* [WebContentsView](api/web-contents-view.md) ### Modules for the Renderer Process (Web Page): @@ -142,11 +147,10 @@ These individual tutorials expand on topics discussed in the guide above. ### Modules for Both Processes: -* [clipboard](api/clipboard.md) +* [clipboard](api/clipboard.md) (non-sandboxed renderers only) * [crashReporter](api/crash-reporter.md) -* [desktopCapturer](api/desktop-capturer.md) * [nativeImage](api/native-image.md) -* [shell](api/shell.md) +* [shell](api/shell.md) (non-sandboxed renderers only) ## Development diff --git a/docs/api-history.schema.json b/docs/api-history.schema.json new file mode 100644 index 0000000000000..137cb02bbb805 --- /dev/null +++ b/docs/api-history.schema.json @@ -0,0 +1,47 @@ +{ + "title": "JSON schema for API history blocks in Electron documentation", + "$schema": "http://json-schema.org/draft-07/schema#", + "$comment": "If you change this schema, remember to edit the TypeScript interfaces in the linting script.", + "definitions": { + "baseChangeSchema": { + "type": "object", + "properties": { + "pr-url": { + "description": "URL to the 'main' GitHub Pull Request for the change (i.e. not a backport PR)", + "type": "string", "pattern": "^https://github.com/electron/electron/pull/\\d+$", + "examples": [ "https://github.com/electron/electron/pull/26789" ] + }, + "breaking-changes-header": { + "description": "Heading ID for the change in `electron/docs/breaking-changes.md`", + "type": "string", "minLength": 3, + "examples": [ "deprecated-browserwindowsettrafficlightpositionposition" ] + }, + "description": { + "description": "Short description of the change", + "type": "string", "minLength": 3, "maxLength": 120, + "examples": [ "Made `trafficLightPosition` option work for `customButtonOnHover`." ] + } + }, + "required": [ "pr-url" ], + "additionalProperties": false + }, + "addedChangeSchema": { + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" } ] + }, + "deprecatedChangeSchema": { + "$comment": "TODO: Make 'breaking-changes-header' required in the future.", + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" } ] + }, + "changesChangeSchema": { + "$comment": "Unlike RFC, added `'type': 'object'` to appease AJV strict mode", + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" }, { "type": "object", "required": [ "description" ] } ] + } + }, + "type": "object", + "properties": { + "added": { "type": "array", "minItems": 1, "maxItems": 1, "items": { "$ref": "#/definitions/addedChangeSchema" } }, + "deprecated": { "type": "array", "minItems": 1, "maxItems": 1, "items": { "$ref": "#/definitions/deprecatedChangeSchema" } }, + "changes": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/changesChangeSchema" } } + }, + "additionalProperties": false +} diff --git a/docs/api/accelerator.md b/docs/api/accelerator.md index b6f7d475dabdf..caefba6488f96 100644 --- a/docs/api/accelerator.md +++ b/docs/api/accelerator.md @@ -4,7 +4,7 @@ Accelerators are strings that can contain multiple modifiers and a single key code, combined by the `+` character, and are used to define keyboard shortcuts -throughout your application. +throughout your application. Accelerators are case insensitive. Examples: @@ -15,7 +15,7 @@ Shortcuts are registered with the [`globalShortcut`](global-shortcut.md) module using the [`register`](global-shortcut.md#globalshortcutregisteraccelerator-callback) method, i.e. -```javascript +```js const { app, globalShortcut } = require('electron') app.whenReady().then(() => { @@ -55,7 +55,7 @@ The `Super` (or `Meta`) key is mapped to the `Windows` key on Windows and Linux * `0` to `9` * `A` to `Z` * `F1` to `F24` -* Punctuation like `~`, `!`, `@`, `#`, `$`, etc. +* Various Punctuation: `)`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `:`, `;`, `:`, `+`, `=`, `<`, `,`, `_`, `-`, `>`, `.`, `?`, `/`, `~`, `` ` ``, `{`, `]`, `[`, `|`, `\`, `}`, `"` * `Plus` * `Space` * `Tab` diff --git a/docs/api/app.md b/docs/api/app.md old mode 100755 new mode 100644 index 960bed3dc8782..e7e635e21bd55 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -7,7 +7,7 @@ Process: [Main](../glossary.md#main-process) The following example shows how to quit the application when the last window is closed: -```javascript +```js const { app } = require('electron') app.on('window-all-closed', () => { app.quit() @@ -23,8 +23,7 @@ The `app` object emits the following events: Emitted when the application has finished basic startup. On Windows and Linux, the `will-finish-launching` event is the same as the `ready` event; on macOS, this event represents the `applicationWillFinishLaunching` notification of -`NSApplication`. You would usually set up listeners for the `open-file` and -`open-url` events here, and start the crash reporter and auto updater. +`NSApplication`. In most cases, you should do everything in the `ready` event handler. @@ -33,7 +32,7 @@ In most cases, you should do everything in the `ready` event handler. Returns: * `event` Event -* `launchInfo` Record | [NotificationResponse](structures/notification-response.md) _macOS_ +* `launchInfo` Record\ | [NotificationResponse](structures/notification-response.md) _macOS_ Emitted once, when Electron has finished initializing. On macOS, `launchInfo` holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification) @@ -42,6 +41,10 @@ that was used to open the application, if it was launched from Notification Cent You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()` to get a Promise that is fulfilled when Electron is initialized. +**Note**: The `ready` event is only fired after the main process has finished running the first +tick of the event loop. If an Electron API needs to be called before the `ready` event, ensure +that it is called synchronously in the top-level context of the main process. + ### Event: 'window-all-closed' Emitted when all windows have been closed. @@ -64,7 +67,7 @@ Calling `event.preventDefault()` will prevent the default behavior, which is terminating the application. **Note:** If application quit was initiated by `autoUpdater.quitAndInstall()`, -then `before-quit` is emitted *after* emitting `close` event on all windows and +then `before-quit` is emitted _after_ emitting `close` event on all windows and closing them. **Note:** On Windows, this event will not be emitted if the app is closed due @@ -128,12 +131,9 @@ Emitted when the user wants to open a URL with the application. Your application `Info.plist` file must define the URL scheme within the `CFBundleURLTypes` key, and set `NSPrincipalClass` to `AtomApplication`. -You should call `event.preventDefault()` if you want to handle this event. - As with the `open-file` event, be sure to register a listener for the `open-url` -event early in your application startup to detect if the the application being -is being opened to handle a URL. If you register the listener in response to a -`ready` event, you'll miss URLs that trigger the launch of your application. +event early in your application startup to detect if the application is being opened to handle a URL. +If you register the listener in response to a `ready` event, you'll miss URLs that trigger the launch of your application. ### Event: 'activate' _macOS_ @@ -153,9 +153,20 @@ Returns: * `event` Event -Emitted when mac application become active. Difference from `activate` event is +Emitted when the application becomes active. This differs from the `activate` event in that `did-become-active` is emitted every time the app becomes active, not only -when Dock icon is clicked or application is re-launched. +when Dock icon is clicked or application is re-launched. It is also emitted when a user +switches to the app via the macOS App Switcher. + +### Event: 'did-resign-active' _macOS_ + +Returns: + +* `event` Event + +Emitted when the app is no longer active and doesn’t have focus. This can be triggered, +for example, by clicking on another application or by using the macOS App Switcher to +switch to another application. ### Event: 'continue-activity' _macOS_ @@ -288,7 +299,7 @@ Emitted when failed to verify the `certificate` for `url`, to trust the certificate you should prevent the default behavior with `event.preventDefault()` and call `callback(true)`. -```javascript +```js const { app } = require('electron') app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { @@ -320,7 +331,7 @@ and `callback` can be called with an entry filtered from the list. Using `event.preventDefault()` prevents the application from using the first certificate from the store. -```javascript +```js const { app } = require('electron') app.on('select-client-certificate', (event, webContents, url, list, callback) => { @@ -334,9 +345,10 @@ app.on('select-client-certificate', (event, webContents, url, list, callback) => Returns: * `event` Event -* `webContents` [WebContents](web-contents.md) +* `webContents` [WebContents](web-contents.md) (optional) * `authenticationResponseDetails` Object * `url` URL + * `pid` number * `authInfo` Object * `isProxy` boolean * `scheme` string @@ -347,13 +359,13 @@ Returns: * `username` string (optional) * `password` string (optional) -Emitted when `webContents` wants to do basic auth. +Emitted when `webContents` or [Utility process](../glossary.md#utility-process) wants to do basic auth. The default behavior is to cancel all authentications. To override this you should prevent the default behavior with `event.preventDefault()` and call `callback(username, password)` with the credentials. -```javascript +```js const { app } = require('electron') app.on('login', (event, webContents, details, authInfo, callback) => { @@ -370,53 +382,13 @@ page. Emitted whenever there is a GPU info update. -### Event: 'gpu-process-crashed' _Deprecated_ - -Returns: - -* `event` Event -* `killed` boolean - -Emitted when the GPU process crashes or is killed. - -**Deprecated:** This event is superceded by the `child-process-gone` event -which contains more information about why the child process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. - -### Event: 'renderer-process-crashed' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `killed` boolean - -Emitted when the renderer process of `webContents` crashes or is killed. - -**Deprecated:** This event is superceded by the `render-process-gone` event -which contains more information about why the render process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. - ### Event: 'render-process-gone' Returns: * `event` Event * `webContents` [WebContents](web-contents.md) -* `details` Object - * `reason` string - The reason the render process is gone. Possible values: - * `clean-exit` - Process exited with an exit code of zero - * `abnormal-exit` - Process exited with a non-zero exit code - * `killed` - Process was sent a SIGTERM or otherwise killed externally - * `crashed` - Process crashed - * `oom` - Process ran out of memory - * `launch-failed` - Process never successfully launched - * `integrity-failure` - Windows code integrity checks failed - * `exitCode` Integer - The exit code of the process, unless `reason` is - `launch-failed`, in which case `exitCode` will be a platform-specific - launch failure error code. +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) Emitted when the renderer process unexpectedly disappears. This is normally because it was crashed or killed. @@ -444,7 +416,7 @@ Returns: * `launch-failed` - Process never successfully launched * `integrity-failure` - Windows code integrity checks failed * `exitCode` number - The exit code for the process - (e.g. status from waitpid if on posix, from GetExitCodeProcess on Windows). + (e.g. status from waitpid if on POSIX, from GetExitCodeProcess on Windows). * `serviceName` string (optional) - The non-localized name of the process. * `name` string (optional) - The name of the process. Examples for utility: `Audio Service`, `Content Decryption Module Service`, `Network Service`, `Video Capture`, etc. @@ -473,7 +445,7 @@ Returns: Emitted when Electron has created a new `session`. -```javascript +```js const { app } = require('electron') app.on('session-created', (session) => { @@ -498,6 +470,10 @@ and `workingDirectory` is its current working directory. Usually applications respond to this by making their primary window focused and non-minimized. +**Note:** `argv` will not be exactly the same list of arguments as those passed +to the second instance. The order might change and additional arguments might be appended. +If you need to maintain the exact same arguments, it's advised to use `additionalData` instead. + **Note:** If the second instance is started by a different user than the first, the `argv` array will not include the arguments. This event is guaranteed to be emitted after the `ready` event of `app` @@ -538,23 +514,23 @@ and `will-quit` events will not be emitted. * `args` string[] (optional) * `execPath` string (optional) -Relaunches the app when current instance exits. +Relaunches the app when the current instance exits. By default, the new instance will use the same working directory and command line -arguments with current instance. When `args` is specified, the `args` will be -passed as command line arguments instead. When `execPath` is specified, the -`execPath` will be executed for relaunch instead of current app. +arguments as the current instance. When `args` is specified, the `args` will be +passed as the command line arguments instead. When `execPath` is specified, the +`execPath` will be executed for the relaunch instead of the current app. -Note that this method does not quit the app when executed, you have to call +Note that this method does not quit the app when executed. You have to call `app.quit` or `app.exit` after calling `app.relaunch` to make the app restart. -When `app.relaunch` is called for multiple times, multiple instances will be -started after current instance exited. +When `app.relaunch` is called multiple times, multiple instances will be +started after the current instance exits. -An example of restarting current instance immediately and adding a new command +An example of restarting the current instance immediately and adding a new command line argument to the new instance: -```javascript +```js const { app } = require('electron') app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) }) @@ -715,7 +691,9 @@ To set the locale, you'll want to use a command line switch at app startup, whic **Note:** When distributing your packaged app, you have to also ship the `locales` folder. -**Note:** On Windows, you have to call it after the `ready` events gets emitted. +**Note:** This API must be called after the `ready` event is emitted. + +**Note:** To see example return values of this API compared to other locale and language APIs, see [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). ### `app.getLocaleCountryCode()` @@ -723,6 +701,51 @@ Returns `string` - User operating system's locale two-letter [ISO 3166](https:// **Note:** When unable to detect locale country code, it returns empty string. +### `app.getSystemLocale()` + +Returns `string` - The current system locale. On Windows and Linux, it is fetched using Chromium's `i18n` library. On macOS, `[NSLocale currentLocale]` is used instead. To get the user's current system language, which is not always the same as the locale, it is better to use [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). + +Different operating systems also use the regional data differently: + +* Windows 11 uses the regional format for numbers, dates, and times. +* macOS Monterey uses the region for formatting numbers, dates, times, and for selecting the currency symbol to use. + +Therefore, this API can be used for purposes such as choosing a format for rendering dates and times in a calendar app, especially when the developer wants the format to be consistent with the OS. + +**Note:** This API must be called after the `ready` event is emitted. + +**Note:** To see example return values of this API compared to other locale and language APIs, see [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). + +### `app.getPreferredSystemLanguages()` + +Returns `string[]` - The user's preferred system languages from most preferred to least preferred, including the country codes if applicable. A user can modify and add to this list on Windows or macOS through the Language and Region settings. + +The API uses `GlobalizationPreferences` (with a fallback to `GetSystemPreferredUILanguages`) on Windows, `\[NSLocale preferredLanguages\]` on macOS, and `g_get_language_names` on Linux. + +This API can be used for purposes such as deciding what language to present the application in. + +Here are some examples of return values of the various language and locale APIs with different configurations: + +On Windows, given application locale is German, the regional format is Finnish (Finland), and the preferred system languages from most to least preferred are French (Canada), English (US), Simplified Chinese (China), Finnish, and Spanish (Latin America): + +```js +app.getLocale() // 'de' +app.getSystemLocale() // 'fi-FI' +app.getPreferredSystemLanguages() // ['fr-CA', 'en-US', 'zh-Hans-CN', 'fi', 'es-419'] +``` + +On macOS, given the application locale is German, the region is Finland, and the preferred system languages from most to least preferred are French (Canada), English (US), Simplified Chinese, and Spanish (Latin America): + +```js +app.getLocale() // 'de' +app.getSystemLocale() // 'fr-FI' +app.getPreferredSystemLanguages() // ['fr-CA', 'en-US', 'zh-Hans-FI', 'es-419'] +``` + +Both the available languages and regions and the possible return values differ between the two operating systems. + +As can be seen with the example above, on Windows, it is possible that a preferred system language has no country code, and that one of the preferred system languages corresponds with the language used for the regional format. On macOS, the region serves more as a default country code: the user doesn't need to have Finnish as a preferred language to use Finland as the region,and the country code `FI` is used as the country code for preferred system languages that do not have associated countries in the language name. + ### `app.addRecentDocument(path)` _macOS_ _Windows_ * `path` string @@ -763,7 +786,7 @@ editor. Please refer to [Apple's documentation][CFBundleURLTypes] for details. **Note:** In a Windows Store environment (when packaged as an `appx`) this API will return `true` for all calls but the registry key it sets won't be accessible by other applications. In order to register your Windows Store application -as a default protocol handler you must [declare the protocol in your manifest](https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol). +as a default protocol handler you must [declare the protocol in your manifest](https://learn.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol). The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` internally. @@ -892,7 +915,7 @@ List, nor will it be displayed. Here's a very simple example of creating a custom Jump List: -```javascript +```js const { app } = require('electron') app.setJumpList([ @@ -912,7 +935,7 @@ app.setJumpList([ title: 'Tool A', program: process.execPath, args: '--run-tool-a', - icon: process.execPath, + iconPath: process.execPath, iconIndex: 0, description: 'Runs Tool A' }, @@ -921,7 +944,7 @@ app.setJumpList([ title: 'Tool B', program: process.execPath, args: '--run-tool-b', - icon: process.execPath, + iconPath: process.execPath, iconIndex: 0, description: 'Runs Tool B' } @@ -952,7 +975,7 @@ app.setJumpList([ ### `app.requestSingleInstanceLock([additionalData])` -* `additionalData` Record (optional) - A JSON object containing additional data to send to the first instance. +* `additionalData` Record\ (optional) - A JSON object containing additional data to send to the first instance. Returns `boolean` @@ -975,8 +998,8 @@ use this method to ensure single instance. An example of activating the window of primary instance when a second instance starts: -```javascript -const { app } = require('electron') +```js +const { app, BrowserWindow } = require('electron') let myWindow = null const additionalData = { myKey: 'myValue' } @@ -996,9 +1019,9 @@ if (!gotTheLock) { } }) - // Create myWindow, load the rest of the app, etc... app.whenReady().then(() => { - myWindow = createWindow() + myWindow = new BrowserWindow({}) + myWindow.loadURL('https://electronjs.org') }) } ``` @@ -1087,11 +1110,11 @@ indicates success while any other value indicates failure according to Chromium resolver will attempt to use the system's DNS settings to do DNS lookups itself. Enabled by default on macOS, disabled by default on Windows and Linux. - * `secureDnsMode` string (optional) - Can be "off", "automatic" or "secure". - Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be - performed. When "automatic", DoH lookups will be performed first if DoH is + * `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'. + Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be + performed. When 'automatic', DoH lookups will be performed first if DoH is available, and insecure DNS lookups will be performed as a fallback. When - "secure", only DoH lookups will be performed. Defaults to "automatic". + 'secure', only DoH lookups will be performed. Defaults to 'automatic'. * `secureDnsServers` string[] (optional) - A list of DNS-over-HTTP server templates. See [RFC8484 § 3][] for details on the template format. Most servers support the POST method; the template for such servers is @@ -1121,11 +1144,15 @@ case the user's DNS configuration does not include a provider that supports DoH. ```js -app.configureHostResolver({ - secureDnsMode: 'secure', - secureDnsServers: [ - 'https://cloudflare-dns.com/dns-query' - ] +const { app } = require('electron') + +app.whenReady().then(() => { + app.configureHostResolver({ + secureDnsMode: 'secure', + secureDnsServers: [ + 'https://cloudflare-dns.com/dns-query' + ] + }) }) ``` @@ -1197,7 +1224,7 @@ For `infoType` equal to `basic`: } ``` -Using `basic` should be preferred if only basic information like `vendorId` or `driverId` is needed. +Using `basic` should be preferred if only basic information like `vendorId` or `deviceId` is needed. ### `app.setBadgeCount([count])` _Linux_ _macOS_ @@ -1213,6 +1240,9 @@ On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. **Note:** Unity launcher requires a `.desktop` file to work. For more information, please read the [Unity integration documentation][unity-requirement]. +**Note:** On macOS, you need to ensure that your application has the permission +to display notifications for this method to work. + ### `app.getBadgeCount()` _Linux_ _macOS_ Returns `Integer` - The current value displayed in the counter badge. @@ -1224,10 +1254,10 @@ Returns `boolean` - Whether the current desktop environment is Unity launcher. ### `app.getLoginItemSettings([options])` _macOS_ _Windows_ * `options` Object (optional) - * `path` string (optional) _Windows_ - The executable path to compare against. - Defaults to `process.execPath`. - * `args` string[] (optional) _Windows_ - The command-line arguments to compare - against. Defaults to an empty array. + * `type` string (optional) _macOS_ - Can be one of `mainAppService`, `agentService`, `daemonService`, or `loginItemService`. Defaults to `mainAppService`. Only available on macOS 13 and up. See [app.setLoginItemSettings](app.md#appsetloginitemsettingssettings-macos-windows) for more information about each type. + * `serviceName` string (optional) _macOS_ - The name of the service. Required if `type` is non-default. Only available on macOS 13 and up. + * `path` string (optional) _Windows_ - The executable path to compare against. Defaults to `process.execPath`. + * `args` string[] (optional) _Windows_ - The command-line arguments to compare against. Defaults to an empty array. If you provided `path` and `args` options to `app.setLoginItemSettings`, then you need to pass the same arguments here for `openAtLogin` to be set correctly. @@ -1235,17 +1265,11 @@ need to pass the same arguments here for `openAtLogin` to be set correctly. Returns `Object`: * `openAtLogin` boolean - `true` if the app is set to open at login. -* `openAsHidden` boolean _macOS_ - `true` if the app is set to open as hidden at login. - This setting is not available on [MAS builds][mas-builds]. -* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login - automatically. This setting is not available on [MAS builds][mas-builds]. -* `wasOpenedAsHidden` boolean _macOS_ - `true` if the app was opened as a hidden login - item. This indicates that the app should not open any windows at startup. - This setting is not available on [MAS builds][mas-builds]. -* `restoreState` boolean _macOS_ - `true` if the app was opened as a login item that - should restore the state from the previous session. This indicates that the - app should restore the windows that were open the last time the app was - closed. This setting is not available on [MAS builds][mas-builds]. +* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up. +* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically. +* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. +* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. +* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`. * `executableWillLaunchAtLogin` boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments. * `launchItems` Object[] _Windows_ * `name` string _Windows_ - name value of a registry entry. @@ -1259,10 +1283,13 @@ Returns `Object`: * `settings` Object * `openAtLogin` boolean (optional) - `true` to open the app at login, `false` to remove the app as a login item. Defaults to `false`. - * `openAsHidden` boolean (optional) _macOS_ - `true` to open the app as hidden. Defaults to - `false`. The user can edit this setting from the System Preferences so - `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app - is opened to know the current value. This setting is not available on [MAS builds][mas-builds]. + * `openAsHidden` boolean (optional) _macOS_ _Deprecated_ - `true` to open the app as hidden. Defaults to `false`. The user can edit this setting from the System Preferences so `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app is opened to know the current value. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. + * `type` string (optional) _macOS_ - The type of service to add as a login item. Defaults to `mainAppService`. Only available on macOS 13 and up. + * `mainAppService` - The primary application. + * `agentService` - The property list name for a launch agent. The property list name must correspond to a property list in the app’s `Contents/Library/LaunchAgents` directory. + * `daemonService` string (optional) _macOS_ - The property list name for a launch agent. The property list name must correspond to a property list in the app’s `Contents/Library/LaunchDaemons` directory. + * `loginItemService` string (optional) _macOS_ - The property list name for a login item service. The property list name must correspond to a property list in the app’s `Contents/Library/LoginItems` directory. + * `serviceName` string (optional) _macOS_ - The name of the service. Required if `type` is non-default. Only available on macOS 13 and up. * `path` string (optional) _Windows_ - The executable to launch at login. Defaults to `process.execPath`. * `args` string[] (optional) _Windows_ - The command-line arguments to pass to @@ -1271,27 +1298,34 @@ Returns `Object`: * `enabled` boolean (optional) _Windows_ - `true` will change the startup approved registry key and `enable / disable` the App in Task Manager and Windows Settings. Defaults to `true`. * `name` string (optional) _Windows_ - value name to write into registry. Defaults to the app's AppUserModelId(). + Set the app's login item settings. To work with Electron's `autoUpdater` on Windows, which uses [Squirrel][Squirrel-Windows], -you'll want to set the launch path to Update.exe, and pass arguments that specify your -application name. For example: +you'll want to set the launch path to your executable's name but a directory up, which is +a stub application automatically generated by Squirrel which will automatically launch the +latest version. + +``` js +const { app } = require('electron') +const path = require('node:path') -``` javascript const appFolder = path.dirname(process.execPath) -const updateExe = path.resolve(appFolder, '..', 'Update.exe') -const exeName = path.basename(process.execPath) +const ourExeName = path.basename(process.execPath) +const stubLauncher = path.resolve(appFolder, '..', ourExeName) app.setLoginItemSettings({ openAtLogin: true, - path: updateExe, + path: stubLauncher, args: [ - '--processStart', `"${exeName}"`, - '--process-start-args', `"--hidden"` + // You might want to pass a parameter here indicating that this + // app was launched via login, but you don't have to ] }) ``` +For more information about setting different services as login items on macOS 13 and up, see [`SMAppService`](https://developer.apple.com/documentation/servicemanagement/smappservice?language=objc). + ### `app.isAccessibilitySupportEnabled()` _macOS_ _Windows_ Returns `boolean` - `true` if Chrome's accessibility support is enabled, @@ -1313,7 +1347,7 @@ This API must be called after the `ready` event is emitted. ### `app.showAboutPanel()` -Show the app's about panel options. These options can be overridden with `app.setAboutPanelOptions(options)`. +Show the app's about panel options. These options can be overridden with `app.setAboutPanelOptions(options)`. This function runs asynchronously. ### `app.setAboutPanelOptions(options)` @@ -1325,7 +1359,7 @@ Show the app's about panel options. These options can be overridden with `app.se * `credits` string (optional) _macOS_ _Windows_ - Credit information. * `authors` string[] (optional) _Linux_ - List of app authors. * `website` string (optional) _Linux_ - The app's website. - * `iconPath` string (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. + * `iconPath` string (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. On Windows, a 48x48 PNG will result in the best visual quality. Set the about panel options. This will override the values defined in the app's `.plist` file on macOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults. @@ -1346,11 +1380,22 @@ Show the platform's native emoji picker. Returns `Function` - This function **must** be called once you have finished accessing the security scoped file. If you do not remember to stop accessing the bookmark, [kernel resources will be leaked](https://developer.apple.com/reference/foundation/nsurl/1417051-startaccessingsecurityscopedreso?language=objc) and your app will lose its ability to reach outside the sandbox completely, until your app is restarted. ```js -// Start accessing the file. -const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(data) -// You can now access the file outside of the sandbox 🎉 +const { app, dialog } = require('electron') +const fs = require('node:fs') -// Remember to stop accessing the file once you've finished with it. +let filepath +let bookmark + +dialog.showOpenDialog(null, { securityScopedBookmarks: true }).then(({ filePaths, bookmarks }) => { + filepath = filePaths[0] + bookmark = bookmarks[0] + fs.readFileSync(filepath) +}) + +// ... restart app ... + +const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(bookmark) +fs.readFileSync(filepath) stopAccessingSecurityScopedResource() ``` @@ -1358,7 +1403,7 @@ Start accessing a security scoped resource. With this method Electron applicatio ### `app.enableSandbox()` -Enables full sandbox mode on the app. This means that all renderers will be launched sandboxed, regardless of the value of the `sandbox` flag in WebPreferences. +Enables full sandbox mode on the app. This means that all renderers will be launched sandboxed, regardless of the value of the `sandbox` flag in [`WebPreferences`](structures/web-preferences.md). This method can only be called before app is ready. @@ -1391,6 +1436,8 @@ By default, if an app of the same name as the one being moved exists in the Appl For example: ```js +const { app, dialog } = require('electron') + app.moveToApplicationsFolder({ conflictHandler: (conflictType) => { if (conflictType === 'exists') { @@ -1426,6 +1473,56 @@ details. **Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed. +### `app.setProxy(config)` + +* `config` [ProxyConfig](structures/proxy-config.md) + +Returns `Promise` - Resolves when the proxy setting process is complete. + +Sets the proxy settings for networks requests made without an associated [Session](session.md). +Currently this will affect requests made with [Net](net.md) in the [utility process](../glossary.md#utility-process) +and internal requests made by the runtime (ex: geolocation queries). + +This method can only be called after app is ready. + +#### `app.resolveProxy(url)` + +* `url` URL + +Returns `Promise` - Resolves with the proxy information for `url` that will be used when attempting to make requests using [Net](net.md) in the [utility process](../glossary.md#utility-process). + +### `app.setClientCertRequestPasswordHandler(handler)` _Linux_ + +* `handler` Function\\> + * `clientCertRequestParams` Object + * `hostname` string - the hostname of the site requiring a client certificate + * `tokenName` string - the token (or slot) name of the cryptographic device + * `isRetry` boolean - whether there have been previous failed attempts at prompting the password + + Returns `Promise` - Resolves with the password + +The handler is called when a password is needed to unlock a client certificate for +`hostname`. + +```js +const { app } = require('electron') + +async function passwordPromptUI (text) { + return new Promise((resolve, reject) => { + // display UI to prompt user for password + // ... + // ... + resolve('the password') + }) +} + +app.setClientCertRequestPasswordHandler(async ({ hostname, tokenName, isRetry }) => { + const text = `Please sign in to ${tokenName} to authenticate to ${hostname} with your certificate` + const password = await passwordPromptUI(text) + return password +}) +``` + ## Properties ### `app.accessibilitySupportEnabled` _macOS_ _Windows_ @@ -1469,19 +1566,18 @@ dock on macOS. A `boolean` property that returns `true` if the app is packaged, `false` otherwise. For many apps, this property can be used to distinguish development and production environments. -[dock-menu]:https://developer.apple.com/macos/human-interface-guidelines/menus/dock-menus/ -[tasks]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[tasks]:https://learn.microsoft.com/en-us/windows/win32/shell/taskbar-extensions#tasks +[app-user-model-id]: https://learn.microsoft.com/en-us/windows/win32/shell/appids [electron-forge]: https://www.electronforge.io/ -[electron-packager]: https://github.com/electron/electron-packager +[electron-packager]: https://github.com/electron/packager [CFBundleURLTypes]: https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115 -[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme +[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/documentation/coreservices/1441725-lscopydefaulthandlerforurlscheme?language=objc [handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html [activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType [unity-requirement]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher [mas-builds]: ../tutorial/mac-app-store-submission-guide.md [Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows -[JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx +[JumpListBeginListMSDN]: https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-icustomdestinationlist-beginlist [about-panel-options]: https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc ### `app.name` @@ -1502,19 +1598,6 @@ This is the user agent that will be used when no user agent is set at the app has the same user agent. Set to a custom value as early as possible in your app's initialization to ensure that your overridden value is used. -### `app.runningUnderRosettaTranslation` _macOS_ _Readonly_ _Deprecated_ - -A `boolean` which when `true` indicates that the app is currently running -under the [Rosetta Translator Environment](https://en.wikipedia.org/wiki/Rosetta_(software)). - -You can use this property to prompt users to download the arm64 version of -your application when they are running the x64 version under Rosetta -incorrectly. - -**Deprecated:** This property is superceded by the `runningUnderARM64Translation` -property which detects when the app is being translated to ARM64 in both macOS -and Windows. - ### `app.runningUnderARM64Translation` _Readonly_ _macOS_ _Windows_ A `boolean` which when `true` indicates that the app is currently running under @@ -1523,5 +1606,4 @@ an ARM64 translator (like the macOS or Windows [WOW](https://en.wikipedia.org/wiki/Windows_on_Windows)). You can use this property to prompt users to download the arm64 version of -your application when they are running the x64 version under Rosetta -incorrectly. +your application when they are mistakenly running the x64 version under Rosetta or WOW. diff --git a/docs/api/auto-updater.md b/docs/api/auto-updater.md index d181dfaccb0ec..bf419f33ad70a 100644 --- a/docs/api/auto-updater.md +++ b/docs/api/auto-updater.md @@ -20,8 +20,9 @@ In addition, there are some subtle differences on each platform: On macOS, the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], meaning you don't need any special setup to make it work. For server-side -requirements, you can read [Server Support][server-support]. Note that [App -Transport Security](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) (ATS) applies to all requests made as part of the +requirements, you can read [Server Support][server-support]. Note that +[App Transport Security](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) +(ATS) applies to all requests made as part of the update process. Apps that need to disable ATS can add the `NSAllowsArbitraryLoads` key to their app's plist. @@ -31,22 +32,28 @@ This is a requirement of `Squirrel.Mac`. ### Windows On Windows, you have to install your app into a user's machine before you can -use the `autoUpdater`, so it is recommended that you use the -[electron-winstaller][installer-lib], [electron-forge][electron-forge-lib] or the [grunt-electron-installer][installer] package to generate a Windows installer. - -When using [electron-winstaller][installer-lib] or [electron-forge][electron-forge-lib] make sure you do not try to update your app [the first time it runs](https://github.com/electron/windows-installer#handling-squirrel-events) (Also see [this issue for more info](https://github.com/electron/electron/issues/7155)). It's also recommended to use [electron-squirrel-startup](https://github.com/mongodb-js/electron-squirrel-startup) to get desktop shortcuts for your app. - -The installer generated with Squirrel will create a shortcut icon with an +use the `autoUpdater`, so it is recommended that you use +[electron-winstaller][installer-lib] or [Electron Forge's Squirrel.Windows maker][electron-forge-lib] to generate a Windows installer. + +Apps built with Squirrel.Windows will trigger [custom launch events](https://github.com/Squirrel/Squirrel.Windows/blob/51f5e2cb01add79280a53d51e8d0cfa20f8c9f9f/docs/using/custom-squirrel-events-non-cs.md#application-startup-commands) +that must be handled by your Electron application to ensure proper setup and teardown. + +Squirrel.Windows apps will launch with the `--squirrel-firstrun` argument immediately +after installation. During this time, Squirrel.Windows will obtain a file lock on +your app, and `autoUpdater` requests will fail until the lock is released. In practice, +this means that you won't be able to check for updates on first launch for the first +few seconds. You can work around this by not checking for updates when `process.argv` +contains the `--squirrel-firstrun` flag or by setting a 10-second timeout on your +update checks (see [electron/electron#7155](https://github.com/electron/electron/issues/7155) +for more information). + +The installer generated with Squirrel.Windows will create a shortcut icon with an [Application User Model ID][app-user-model-id] in the format of `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, examples are `com.squirrel.slack.Slack` and `com.squirrel.code.Code`. You have to use the same ID for your app with `app.setAppUserModelId` API, otherwise Windows will not be able to pin your app properly in task bar. -Like Squirrel.Mac, Windows can host updates on S3 or any other static file host. -You can read the documents of [Squirrel.Windows][squirrel-windows] to get more details -about how Squirrel.Windows works. - ## Events The `autoUpdater` object emits the following events: @@ -61,7 +68,7 @@ Emitted when there is an error while updating. ### Event: 'checking-for-update' -Emitted when checking if an update has started. +Emitted when checking for an available update has started. ### Event: 'update-available' @@ -103,7 +110,7 @@ The `autoUpdater` object has the following methods: * `options` Object * `url` string - * `headers` Record (optional) _macOS_ - HTTP request headers. + * `headers` Record\ (optional) _macOS_ - HTTP request headers. * `serverType` string (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac] README for more information. @@ -136,9 +143,7 @@ application starts. [squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac [server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support -[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows -[installer]: https://github.com/electron/grunt-electron-installer [installer-lib]: https://github.com/electron/windows-installer -[electron-forge-lib]: https://github.com/electron-userland/electron-forge -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[electron-forge-lib]: https://www.electronforge.io/config/makers/squirrel.windows +[app-user-model-id]: https://learn.microsoft.com/en-us/windows/win32/shell/appids [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/base-window.md b/docs/api/base-window.md new file mode 100644 index 0000000000000..1cf5cb18e331f --- /dev/null +++ b/docs/api/base-window.md @@ -0,0 +1,1446 @@ +# BaseWindow + +> Create and control windows. + +Process: [Main](../glossary.md#main-process) + +> **Note** +> `BaseWindow` provides a flexible way to compose multiple web views in a +> single window. For windows with only a single, full-size web view, the +> [`BrowserWindow`](browser-window.md) class may be a simpler option. + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +// In the main process. +const { BaseWindow, WebContentsView } = require('electron') + +const win = new BaseWindow({ width: 800, height: 600 }) + +const leftView = new WebContentsView() +leftView.webContents.loadURL('https://electronjs.org') +win.contentView.addChildView(leftView) + +const rightView = new WebContentsView() +rightView.webContents.loadURL('https://github.com/electron/electron') +win.contentView.addChildView(rightView) + +leftView.setBounds({ x: 0, y: 0, width: 400, height: 600 }) +rightView.setBounds({ x: 400, y: 0, width: 400, height: 600 }) +``` + +## Parent and child windows + +By using `parent` option, you can create child windows: + +```js +const { BaseWindow } = require('electron') + +const parent = new BaseWindow() +const child = new BaseWindow({ parent }) +``` + +The `child` window will always show on top of the `parent` window. + +## Modal windows + +A modal window is a child window that disables parent window. To create a modal +window, you have to set both the `parent` and `modal` options: + +```js +const { BaseWindow } = require('electron') + +const parent = new BaseWindow() +const child = new BaseWindow({ parent, modal: true }) +``` + +## Platform notices + +* On macOS modal windows will be displayed as sheets attached to the parent window. +* On macOS the child windows will keep the relative position to parent window + when parent window moves, while on Windows and Linux child windows will not + move. +* On Linux the type of modal windows will be changed to `dialog`. +* On Linux many desktop environments do not support hiding a modal window. + +## Resource management + +When you add a [`WebContentsView`](web-contents-view.md) to a `BaseWindow` and the `BaseWindow` +is closed, the [`webContents`](web-contents.md) of the `WebContentsView` are not destroyed +automatically. + +It is your responsibility to close the `webContents` when you no longer need them, e.g. when +the `BaseWindow` is closed: + +```js +const { BaseWindow, WebContentsView } = require('electron') + +const win = new BaseWindow({ width: 800, height: 600 }) + +const view = new WebContentsView() +win.contentView.addChildView(view) + +win.on('closed', () => { + view.webContents.close() +}) +``` + +Unlike with a [`BrowserWindow`](browser-window.md), if you don't explicitly close the +`webContents`, you'll encounter memory leaks. + +## Class: BaseWindow + +> Create and control windows. + +Process: [Main](../glossary.md#main-process) + +`BaseWindow` is an [EventEmitter][event-emitter]. + +It creates a new `BaseWindow` with native properties as set by the `options`. + +### `new BaseWindow([options])` + +* `options` [BaseWindowConstructorOptions](structures/base-window-options.md?inline) (optional) + +### Instance Events + +Objects created with `new BaseWindow` emit the following events: + +**Note:** Some events are only available on specific operating systems and are +labeled as such. + +#### Event: 'close' + +Returns: + +* `event` Event + +Emitted when the window is going to be closed. It's emitted before the +`beforeunload` and `unload` event of the DOM. Calling `event.preventDefault()` +will cancel the close. + +Usually you would want to use the `beforeunload` handler to decide whether the +window should be closed, which will also be called when the window is +reloaded. In Electron, returning any value other than `undefined` would cancel the +close. For example: + +```js +window.onbeforeunload = (e) => { + console.log('I do not want to be closed') + + // Unlike usual browsers that a message box will be prompted to users, returning + // a non-void value will silently cancel the close. + // It is recommended to use the dialog API to let the user confirm closing the + // application. + e.returnValue = false +} +``` + +_**Note**: There is a subtle difference between the behaviors of `window.onbeforeunload = handler` and `window.addEventListener('beforeunload', handler)`. It is recommended to always set the `event.returnValue` explicitly, instead of only returning a value, as the former works more consistently within Electron._ + +#### Event: 'closed' + +Emitted when the window is closed. After you have received this event you should +remove the reference to the window and avoid using it any more. + +#### Event: 'query-session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. +Calling `event.preventDefault()` can delay the system shutdown, though it’s generally best +to respect the user’s choice to end the session. However, you may choose to use it if +ending the session puts the user at risk of losing data. + +#### Event: 'session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. Once this event fires, there is no way to prevent the session from ending. + +#### Event: 'blur' + +Returns: + +* `event` Event + +Emitted when the window loses focus. + +#### Event: 'focus' + +Returns: + +* `event` Event + +Emitted when the window gains focus. + +#### Event: 'show' + +Emitted when the window is shown. + +#### Event: 'hide' + +Emitted when the window is hidden. + +#### Event: 'maximize' + +Emitted when window is maximized. + +#### Event: 'unmaximize' + +Emitted when the window exits from a maximized state. + +#### Event: 'minimize' + +Emitted when the window is minimized. + +#### Event: 'restore' + +Emitted when the window is restored from a minimized state. + +#### Event: 'will-resize' _macOS_ _Windows_ + +Returns: + +* `event` Event +* `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to. +* `details` Object + * `edge` (string) - The edge of the window being dragged for resizing. Can be `bottom`, `left`, `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. + +Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized. + +Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event. + +The possible values and behaviors of the `edge` option are platform dependent. Possible values are: + +* On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. +* On macOS, possible values are `bottom` and `right`. + * The value `bottom` is used to denote vertical resizing. + * The value `right` is used to denote horizontal resizing. + +#### Event: 'resize' + +Emitted after the window has been resized. + +#### Event: 'resized' _macOS_ _Windows_ + +Emitted once when the window has finished being resized. + +This is usually emitted when the window has been resized manually. On macOS, resizing the window with `setBounds`/`setSize` and setting the `animate` parameter to `true` will also emit this event once resizing has finished. + +#### Event: 'will-move' _macOS_ _Windows_ + +Returns: + +* `event` Event +* `newBounds` [Rectangle](structures/rectangle.md) - Location the window is being moved to. + +Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved. + +Note that this is only emitted when the window is being moved manually. Moving the window with `setPosition`/`setBounds`/`center` will not emit this event. + +#### Event: 'move' + +Emitted when the window is being moved to a new position. + +#### Event: 'moved' _macOS_ _Windows_ + +Emitted once when the window is moved to a new position. + +**Note**: On macOS this event is an alias of `move`. + +#### Event: 'enter-full-screen' + +Emitted when the window enters a full-screen state. + +#### Event: 'leave-full-screen' + +Emitted when the window leaves a full-screen state. + +#### Event: 'always-on-top-changed' + +Returns: + +* `event` Event +* `isAlwaysOnTop` boolean + +Emitted when the window is set or unset to show always on top of other windows. + +#### Event: 'app-command' _Windows_ _Linux_ + +Returns: + +* `event` Event +* `command` string + +Emitted when an [App Command](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand) +is invoked. These are typically related to keyboard media keys or browser +commands, as well as the "Back" button built into some mice on Windows. + +Commands are lowercased, underscores are replaced with hyphens, and the +`APPCOMMAND_` prefix is stripped off. +e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`. + +```js +const { BaseWindow } = require('electron') +const win = new BaseWindow() +win.on('app-command', (e, cmd) => { + // Navigate the window back when the user hits their mouse back button + if (cmd === 'browser-backward') { + // Find the appropriate WebContents to navigate. + } +}) +``` + +The following app commands are explicitly supported on Linux: + +* `browser-backward` +* `browser-forward` + +#### Event: 'swipe' _macOS_ + +Returns: + +* `event` Event +* `direction` string + +Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`. + +The method underlying this event is built to handle older macOS-style trackpad swiping, +where the content on the screen doesn't move with the swipe. Most macOS trackpads are not +configured to allow this kind of swiping anymore, so in order for it to emit properly the +'Swipe between pages' preference in `System Preferences > Trackpad > More Gestures` must be +set to 'Swipe with two or three fingers'. + +#### Event: 'rotate-gesture' _macOS_ + +Returns: + +* `event` Event +* `rotation` Float + +Emitted on trackpad rotation gesture. Continually emitted until rotation gesture is +ended. The `rotation` value on each emission is the angle in degrees rotated since +the last emission. The last emitted event upon a rotation gesture will always be of +value `0`. Counter-clockwise rotation values are positive, while clockwise ones are +negative. + +#### Event: 'sheet-begin' _macOS_ + +Emitted when the window opens a sheet. + +#### Event: 'sheet-end' _macOS_ + +Emitted when the window has closed a sheet. + +#### Event: 'new-window-for-tab' _macOS_ + +Emitted when the native new tab button is clicked. + +#### Event: 'system-context-menu' _Windows_ + +Returns: + +* `event` Event +* `point` [Point](structures/point.md) - The screen coordinates the context menu was triggered at + +Emitted when the system context menu is triggered on the window, this is +normally only triggered when the user right clicks on the non-client area +of your window. This is the window titlebar or any area you have declared +as `-webkit-app-region: drag` in a frameless window. + +Calling `event.preventDefault()` will prevent the menu from being displayed. + +### Static Methods + +The `BaseWindow` class has the following static methods: + +#### `BaseWindow.getAllWindows()` + +Returns `BaseWindow[]` - An array of all opened browser windows. + +#### `BaseWindow.getFocusedWindow()` + +Returns `BaseWindow | null` - The window that is focused in this application, otherwise returns `null`. + +#### `BaseWindow.fromId(id)` + +* `id` Integer + +Returns `BaseWindow | null` - The window with the given `id`. + +### Instance Properties + +Objects created with `new BaseWindow` have the following properties: + +```js +const { BaseWindow } = require('electron') +// In this example `win` is our instance +const win = new BaseWindow({ width: 800, height: 600 }) +``` + +#### `win.id` _Readonly_ + +A `Integer` property representing the unique ID of the window. Each ID is unique among all `BaseWindow` instances of the entire Electron application. + +#### `win.contentView` + +A `View` property for the content view of the window. + +#### `win.tabbingIdentifier` _macOS_ _Readonly_ + +A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set. + +#### `win.autoHideMenuBar` + +A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key. + +If the menu bar is already visible, setting this property to `true` won't +hide it immediately. + +#### `win.simpleFullScreen` + +A `boolean` property that determines whether the window is in simple (pre-Lion) fullscreen mode. + +#### `win.fullScreen` + +A `boolean` property that determines whether the window is in fullscreen mode. + +#### `win.focusable` _Windows_ _macOS_ + +A `boolean` property that determines whether the window is focusable. + +#### `win.visibleOnAllWorkspaces` _macOS_ _Linux_ + +A `boolean` property that determines whether the window is visible on all workspaces. + +**Note:** Always returns false on Windows. + +#### `win.shadow` + +A `boolean` property that determines whether the window has a shadow. + +#### `win.menuBarVisible` _Windows_ _Linux_ + +A `boolean` property that determines whether the menu bar should be visible. + +**Note:** If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. + +#### `win.kiosk` + +A `boolean` property that determines whether the window is in kiosk mode. + +#### `win.documentEdited` _macOS_ + +A `boolean` property that specifies whether the window’s document has been edited. + +The icon in title bar will become gray when set to `true`. + +#### `win.representedFilename` _macOS_ + +A `string` property that determines the pathname of the file the window represents, +and the icon of the file will show in window's title bar. + +#### `win.title` + +A `string` property that determines the title of the native window. + +**Note:** The title of the web page can be different from the title of the native window. + +#### `win.minimizable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually minimized by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.maximizable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually maximized by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.fullScreenable` + +A `boolean` property that determines whether the maximize/zoom window button toggles fullscreen mode or +maximizes the window. + +#### `win.resizable` + +A `boolean` property that determines whether the window can be manually resized by user. + +#### `win.closable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually closed by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.movable` _macOS_ _Windows_ + +A `boolean` property that determines Whether the window can be moved by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.excludedFromShownWindowsMenu` _macOS_ + +A `boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default. + +```js @ts-expect-error=[12] +const { Menu, BaseWindow } = require('electron') +const win = new BaseWindow({ height: 600, width: 600 }) + +const template = [ + { + role: 'windowmenu' + } +] + +win.excludedFromShownWindowsMenu = true + +const menu = Menu.buildFromTemplate(template) +Menu.setApplicationMenu(menu) +``` + +#### `win.accessibleTitle` + +A `string` property that defines an alternative title provided only to +accessibility tools such as screen readers. This string is not directly +visible to users. + +### Instance Methods + +Objects created with `new BaseWindow` have the following instance methods: + +**Note:** Some methods are only available on specific operating systems and are +labeled as such. + +#### `win.setContentView(view)` + +* `view` [View](view.md) + +Sets the content view of the window. + +#### `win.getContentView()` + +Returns [`View`](view.md) - The content view of the window. + +#### `win.destroy()` + +Force closing the window, the `unload` and `beforeunload` event won't be emitted +for the web page, and `close` event will also not be emitted +for this window, but it guarantees the `closed` event will be emitted. + +#### `win.close()` + +Try to close the window. This has the same effect as a user manually clicking +the close button of the window. The web page may cancel the close though. See +the [close event](#event-close). + +#### `win.focus()` + +Focuses on the window. + +#### `win.blur()` + +Removes focus from the window. + +#### `win.isFocused()` + +Returns `boolean` - Whether the window is focused. + +#### `win.isDestroyed()` + +Returns `boolean` - Whether the window is destroyed. + +#### `win.show()` + +Shows and gives focus to the window. + +#### `win.showInactive()` + +Shows the window but doesn't focus on it. + +#### `win.hide()` + +Hides the window. + +#### `win.isVisible()` + +Returns `boolean` - Whether the window is visible to the user in the foreground of the app. + +#### `win.isModal()` + +Returns `boolean` - Whether current window is a modal window. + +#### `win.maximize()` + +Maximizes the window. This will also show (but not focus) the window if it +isn't being displayed already. + +#### `win.unmaximize()` + +Unmaximizes the window. + +#### `win.isMaximized()` + +Returns `boolean` - Whether the window is maximized. + +#### `win.minimize()` + +Minimizes the window. On some platforms the minimized window will be shown in +the Dock. + +#### `win.restore()` + +Restores the window from minimized state to its previous state. + +#### `win.isMinimized()` + +Returns `boolean` - Whether the window is minimized. + +#### `win.setFullScreen(flag)` + +* `flag` boolean + +Sets whether the window should be in fullscreen mode. + +**Note:** On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](base-window.md#event-enter-full-screen) or ['leave-full-screen'](base-window.md#event-leave-full-screen) events. + +#### `win.isFullScreen()` + +Returns `boolean` - Whether the window is in fullscreen mode. + +#### `win.setSimpleFullScreen(flag)` _macOS_ + +* `flag` boolean + +Enters or leaves simple fullscreen mode. + +Simple fullscreen mode emulates the native fullscreen behavior found in versions of macOS prior to Lion (10.7). + +#### `win.isSimpleFullScreen()` _macOS_ + +Returns `boolean` - Whether the window is in simple (pre-Lion) fullscreen mode. + +#### `win.isNormal()` + +Returns `boolean` - Whether the window is in normal state (not maximized, not minimized, not in fullscreen mode). + +#### `win.setAspectRatio(aspectRatio[, extraSize])` + +* `aspectRatio` Float - The aspect ratio to maintain for some portion of the +content view. +* `extraSize` [Size](structures/size.md) (optional) _macOS_ - The extra size not to be included while +maintaining the aspect ratio. + +This will make a window maintain an aspect ratio. The extra size allows a +developer to have space, specified in pixels, not included within the aspect +ratio calculations. This API already takes into account the difference between a +window's size and its content size. + +Consider a normal window with an HD video player and associated controls. +Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls +on the right edge and 50 pixels of controls below the player. In order to +maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within +the player itself we would call this function with arguments of 16/9 and +\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height +are within the content view--only that they exist. Sum any extra width and +height areas you have within the overall content view. + +The aspect ratio is not respected when window is resized programmatically with +APIs like `win.setSize`. + +To reset an aspect ratio, pass 0 as the `aspectRatio` value: `win.setAspectRatio(0)`. + +#### `win.setBackgroundColor(backgroundColor)` + +* `backgroundColor` string - Color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type. + +Examples of valid `backgroundColor` values: + +* Hex + * #fff (shorthand RGB) + * #ffff (shorthand ARGB) + * #ffffff (RGB) + * #ffffffff (ARGB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. rgb(255, 255, 255) +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. rgba(255, 255, 255, 1.0) +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. hsl(200, 20%, 50%) +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. hsla(200, 20%, 50%, 0.5) +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +Sets the background color of the window. See [Setting `backgroundColor`](browser-window.md#setting-the-backgroundcolor-property). + +#### `win.previewFile(path[, displayName])` _macOS_ + +* `path` string - The absolute path to the file to preview with QuickLook. This + is important as Quick Look uses the file name and file extension on the path + to determine the content type of the file to open. +* `displayName` string (optional) - The name of the file to display on the + Quick Look modal view. This is purely visual and does not affect the content + type of the file. Defaults to `path`. + +Uses [Quick Look][quick-look] to preview a file at a given path. + +#### `win.closeFilePreview()` _macOS_ + +Closes the currently open [Quick Look][quick-look] panel. + +#### `win.setBounds(bounds[, animate])` + +* `bounds` Partial\<[Rectangle](structures/rectangle.md)\> +* `animate` boolean (optional) _macOS_ + +Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values. + +```js +const { BaseWindow } = require('electron') +const win = new BaseWindow() + +// set all bounds properties +win.setBounds({ x: 440, y: 225, width: 800, height: 600 }) + +// set a single bounds property +win.setBounds({ width: 100 }) + +// { x: 440, y: 225, width: 100, height: 600 } +console.log(win.getBounds()) +``` + +**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray. + +#### `win.getBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`. + +**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`. + +#### `win.getBackgroundColor()` + +Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format. + +See [Setting `backgroundColor`](browser-window.md#setting-the-backgroundcolor-property). + +**Note:** The alpha value is _not_ returned alongside the red, green, and blue values. + +#### `win.setContentBounds(bounds[, animate])` + +* `bounds` [Rectangle](structures/rectangle.md) +* `animate` boolean (optional) _macOS_ + +Resizes and moves the window's client area (e.g. the web page) to +the supplied bounds. + +#### `win.getContentBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window's client area as `Object`. + +#### `win.getNormalBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - Contains the window bounds of the normal state + +**Note:** whatever the current state of the window : maximized, minimized or in fullscreen, this function always returns the position and size of the window in normal state. In normal state, getBounds and getNormalBounds returns the same [`Rectangle`](structures/rectangle.md). + +#### `win.setEnabled(enable)` + +* `enable` boolean + +Disable or enable the window. + +#### `win.isEnabled()` + +Returns `boolean` - whether the window is enabled. + +#### `win.setSize(width, height[, animate])` + +* `width` Integer +* `height` Integer +* `animate` boolean (optional) _macOS_ + +Resizes the window to `width` and `height`. If `width` or `height` are below any set minimum size constraints the window will snap to its minimum size. + +#### `win.getSize()` + +Returns `Integer[]` - Contains the window's width and height. + +#### `win.setContentSize(width, height[, animate])` + +* `width` Integer +* `height` Integer +* `animate` boolean (optional) _macOS_ + +Resizes the window's client area (e.g. the web page) to `width` and `height`. + +#### `win.getContentSize()` + +Returns `Integer[]` - Contains the window's client area's width and height. + +#### `win.setMinimumSize(width, height)` + +* `width` Integer +* `height` Integer + +Sets the minimum size of window to `width` and `height`. + +#### `win.getMinimumSize()` + +Returns `Integer[]` - Contains the window's minimum width and height. + +#### `win.setMaximumSize(width, height)` + +* `width` Integer +* `height` Integer + +Sets the maximum size of window to `width` and `height`. + +#### `win.getMaximumSize()` + +Returns `Integer[]` - Contains the window's maximum width and height. + +#### `win.setResizable(resizable)` + +* `resizable` boolean + +Sets whether the window can be manually resized by the user. + +#### `win.isResizable()` + +Returns `boolean` - Whether the window can be manually resized by the user. + +#### `win.setMovable(movable)` _macOS_ _Windows_ + +* `movable` boolean + +Sets whether the window can be moved by user. On Linux does nothing. + +#### `win.isMovable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be moved by user. + +On Linux always returns `true`. + +#### `win.setMinimizable(minimizable)` _macOS_ _Windows_ + +* `minimizable` boolean + +Sets whether the window can be manually minimized by user. On Linux does nothing. + +#### `win.isMinimizable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually minimized by the user. + +On Linux always returns `true`. + +#### `win.setMaximizable(maximizable)` _macOS_ _Windows_ + +* `maximizable` boolean + +Sets whether the window can be manually maximized by user. On Linux does nothing. + +#### `win.isMaximizable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually maximized by user. + +On Linux always returns `true`. + +#### `win.setFullScreenable(fullscreenable)` + +* `fullscreenable` boolean + +Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. + +#### `win.isFullScreenable()` + +Returns `boolean` - Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. + +#### `win.setClosable(closable)` _macOS_ _Windows_ + +* `closable` boolean + +Sets whether the window can be manually closed by user. On Linux does nothing. + +#### `win.isClosable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually closed by user. + +On Linux always returns `true`. + +#### `win.setHiddenInMissionControl(hidden)` _macOS_ + +* `hidden` boolean + +Sets whether the window will be hidden when the user toggles into mission control. + +#### `win.isHiddenInMissionControl()` _macOS_ + +Returns `boolean` - Whether the window will be hidden when the user toggles into mission control. + +#### `win.setAlwaysOnTop(flag[, level][, relativeLevel])` + +* `flag` boolean +* `level` string (optional) _macOS_ _Windows_ - Values include `normal`, + `floating`, `torn-off-menu`, `modal-panel`, `main-menu`, `status`, + `pop-up-menu`, `screen-saver`, and ~~`dock`~~ (Deprecated). The default is + `floating` when `flag` is true. The `level` is reset to `normal` when the + flag is false. Note that from `floating` to `status` included, the window is + placed below the Dock on macOS and below the taskbar on Windows. From + `pop-up-menu` to a higher it is shown above the Dock on macOS and above the + taskbar on Windows. See the [macOS docs][window-levels] for more details. +* `relativeLevel` Integer (optional) _macOS_ - The number of layers higher to set + this window relative to the given `level`. The default is `0`. Note that Apple + discourages setting levels higher than 1 above `screen-saver`. + +Sets whether the window should show always on top of other windows. After +setting this, the window is still a normal window, not a toolbox window which +can not be focused on. + +#### `win.isAlwaysOnTop()` + +Returns `boolean` - Whether the window is always on top of other windows. + +#### `win.moveAbove(mediaSourceId)` + +* `mediaSourceId` string - Window id in the format of DesktopCapturerSource's id. For example "window:1869:0". + +Moves window above the source window in the sense of z-order. If the +`mediaSourceId` is not of type window or if the window does not exist then +this method throws an error. + +#### `win.moveTop()` + +Moves window to top(z-order) regardless of focus + +#### `win.center()` + +Moves window to the center of the screen. + +#### `win.setPosition(x, y[, animate])` + +* `x` Integer +* `y` Integer +* `animate` boolean (optional) _macOS_ + +Moves window to `x` and `y`. + +#### `win.getPosition()` + +Returns `Integer[]` - Contains the window's current position. + +#### `win.setTitle(title)` + +* `title` string + +Changes the title of native window to `title`. + +#### `win.getTitle()` + +Returns `string` - The title of the native window. + +**Note:** The title of the web page can be different from the title of the native +window. + +#### `win.setSheetOffset(offsetY[, offsetX])` _macOS_ + +* `offsetY` Float +* `offsetX` Float (optional) + +Changes the attachment point for sheets on macOS. By default, sheets are +attached just below the window frame, but you may want to display them beneath +a HTML-rendered toolbar. For example: + +```js +const { BaseWindow } = require('electron') +const win = new BaseWindow() + +const toolbarRect = document.getElementById('toolbar').getBoundingClientRect() +win.setSheetOffset(toolbarRect.height) +``` + +#### `win.flashFrame(flag)` + + + +* `flag` boolean + +Starts or stops flashing the window to attract user's attention. + +#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_ + +* `skip` boolean + +Makes the window not show in the taskbar. + +#### `win.setKiosk(flag)` + +* `flag` boolean + +Enters or leaves kiosk mode. + +#### `win.isKiosk()` + +Returns `boolean` - Whether the window is in kiosk mode. + +#### `win.isTabletMode()` _Windows_ + +Returns `boolean` - Whether the window is in Windows 10 tablet mode. + +Since Windows 10 users can [use their PC as tablet](https://support.microsoft.com/en-us/help/17210/windows-10-use-your-pc-like-a-tablet), +under this mode apps can choose to optimize their UI for tablets, such as +enlarging the titlebar and hiding titlebar buttons. + +This API returns whether the window is in tablet mode, and the `resize` event +can be be used to listen to changes to tablet mode. + +#### `win.getMediaSourceId()` + +Returns `string` - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0". + +More precisely the format is `window:id:other_id` where `id` is `HWND` on +Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on +Linux. `other_id` is used to identify web contents (tabs) so within the same +top level window. + +#### `win.getNativeWindowHandle()` + +Returns `Buffer` - The platform-specific handle of the window. + +The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and +`Window` (`unsigned long`) on Linux. + +#### `win.hookWindowMessage(message, callback)` _Windows_ + +* `message` Integer +* `callback` Function + * `wParam` Buffer - The `wParam` provided to the WndProc + * `lParam` Buffer - The `lParam` provided to the WndProc + +Hooks a windows message. The `callback` is called when +the message is received in the WndProc. + +#### `win.isWindowMessageHooked(message)` _Windows_ + +* `message` Integer + +Returns `boolean` - `true` or `false` depending on whether the message is hooked. + +#### `win.unhookWindowMessage(message)` _Windows_ + +* `message` Integer + +Unhook the window message. + +#### `win.unhookAllWindowMessages()` _Windows_ + +Unhooks all of the window messages. + +#### `win.setRepresentedFilename(filename)` _macOS_ + +* `filename` string + +Sets the pathname of the file the window represents, and the icon of the file +will show in window's title bar. + +#### `win.getRepresentedFilename()` _macOS_ + +Returns `string` - The pathname of the file the window represents. + +#### `win.setDocumentEdited(edited)` _macOS_ + +* `edited` boolean + +Specifies whether the window’s document has been edited, and the icon in title +bar will become gray when set to `true`. + +#### `win.isDocumentEdited()` _macOS_ + +Returns `boolean` - Whether the window's document has been edited. + +#### `win.setMenu(menu)` _Linux_ _Windows_ + +* `menu` Menu | null + +Sets the `menu` as the window's menu bar. + +#### `win.removeMenu()` _Linux_ _Windows_ + +Remove the window's menu bar. + +#### `win.setProgressBar(progress[, options])` + +* `progress` Double +* `options` Object (optional) + * `mode` string _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`. + +Sets progress value in progress bar. Valid range is \[0, 1.0]. + +Remove progress bar when progress < 0; +Change to indeterminate mode when progress > 1. + +On Linux platform, only supports Unity desktop environment, you need to specify +the `*.desktop` file name to `desktopName` field in `package.json`. By default, +it will assume `{app.name}.desktop`. + +On Windows, a mode can be passed. Accepted values are `none`, `normal`, +`indeterminate`, `error`, and `paused`. If you call `setProgressBar` without a +mode set (but with a value within the valid range), `normal` will be assumed. + +#### `win.setOverlayIcon(overlay, description)` _Windows_ + +* `overlay` [NativeImage](native-image.md) | null - the icon to display on the bottom +right corner of the taskbar icon. If this parameter is `null`, the overlay is +cleared +* `description` string - a description that will be provided to Accessibility +screen readers + +Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to +convey some sort of application status or to passively notify the user. + +#### `win.invalidateShadow()` _macOS_ + +Invalidates the window shadow so that it is recomputed based on the current window shape. + +`BaseWindow`s that are transparent can sometimes leave behind visual artifacts on macOS. +This method can be used to clear these artifacts when, for example, performing an animation. + +#### `win.setHasShadow(hasShadow)` + +* `hasShadow` boolean + +Sets whether the window should have a shadow. + +#### `win.hasShadow()` + +Returns `boolean` - Whether the window has a shadow. + +#### `win.setOpacity(opacity)` _Windows_ _macOS_ + +* `opacity` number - between 0.0 (fully transparent) and 1.0 (fully opaque) + +Sets the opacity of the window. On Linux, does nothing. Out of bound number +values are clamped to the \[0, 1] range. + +#### `win.getOpacity()` + +Returns `number` - between 0.0 (fully transparent) and 1.0 (fully opaque). On +Linux, always returns 1. + +#### `win.setShape(rects)` _Windows_ _Linux_ _Experimental_ + +* `rects` [Rectangle[]](structures/rectangle.md) - Sets a shape on the window. + Passing an empty list reverts the window to being rectangular. + +Setting a window shape determines the area within the window where the system +permits drawing and user interaction. Outside of the given region, no pixels +will be drawn and no mouse events will be registered. Mouse events outside of +the region will not be received by that window, but will fall through to +whatever is behind the window. + +#### `win.setThumbarButtons(buttons)` _Windows_ + +* `buttons` [ThumbarButton[]](structures/thumbar-button.md) + +Returns `boolean` - Whether the buttons were added successfully + +Add a thumbnail toolbar with a specified set of buttons to the thumbnail image +of a window in a taskbar button layout. Returns a `boolean` object indicates +whether the thumbnail has been added successfully. + +The number of buttons in thumbnail toolbar should be no greater than 7 due to +the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be +removed due to the platform's limitation. But you can call the API with an empty +array to clean the buttons. + +The `buttons` is an array of `Button` objects: + +* `Button` Object + * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail + toolbar. + * `click` Function + * `tooltip` string (optional) - The text of the button's tooltip. + * `flags` string[] (optional) - Control specific states and behaviors of the + button. By default, it is `['enabled']`. + +The `flags` is an array that can include following `string`s: + +* `enabled` - The button is active and available to the user. +* `disabled` - The button is disabled. It is present, but has a visual state + indicating it will not respond to user action. +* `dismissonclick` - When the button is clicked, the thumbnail window closes + immediately. +* `nobackground` - Do not draw a button border, use only the image. +* `hidden` - The button is not shown to the user. +* `noninteractive` - The button is enabled but not interactive; no pressed + button state is drawn. This value is intended for instances where the button + is used in a notification. + +#### `win.setThumbnailClip(region)` _Windows_ + +* `region` [Rectangle](structures/rectangle.md) - Region of the window + +Sets the region of the window to show as the thumbnail image displayed when +hovering over the window in the taskbar. You can reset the thumbnail to be +the entire window by specifying an empty region: +`{ x: 0, y: 0, width: 0, height: 0 }`. + +#### `win.setThumbnailToolTip(toolTip)` _Windows_ + +* `toolTip` string + +Sets the toolTip that is displayed when hovering over the window thumbnail +in the taskbar. + +#### `win.setAppDetails(options)` _Windows_ + +* `options` Object + * `appId` string (optional) - Window's [App User Model ID](https://learn.microsoft.com/en-us/windows/win32/shell/appids). + It has to be set, otherwise the other options will have no effect. + * `appIconPath` string (optional) - Window's [Relaunch Icon](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource). + * `appIconIndex` Integer (optional) - Index of the icon in `appIconPath`. + Ignored when `appIconPath` is not set. Default is `0`. + * `relaunchCommand` string (optional) - Window's [Relaunch Command](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchcommand). + * `relaunchDisplayName` string (optional) - Window's [Relaunch Display Name](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource). + +Sets the properties for the window's taskbar button. + +**Note:** `relaunchCommand` and `relaunchDisplayName` must always be set +together. If one of those properties is not set, then neither will be used. + +#### `win.setIcon(icon)` _Windows_ _Linux_ + +* `icon` [NativeImage](native-image.md) | string + +Changes window icon. + +#### `win.setWindowButtonVisibility(visible)` _macOS_ + +* `visible` boolean + +Sets whether the window traffic light buttons should be visible. + +#### `win.setAutoHideMenuBar(hide)` _Windows_ _Linux_ + +* `hide` boolean + +Sets whether the window menu bar should hide itself automatically. Once set the +menu bar will only show when users press the single `Alt` key. + +If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't hide it immediately. + +#### `win.isMenuBarAutoHide()` _Windows_ _Linux_ + +Returns `boolean` - Whether menu bar automatically hides itself. + +#### `win.setMenuBarVisibility(visible)` _Windows_ _Linux_ + +* `visible` boolean + +Sets whether the menu bar should be visible. If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. + +#### `win.isMenuBarVisible()` _Windows_ _Linux_ + +Returns `boolean` - Whether the menu bar is visible. + +#### `win.setVisibleOnAllWorkspaces(visible[, options])` _macOS_ _Linux_ + +* `visible` boolean +* `options` Object (optional) + * `visibleOnFullScreen` boolean (optional) _macOS_ - Sets whether + the window should be visible above fullscreen windows. + * `skipTransformProcessType` boolean (optional) _macOS_ - Calling + setVisibleOnAllWorkspaces will by default transform the process + type between UIElementApplication and ForegroundApplication to + ensure the correct behavior. However, this will hide the window + and dock for a short time every time it is called. If your window + is already of type UIElementApplication, you can bypass this + transformation by passing true to skipTransformProcessType. + +Sets whether the window should be visible on all workspaces. + +**Note:** This API does nothing on Windows. + +#### `win.isVisibleOnAllWorkspaces()` _macOS_ _Linux_ + +Returns `boolean` - Whether the window is visible on all workspaces. + +**Note:** This API always returns false on Windows. + +#### `win.setIgnoreMouseEvents(ignore[, options])` + +* `ignore` boolean +* `options` Object (optional) + * `forward` boolean (optional) _macOS_ _Windows_ - If true, forwards mouse move + messages to Chromium, enabling mouse related events such as `mouseleave`. + Only used when `ignore` is true. If `ignore` is false, forwarding is always + disabled regardless of this value. + +Makes the window ignore all mouse events. + +All mouse events happened in this window will be passed to the window below +this window, but if this window has focus, it will still receive keyboard +events. + +#### `win.setContentProtection(enable)` _macOS_ _Windows_ + +* `enable` boolean + +Prevents the window contents from being captured by other apps. + +On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. +On Windows it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. +For Windows 10 version 2004 and up the window will be removed from capture entirely, +older Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. + +#### `win.setFocusable(focusable)` _macOS_ _Windows_ + +* `focusable` boolean + +Changes whether the window can be focused. + +On macOS it does not remove the focus from the window. + +#### `win.isFocusable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be focused. + +#### `win.setParentWindow(parent)` + +* `parent` BaseWindow | null + +Sets `parent` as current window's parent window, passing `null` will turn +current window into a top-level window. + +#### `win.getParentWindow()` + +Returns `BaseWindow | null` - The parent window or `null` if there is no parent. + +#### `win.getChildWindows()` + +Returns `BaseWindow[]` - All child windows. + +#### `win.setAutoHideCursor(autoHide)` _macOS_ + +* `autoHide` boolean + +Controls whether to hide cursor when typing. + +#### `win.selectPreviousTab()` _macOS_ + +Selects the previous tab when native tabs are enabled and there are other +tabs in the window. + +#### `win.selectNextTab()` _macOS_ + +Selects the next tab when native tabs are enabled and there are other +tabs in the window. + +#### `win.showAllTabs()` _macOS_ + +Shows or hides the tab overview when native tabs are enabled. + +#### `win.mergeAllWindows()` _macOS_ + +Merges all windows into one window with multiple tabs when native tabs +are enabled and there is more than one open window. + +#### `win.moveTabToNewWindow()` _macOS_ + +Moves the current tab into a new window if native tabs are enabled and +there is more than one tab in the current window. + +#### `win.toggleTabBar()` _macOS_ + +Toggles the visibility of the tab bar if native tabs are enabled and +there is only one tab in the current window. + +#### `win.addTabbedWindow(baseWindow)` _macOS_ + +* `baseWindow` BaseWindow + +Adds a window as a tab on this window, after the tab for the window instance. + +#### `win.setVibrancy(type)` _macOS_ + +* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See + the [macOS documentation][vibrancy-docs] for more details. + +Adds a vibrancy effect to the window. Passing `null` or an empty string +will remove the vibrancy effect on the window. + +#### `win.setBackgroundMaterial(material)` _Windows_ + +* `material` string + * `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default. + * `none` - Don't draw any system backdrop. + * `mica` - Draw the backdrop material effect corresponding to a long-lived window. + * `acrylic` - Draw the backdrop material effect corresponding to a transient window. + * `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar. + +This method sets the browser window's system-drawn background material, including behind the non-client area. + +See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details. + +**Note:** This method is only supported on Windows 11 22H2 and up. + +#### `win.setWindowButtonPosition(position)` _macOS_ + +* `position` [Point](structures/point.md) | null + +Set a custom position for the traffic light buttons in frameless window. +Passing `null` will reset the position to default. + +#### `win.getWindowButtonPosition()` _macOS_ + +Returns `Point | null` - The custom position for the traffic light buttons in +frameless window, `null` will be returned when there is no custom position. + +#### `win.setTouchBar(touchBar)` _macOS_ + +* `touchBar` TouchBar | null + +Sets the touchBar layout for the current window. Specifying `null` or +`undefined` clears the touch bar. This method only has an effect if the +machine has a touch bar. + +**Note:** The TouchBar API is currently experimental and may change or be +removed in future Electron releases. + +#### `win.setTitleBarOverlay(options)` _Windows_ _Linux_ + +* `options` Object + * `color` String (optional) - The CSS color of the Window Controls Overlay when enabled. + * `symbolColor` String (optional) - The CSS color of the symbols on the Window Controls Overlay when enabled. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. + +On a Window with Window Controls Overlay already enabled, this method updates the style of the title bar overlay. + +On Linux, the `symbolColor` is automatically calculated to have minimum accessible contrast to the `color` if not explicitly set. + +[quick-look]: https://en.wikipedia.org/wiki/Quick_Look +[vibrancy-docs]: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc +[window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[window-session-end-event]:../api/structures/window-session-end-event.md diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index a2c5b03079a06..f3873c538a69b 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -1,5 +1,17 @@ # BrowserView + + +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + A `BrowserView` can be used to embed additional web content into a [`BrowserWindow`](browser-window.md). It is like a child window, except that it is positioned relative to its owning window. It is meant to be an alternative to the @@ -7,8 +19,20 @@ relative to its owning window. It is meant to be an alternative to the ## Class: BrowserView + + > Create and control views. +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + Process: [Main](../glossary.md#main-process) This module cannot be used until the `ready` event of the `app` @@ -16,7 +40,7 @@ module is emitted. ### Example -```javascript +```js // In the main process. const { app, BrowserView, BrowserWindow } = require('electron') @@ -30,16 +54,32 @@ app.whenReady().then(() => { }) ``` -### `new BrowserView([options])` _Experimental_ +### `new BrowserView([options])` _Experimental_ _Deprecated_ + + * `options` Object (optional) - * `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md). + * `webPreferences` [WebPreferences](structures/web-preferences.md?inline) (optional) - Settings of web page's features. ### Instance Properties Objects created with `new BrowserView` have the following properties: -#### `view.webContents` _Experimental_ +#### `view.webContents` _Experimental_ _Deprecated_ + + A [`WebContents`](web-contents.md) object owned by this view. @@ -47,7 +87,19 @@ A [`WebContents`](web-contents.md) object owned by this view. Objects created with `new BrowserView` have the following instance methods: -#### `view.setAutoResize(options)` _Experimental_ +#### `view.setAutoResize(options)` _Experimental_ _Deprecated_ + + * `options` Object * `width` boolean (optional) - If `true`, the view's width will grow and shrink together @@ -59,19 +111,43 @@ Objects created with `new BrowserView` have the following instance methods: * `vertical` boolean (optional) - If `true`, the view's y position and height will grow and shrink proportionally with the window. `false` by default. -#### `view.setBounds(bounds)` _Experimental_ +#### `view.setBounds(bounds)` _Experimental_ _Deprecated_ + + * `bounds` [Rectangle](structures/rectangle.md) Resizes and moves the view to the supplied bounds relative to the window. -#### `view.getBounds()` _Experimental_ +#### `view.getBounds()` _Experimental_ _Deprecated_ + + Returns [`Rectangle`](structures/rectangle.md) The `bounds` of this BrowserView instance as `Object`. -#### `view.setBackgroundColor(color)` _Experimental_ +#### `view.setBackgroundColor(color)` _Experimental_ _Deprecated_ + + * `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type. @@ -79,25 +155,25 @@ The `bounds` of this BrowserView instance as `Object`. Examples of valid `color` values: * Hex - * #fff (RGB) - * #ffff (ARGB) - * #ffffff (RRGGBB) - * #ffffffff (AARRGGBB) + * `#fff` (RGB) + * `#ffff` (ARGB) + * `#ffffff` (RRGGBB) + * `#ffffffff` (AARRGGBB) * RGB - * rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\) - * e.g. rgb(255, 255, 255) + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. `rgb(255, 255, 255)` * RGBA - * rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\) - * e.g. rgba(255, 255, 255, 1.0) + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. `rgba(255, 255, 255, 1.0)` * HSL - * hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\) - * e.g. hsl(200, 20%, 50%) + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. `hsl(200, 20%, 50%)` * HSLA - * hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\) - * e.g. hsla(200, 20%, 50%, 0.5) + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. `hsla(200, 20%, 50%, 0.5)` * Color name * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) * Similar to CSS Color Module Level 3 keywords, but case-sensitive. * e.g. `blueviolet` or `red` -**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBA` or `RGA`. +**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index e5fd4045803a2..7742039cf6710 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -7,7 +7,7 @@ Process: [Main](../glossary.md#main-process) This module cannot be used until the `ready` event of the `app` module is emitted. -```javascript +```js // In the main process. const { BrowserWindow } = require('electron') @@ -38,7 +38,7 @@ While loading the page, the `ready-to-show` event will be emitted when the rende process has rendered the page for the first time if the window has not been shown yet. Showing the window after this event will have no visual flash: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ show: false }) win.once('ready-to-show', () => { @@ -59,7 +59,7 @@ For a complex app, the `ready-to-show` event could be emitted too late, making the app feel slow. In this case, it is recommended to show the window immediately, and use a `backgroundColor` close to your app's background: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ backgroundColor: '#2e2c29' }) @@ -85,7 +85,7 @@ For more information about these color types see valid options in [win.setBackgr By using `parent` option, you can create child windows: -```javascript +```js const { BrowserWindow } = require('electron') const top = new BrowserWindow() @@ -98,12 +98,13 @@ The `child` window will always show on top of the `top` window. ## Modal windows -A modal window is a child window that disables parent window, to create a modal -window, you have to set both `parent` and `modal` options: +A modal window is a child window that disables parent window. To create a modal +window, you have to set both the `parent` and `modal` options: -```javascript +```js const { BrowserWindow } = require('electron') +const top = new BrowserWindow() const child = new BrowserWindow({ parent: top, modal: true, show: false }) child.loadURL('https://github.com') child.once('ready-to-show', () => { @@ -139,7 +140,7 @@ state is `hidden` in order to minimize power consumption. * On Linux the type of modal windows will be changed to `dialog`. * On Linux many desktop environments do not support hiding a modal window. -## Class: BrowserWindow +## Class: BrowserWindow extends `BaseWindow` > Create and control browser windows. @@ -151,292 +152,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. ### `new BrowserWindow([options])` -* `options` Object (optional) - * `width` Integer (optional) - Window's width in pixels. Default is `800`. - * `height` Integer (optional) - Window's height in pixels. Default is `600`. - * `x` Integer (optional) - (**required** if y is used) Window's left offset from screen. - Default is to center the window. - * `y` Integer (optional) - (**required** if x is used) Window's top offset from screen. - Default is to center the window. - * `useContentSize` boolean (optional) - The `width` and `height` would be used as web - page's size, which means the actual window's size will include window - frame's size and be slightly larger. Default is `false`. - * `center` boolean (optional) - Show window in the center of the screen. Default is `false`. - * `minWidth` Integer (optional) - Window's minimum width. Default is `0`. - * `minHeight` Integer (optional) - Window's minimum height. Default is `0`. - * `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. - * `maxHeight` Integer (optional) - Window's maximum height. Default is no limit. - * `resizable` boolean (optional) - Whether window is resizable. Default is `true`. - * `movable` boolean (optional) _macOS_ _Windows_ - Whether window is - movable. This is not implemented on Linux. Default is `true`. - * `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is - minimizable. This is not implemented on Linux. Default is `true`. - * `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is - maximizable. This is not implemented on Linux. Default is `true`. - * `closable` boolean (optional) _macOS_ _Windows_ - Whether window is - closable. This is not implemented on Linux. Default is `true`. - * `focusable` boolean (optional) - Whether the window can be focused. Default is - `true`. On Windows setting `focusable: false` also implies setting - `skipTaskbar: true`. On Linux setting `focusable: false` makes the window - stop interacting with wm, so the window will always stay on top in all - workspaces. - * `alwaysOnTop` boolean (optional) - Whether the window should always stay on top of - other windows. Default is `false`. - * `fullscreen` boolean (optional) - Whether the window should show in fullscreen. When - explicitly set to `false` the fullscreen button will be hidden or disabled - on macOS. Default is `false`. - * `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen - mode. On macOS, also whether the maximize/zoom button should toggle full - screen mode or maximize window. Default is `true`. - * `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on - macOS. Default is `false`. - * `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar. - Default is `false`. - * `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`. - * `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. - * `icon` ([NativeImage](native-image.md) | string) (optional) - The window icon. On Windows it is - recommended to use `ICO` icons to get best visual effects, you can also - leave it undefined so the executable's icon will be used. - * `show` boolean (optional) - Whether window should be shown when created. Default is - `true`. - * `paintWhenInitiallyHidden` boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`. - * `frame` boolean (optional) - Specify `false` to create a - [frameless window](../tutorial/window-customization.md#create-frameless-windows). Default is `true`. - * `parent` BrowserWindow (optional) - Specify parent window. Default is `null`. - * `modal` boolean (optional) - Whether this is a modal window. This only works when the - window is a child window. Default is `false`. - * `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an - inactive window will also click through to the web contents. Default is - `false` on macOS. This option is not configurable on other platforms. - * `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing. - Default is `false`. - * `autoHideMenuBar` boolean (optional) - Auto hide the menu bar unless the `Alt` - key is pressed. Default is `false`. - * `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to - be resized larger than screen. Only relevant for macOS, as other OSes - allow larger-than-screen windows by default. Default is `false`. - * `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information. - * `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`. - * `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of - the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This - is only implemented on Windows and macOS. - * `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on - some GTK+3 desktop environments. Default is `false`. - * `transparent` boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows). - Default is `false`. On Windows, does not work unless the window is frameless. - * `type` string (optional) - The type of window, default is normal window. See more about - this below. - * `visualEffectState` string (optional) _macOS_ - Specify how the material - appearance should reflect window activity state on macOS. Must be used - with the `vibrancy` property. Possible values are: - * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. - * `active` - The backdrop should always appear active. - * `inactive` - The backdrop should always appear inactive. - * `titleBarStyle` string (optional) _macOS_ _Windows_ - The style of window title bar. - Default is `default`. Possible values are: - * `default` - Results in the standard title bar for macOS or Windows respectively. - * `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown. - * `hiddenInset` _macOS_ - Only on macOS, results in a hidden title bar - with an alternative look where the traffic light buttons are slightly - more inset from the window edge. - * `customButtonsOnHover` _macOS_ - Only on macOS, results in a hidden - title bar and a full size content window, the traffic light buttons will - display when being hovered over in the top left of the window. - **Note:** This option is currently experimental. - * `trafficLightPosition` [Point](structures/point.md) (optional) _macOS_ - - Set a custom position for the traffic light buttons in frameless windows. - * `roundedCorners` boolean (optional) _macOS_ - Whether frameless window - should have rounded corners on macOS. Default is `true`. - * `fullscreenWindowTitle` boolean (optional) _macOS_ _Deprecated_ - Shows - the title in the title bar in full screen mode on macOS for `hiddenInset` - titleBarStyle. Default is `false`. - * `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on - Windows, which adds standard window frame. Setting it to `false` will remove - window shadow and window animations. Default is `true`. - * `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to - the window, only on macOS. Can be `appearance-based`, `light`, `dark`, - `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `medium-light`, - `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, - `tooltip`, `content`, `under-window`, or `under-page`. Please note that - `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` are - deprecated and have been removed in macOS Catalina (10.15). - * `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on - macOS when option-clicking the green stoplight button on the toolbar or by - clicking the Window > Zoom menu item. If `true`, the window will grow to - the preferred width of the web page when zoomed, `false` will cause it to - zoom to the width of the screen. This will also affect the behavior when - calling `maximize()` directly. Default is `false`. - * `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows - opening the window as a native tab on macOS 10.12+. Windows with the same - tabbing identifier will be grouped together. This also adds a native new - tab button to your window's tab bar and allows your `app` and window to - receive the `new-window-for-tab` event. - * `webPreferences` Object (optional) - Settings of web page's features. - * `devTools` boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. - * `nodeIntegration` boolean (optional) - Whether node integration is enabled. - Default is `false`. - * `nodeIntegrationInWorker` boolean (optional) - Whether node integration is - enabled in web workers. Default is `false`. More about this can be found - in [Multithreading](../tutorial/multithreading.md). - * `nodeIntegrationInSubFrames` boolean (optional) - Experimental option for - enabling Node.js support in sub-frames such as iframes and child windows. All your preloads will load for - every iframe, you can use `process.isMainFrame` to determine if you are - in the main frame or not. - * `preload` string (optional) - Specifies a script that will be loaded before other - scripts run in the page. This script will always have access to node APIs - no matter whether node integration is turned on or off. The value should - be the absolute file path to the script. - When node integration is turned off, the preload script can reintroduce - Node global symbols back to the global scope. See example - [here](context-bridge.md#exposing-node-global-symbols). - * `sandbox` boolean (optional) - If set, this will sandbox the renderer - associated with the window, making it compatible with the Chromium - OS-level sandbox and disabling the Node.js engine. This is not the same as - the `nodeIntegration` option and the APIs available to the preload script - are more limited. Read more about the option [here](../tutorial/sandbox.md). - * `session` [Session](session.md#class-session) (optional) - Sets the session used by the - page. Instead of passing the Session object directly, you can also choose to - use the `partition` option instead, which accepts a partition string. When - both `session` and `partition` are provided, `session` will be preferred. - Default is the default session. - * `partition` string (optional) - Sets the session used by the page according to the - session's partition string. If `partition` starts with `persist:`, the page - will use a persistent session available to all pages in the app with the - same `partition`. If there is no `persist:` prefix, the page will use an - in-memory session. By assigning the same `partition`, multiple pages can share - the same session. Default is the default session. - * `zoomFactor` number (optional) - The default zoom factor of the page, `3.0` represents - `300%`. Default is `1.0`. - * `javascript` boolean (optional) - Enables JavaScript support. Default is `true`. - * `webSecurity` boolean (optional) - When `false`, it will disable the - same-origin policy (usually using testing websites by people), and set - `allowRunningInsecureContent` to `true` if this options has not been set - by user. Default is `true`. - * `allowRunningInsecureContent` boolean (optional) - Allow an https page to run - JavaScript, CSS or plugins from http URLs. Default is `false`. - * `images` boolean (optional) - Enables image support. Default is `true`. - * `imageAnimationPolicy` string (optional) - Specifies how to run image animations (E.g. GIFs). Can be `animate`, `animateOnce` or `noAnimation`. Default is `animate`. - * `textAreasAreResizable` boolean (optional) - Make TextArea elements resizable. Default - is `true`. - * `webgl` boolean (optional) - Enables WebGL support. Default is `true`. - * `plugins` boolean (optional) - Whether plugins should be enabled. Default is `false`. - * `experimentalFeatures` boolean (optional) - Enables Chromium's experimental features. - Default is `false`. - * `scrollBounce` boolean (optional) _macOS_ - Enables scroll bounce - (rubber banding) effect on macOS. Default is `false`. - * `enableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, like - `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature - strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] - file. - * `disableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, - like `CSSVariables,KeyboardEventKey` to disable. The full list of supported - feature strings can be found in the - [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. - * `defaultFontFamily` Object (optional) - Sets the default font for the font-family. - * `standard` string (optional) - Defaults to `Times New Roman`. - * `serif` string (optional) - Defaults to `Times New Roman`. - * `sansSerif` string (optional) - Defaults to `Arial`. - * `monospace` string (optional) - Defaults to `Courier New`. - * `cursive` string (optional) - Defaults to `Script`. - * `fantasy` string (optional) - Defaults to `Impact`. - * `defaultFontSize` Integer (optional) - Defaults to `16`. - * `defaultMonospaceFontSize` Integer (optional) - Defaults to `13`. - * `minimumFontSize` Integer (optional) - Defaults to `0`. - * `defaultEncoding` string (optional) - Defaults to `ISO-8859-1`. - * `backgroundThrottling` boolean (optional) - Whether to throttle animations and timers - when the page becomes background. This also affects the - [Page Visibility API](#page-visibility). Defaults to `true`. - * `offscreen` boolean (optional) - Whether to enable offscreen rendering for the browser - window. Defaults to `false`. See the - [offscreen rendering tutorial](../tutorial/offscreen-rendering.md) for - more details. - * `contextIsolation` boolean (optional) - Whether to run Electron APIs and - the specified `preload` script in a separate JavaScript context. Defaults - to `true`. The context that the `preload` script runs in will only have - access to its own dedicated `document` and `window` globals, as well as - its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.), - which are all invisible to the loaded content. The Electron API will only - be available in the `preload` script and not the loaded page. This option - should be used when loading potentially untrusted remote content to ensure - the loaded content cannot tamper with the `preload` script and any - Electron APIs being used. This option uses the same technique used by - [Chrome Content Scripts][chrome-content-scripts]. You can access this - context in the dev tools by selecting the 'Electron Isolated Context' - entry in the combo box at the top of the Console tab. - * `webviewTag` boolean (optional) - Whether to enable the [`<webview>` tag](webview-tag.md). - Defaults to `false`. **Note:** The - `preload` script configured for the `<webview>` will have node integration - enabled when it is executed so you should ensure remote/untrusted content - is not able to create a `<webview>` tag with a possibly malicious `preload` - script. You can use the `will-attach-webview` event on [webContents](web-contents.md) - to strip away the `preload` script and to validate or alter the - `<webview>`'s initial settings. - * `additionalArguments` string[] (optional) - A list of strings that will be appended - to `process.argv` in the renderer process of this app. Useful for passing small - bits of data down to renderer process preload scripts. - * `safeDialogs` boolean (optional) - Whether to enable browser style - consecutive dialog protection. Default is `false`. - * `safeDialogsMessage` string (optional) - The message to display when - consecutive dialog protection is triggered. If not defined the default - message would be used, note that currently the default message is in - English and not localized. - * `disableDialogs` boolean (optional) - Whether to disable dialogs - completely. Overrides `safeDialogs`. Default is `false`. - * `navigateOnDragDrop` boolean (optional) - Whether dragging and dropping a - file or link onto the page causes a navigation. Default is `false`. - * `autoplayPolicy` string (optional) - Autoplay policy to apply to - content in the window, can be `no-user-gesture-required`, - `user-gesture-required`, `document-user-activation-required`. Defaults to - `no-user-gesture-required`. - * `disableHtmlFullscreenWindowResize` boolean (optional) - Whether to - prevent the window from resizing when entering HTML Fullscreen. Default - is `false`. - * `accessibleTitle` string (optional) - An alternative title string provided only - to accessibility tools such as screen readers. This string is not directly - visible to users. - * `spellcheck` boolean (optional) - Whether to enable the builtin spellchecker. - Default is `true`. - * `enableWebSQL` boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/). - Default is `true`. - * `v8CacheOptions` string (optional) - Enforces the v8 code caching policy - used by blink. Accepted values are - * `none` - Disables code caching - * `code` - Heuristic based code caching - * `bypassHeatCheck` - Bypass code caching heuristics but with lazy compilation - * `bypassHeatCheckAndEagerCompile` - Same as above except compilation is eager. - Default policy is `code`. - * `enablePreferredSizeMode` boolean (optional) - Whether to enable - preferred size mode. The preferred size is the minimum size needed to - contain the layout of the document—without requiring scrolling. Enabling - this will cause the `preferred-size-changed` event to be emitted on the - `WebContents` when the preferred size changes. Default is `false`. - * `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. - * `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color. - * `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color. - * `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height. - -When setting minimum or maximum window size with `minWidth`/`maxWidth`/ -`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from -passing a size that does not follow size constraints to `setBounds`/`setSize` or -to the constructor of `BrowserWindow`. - -The possible values and behaviors of the `type` option are platform dependent. -Possible values are: - -* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, - `notification`. -* On macOS, possible types are `desktop`, `textured`, `panel`. - * The `textured` type adds metal gradient appearance - (`NSWindowStyleMaskTexturedBackground`). - * The `desktop` type places the window at the desktop background window level - (`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive - focus, keyboard or mouse events, but you can use `globalShortcut` to receive - input sparingly. - * The `panel` type enables the window to float on top of full-screened apps - by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally - reserved for NSPanel, at runtime. Also, the window will appear on all - spaces (desktops). -* On Windows, possible type is `toolbar`. +* `options` [BrowserWindowConstructorOptions](structures/browser-window-options.md?inline) (optional) ### Instance Events @@ -472,7 +188,7 @@ window should be closed, which will also be called when the window is reloaded. In Electron, returning any value other than `undefined` would cancel the close. For example: -```javascript +```js window.onbeforeunload = (e) => { console.log('I do not want to be closed') @@ -491,10 +207,24 @@ _**Note**: There is a subtle difference between the behaviors of `window.onbefor Emitted when the window is closed. After you have received this event you should remove the reference to the window and avoid using it any more. +#### Event: 'query-session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. +Calling `event.preventDefault()` can delay the system shutdown, though it’s generally best +to respect the user’s choice to end the session. However, you may choose to use it if +ending the session puts the user at risk of losing data. + #### Event: 'session-end' _Windows_ -Emitted when window session is going to end due to force shutdown or machine restart -or session log off. +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. Once this event fires, there is no way to prevent the session from ending. #### Event: 'unresponsive' @@ -593,7 +323,7 @@ Emitted when the window is being moved to a new position. Emitted once when the window is moved to a new position. -__Note__: On macOS this event is an alias of `move`. +**Note**: On macOS this event is an alias of `move`. #### Event: 'enter-full-screen' @@ -627,7 +357,7 @@ Returns: * `event` Event * `command` string -Emitted when an [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) +Emitted when an [App Command](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand) is invoked. These are typically related to keyboard media keys or browser commands, as well as the "Back" button built into some mice on Windows. @@ -635,7 +365,7 @@ Commands are lowercased, underscores are replaced with hyphens, and the `APPCOMMAND_` prefix is stripped off. e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() win.on('app-command', (e, cmd) => { @@ -651,18 +381,6 @@ The following app commands are explicitly supported on Linux: * `browser-backward` * `browser-forward` -#### Event: 'scroll-touch-begin' _macOS_ - -Emitted when scroll wheel event phase has begun. - -#### Event: 'scroll-touch-end' _macOS_ - -Emitted when scroll wheel event phase has ended. - -#### Event: 'scroll-touch-edge' _macOS_ - -Emitted when scroll wheel event phase filed upon reaching the edge of element. - #### Event: 'swipe' _macOS_ Returns: @@ -736,10 +454,14 @@ Returns `BrowserWindow | null` - The window that is focused in this application, Returns `BrowserWindow | null` - The window that owns the given `webContents` or `null` if the contents are not owned by a window. -#### `BrowserWindow.fromBrowserView(browserView)` +#### `BrowserWindow.fromBrowserView(browserView)` _Deprecated_ * `browserView` [BrowserView](browser-view.md) +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + Returns `BrowserWindow | null` - The window that owns the given `browserView`. If the given view is not attached to any window, returns `null`. #### `BrowserWindow.fromId(id)` @@ -752,7 +474,7 @@ Returns `BrowserWindow | null` - The window with the given `id`. Objects created with `new BrowserWindow` have the following properties: -```javascript +```js const { BrowserWindow } = require('electron') // In this example `win` is our instance const win = new BrowserWindow({ width: 800, height: 600 }) @@ -771,6 +493,10 @@ events. A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application. +#### `win.tabbingIdentifier` _macOS_ _Readonly_ + +A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set. + #### `win.autoHideMenuBar` A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key. @@ -864,7 +590,7 @@ On Linux the setter is a no-op, although the getter returns `true`. A `boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default. -```js +```js @ts-expect-error=[11] const win = new BrowserWindow({ height: 600, width: 600 }) const template = [ @@ -934,7 +660,7 @@ Hides the window. #### `win.isVisible()` -Returns `boolean` - Whether the window is visible to the user. +Returns `boolean` - Whether the window is visible to the user in the foreground of the app. #### `win.isModal()` @@ -972,10 +698,14 @@ Returns `boolean` - Whether the window is minimized. Sets whether the window should be in fullscreen mode. +**Note:** On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](browser-window.md#event-enter-full-screen) or ['leave-full-screen'](browser-window.md#event-leave-full-screen) events. + #### `win.isFullScreen()` Returns `boolean` - Whether the window is in fullscreen mode. +**Note:** On macOS, fullscreen transitions take place asynchronously. When querying for a BrowserWindow's fullscreen status, you should ensure that either the ['enter-full-screen'](browser-window.md#event-enter-full-screen) or ['leave-full-screen'](browser-window.md#event-leave-full-screen) events have been emitted. + #### `win.setSimpleFullScreen(flag)` _macOS_ * `flag` boolean @@ -1009,13 +739,15 @@ Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within the player itself we would call this function with arguments of 16/9 and -{ width: 40, height: 50 }. The second argument doesn't care where the extra width and height +\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height are within the content view--only that they exist. Sum any extra width and height areas you have within the overall content view. The aspect ratio is not respected when window is resized programmatically with APIs like `win.setSize`. +To reset an aspect ratio, pass 0 as the `aspectRatio` value: `win.setAspectRatio(0)`. + #### `win.setBackgroundColor(backgroundColor)` * `backgroundColor` string - Color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type. @@ -1028,16 +760,16 @@ Examples of valid `backgroundColor` values: * #ffffff (RGB) * #ffffffff (ARGB) * RGB - * rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\) + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` * e.g. rgb(255, 255, 255) * RGBA - * rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\) + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` * e.g. rgba(255, 255, 255, 1.0) * HSL - * hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\) + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` * e.g. hsl(200, 20%, 50%) * HSLA - * hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\) + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` * e.g. hsla(200, 20%, 50%, 0.5) * Color name * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) @@ -1063,12 +795,12 @@ Closes the currently open [Quick Look][quick-look] panel. #### `win.setBounds(bounds[, animate])` -* `bounds` Partial<[Rectangle](structures/rectangle.md)> +* `bounds` Partial\<[Rectangle](structures/rectangle.md)\> * `animate` boolean (optional) _macOS_ Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -1082,10 +814,14 @@ win.setBounds({ width: 100 }) console.log(win.getBounds()) ``` +**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray. + #### `win.getBounds()` Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`. +**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`. + #### `win.getBackgroundColor()` Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format. @@ -1236,6 +972,16 @@ Returns `boolean` - Whether the window can be manually closed by user. On Linux always returns `true`. +#### `win.setHiddenInMissionControl(hidden)` _macOS_ + +* `hidden` boolean + +Sets whether the window will be hidden when the user toggles into mission control. + +#### `win.isHiddenInMissionControl()` _macOS_ + +Returns `boolean` - Whether the window will be hidden when the user toggles into mission control. + #### `win.setAlwaysOnTop(flag[, level][, relativeLevel])` * `flag` boolean @@ -1309,7 +1055,7 @@ Changes the attachment point for sheets on macOS. By default, sheets are attached just below the window frame, but you may want to display them beneath a HTML-rendered toolbar. For example: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -1319,6 +1065,15 @@ win.setSheetOffset(toolbarRect.height) #### `win.flashFrame(flag)` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/41391 + description: "`window.flashFrame(bool)` will flash dock icon continuously on macOS" + breaking-changes-header: behavior-changed-windowflashframebool-will-flash-dock-icon-continuously-on-macos +``` +--> + * `flag` boolean Starts or stops flashing the window to attract user's attention. @@ -1370,8 +1125,8 @@ The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and * `message` Integer * `callback` Function - * `wParam` any - The `wParam` provided to the WndProc - * `lParam` any - The `lParam` provided to the WndProc + * `wParam` Buffer - The `wParam` provided to the WndProc + * `lParam` Buffer - The `lParam` provided to the WndProc Hooks a windows message. The `callback` is called when the message is received in the WndProc. @@ -1418,13 +1173,16 @@ Returns `boolean` - Whether the window's document has been edited. #### `win.blurWebView()` -#### `win.capturePage([rect])` +#### `win.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md) -Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. +Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. The page is considered visible when its browser window is hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `win.loadURL(url[, options])` @@ -1449,11 +1207,14 @@ To ensure that file URLs are properly formatted, it is recommended to use Node's [`url.format`](https://nodejs.org/api/url.html#url_url_format_urlobject) method: -```javascript +```js +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() + const url = require('url').format({ protocol: 'file', slashes: true, - pathname: require('path').join(__dirname, 'index.html') + pathname: require('node:path').join(__dirname, 'index.html') }) win.loadURL(url) @@ -1462,7 +1223,10 @@ win.loadURL(url) You can load a URL using a `POST` request with URL-encoded data by doing the following: -```javascript +```js +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() + win.loadURL('http://localhost:8000/post', { postData: [{ type: 'rawData', @@ -1476,7 +1240,7 @@ win.loadURL('http://localhost:8000/post', { * `filePath` string * `options` Object (optional) - * `query` Record<string, string> (optional) - Passed to `url.format()`. + * `query` Record\<string, string\> (optional) - Passed to `url.format()`. * `search` string (optional) - Passed to `url.format()`. * `hash` string (optional) - Passed to `url.format()`. @@ -1508,7 +1272,7 @@ Remove the window's menu bar. * `options` Object (optional) * `mode` string _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`. -Sets progress value in progress bar. Valid range is [0, 1.0]. +Sets progress value in progress bar. Valid range is \[0, 1.0]. Remove progress bar when progress < 0; Change to indeterminate mode when progress > 1. @@ -1532,6 +1296,13 @@ screen readers Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to convey some sort of application status or to passively notify the user. +#### `win.invalidateShadow()` _macOS_ + +Invalidates the window shadow so that it is recomputed based on the current window shape. + +`BrowserWindows` that are transparent can sometimes leave behind visual artifacts on macOS. +This method can be used to clear these artifacts when, for example, performing an animation. + #### `win.setHasShadow(hasShadow)` * `hasShadow` boolean @@ -1547,7 +1318,7 @@ Returns `boolean` - Whether the window has a shadow. * `opacity` number - between 0.0 (fully transparent) and 1.0 (fully opaque) Sets the opacity of the window. On Linux, does nothing. Out of bound number -values are clamped to the [0, 1] range. +values are clamped to the \[0, 1] range. #### `win.getOpacity()` @@ -1622,13 +1393,13 @@ in the taskbar. #### `win.setAppDetails(options)` _Windows_ * `options` Object - * `appId` string (optional) - Window's [App User Model ID](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx). + * `appId` string (optional) - Window's [App User Model ID](https://learn.microsoft.com/en-us/windows/win32/shell/appids). It has to be set, otherwise the other options will have no effect. - * `appIconPath` string (optional) - Window's [Relaunch Icon](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391573(v=vs.85).aspx). + * `appIconPath` string (optional) - Window's [Relaunch Icon](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource). * `appIconIndex` Integer (optional) - Index of the icon in `appIconPath`. Ignored when `appIconPath` is not set. Default is `0`. - * `relaunchCommand` string (optional) - Window's [Relaunch Command](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391571(v=vs.85).aspx). - * `relaunchDisplayName` string (optional) - Window's [Relaunch Display Name](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391572(v=vs.85).aspx). + * `relaunchCommand` string (optional) - Window's [Relaunch Command](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchcommand). + * `relaunchDisplayName` string (optional) - Window's [Relaunch Display Name](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource). Sets the properties for the window's taskbar button. @@ -1734,7 +1505,7 @@ On macOS it does not remove the focus from the window. #### `win.isFocusable()` _macOS_ _Windows_ -Returns whether the window can be focused. +Returns `boolean` - Whether the window can be focused. #### `win.setParentWindow(parent)` @@ -1767,6 +1538,10 @@ tabs in the window. Selects the next tab when native tabs are enabled and there are other tabs in the window. +#### `win.showAllTabs()` _macOS_ + +Shows or hides the tab overview when native tabs are enabled. + #### `win.mergeAllWindows()` _macOS_ Merges all windows into one window with multiple tabs when native tabs @@ -1788,28 +1563,44 @@ there is only one tab in the current window. Adds a window as a tab on this window, after the tab for the window instance. -#### `win.setVibrancy(type)` _macOS_ +#### `win.setVibrancy(type[, options])` _macOS_ -* `type` string | null - Can be `appearance-based`, `light`, `dark`, `titlebar`, - `selection`, `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See +* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See the [macOS documentation][vibrancy-docs] for more details. +* `options` Object (optional) + * `animationDuration` number (optional) - if greater than zero, the change to vibrancy will be animated over the given duration (in milliseconds). Adds a vibrancy effect to the browser window. Passing `null` or an empty string -will remove the vibrancy effect on the window. +will remove the vibrancy effect on the window. The `animationDuration` parameter only + animates fading in or fading out the vibrancy effect. Animating between + different types of vibrancy is not supported. + +#### `win.setBackgroundMaterial(material)` _Windows_ + +* `material` string + * `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default. + * `none` - Don't draw any system backdrop. + * `mica` - Draw the backdrop material effect corresponding to a long-lived window. + * `acrylic` - Draw the backdrop material effect corresponding to a transient window. + * `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar. + +This method sets the browser window's system-drawn background material, including behind the non-client area. -Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been -deprecated and will be removed in an upcoming version of macOS. +See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details. -#### `win.setTrafficLightPosition(position)` _macOS_ +**Note:** This method is only supported on Windows 11 22H2 and up. -* `position` [Point](structures/point.md) +#### `win.setWindowButtonPosition(position)` _macOS_ + +* `position` [Point](structures/point.md) | null Set a custom position for the traffic light buttons in frameless window. +Passing `null` will reset the position to default. -#### `win.getTrafficLightPosition()` _macOS_ +#### `win.getWindowButtonPosition()` _macOS_ -Returns `Point` - The custom position for the traffic light buttons in -frameless window. +Returns `Point | null` - The custom position for the traffic light buttons in +frameless window, `null` will be returned when there is no custom position. #### `win.setTouchBar(touchBar)` _macOS_ @@ -1817,63 +1608,82 @@ frameless window. Sets the touchBar layout for the current window. Specifying `null` or `undefined` clears the touch bar. This method only has an effect if the -machine has a touch bar and is running on macOS 10.12.1+. +machine has a touch bar. **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. -#### `win.setBrowserView(browserView)` _Experimental_ +#### `win.setBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) | null - Attach `browserView` to `win`. If there are other `BrowserView`s attached, they will be removed from this window. -#### `win.getBrowserView()` _Experimental_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.getBrowserView()` _Experimental_ _Deprecated_ Returns `BrowserView | null` - The `BrowserView` attached to `win`. Returns `null` if one is not attached. Throws an error if multiple `BrowserView`s are attached. -#### `win.addBrowserView(browserView)` _Experimental_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.addBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) Replacement API for setBrowserView supporting work with multi browser views. -#### `win.removeBrowserView(browserView)` _Experimental_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.removeBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) -#### `win.setTopBrowserView(browserView)` _Experimental_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.setTopBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) Raises `browserView` above other `BrowserView`s attached to `win`. Throws an error if `browserView` is not attached to `win`. -#### `win.getBrowserViews()` _Experimental_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. -Returns `BrowserView[]` - an array of all BrowserViews that have been attached -with `addBrowserView` or `setBrowserView`. +#### `win.getBrowserViews()` _Experimental_ _Deprecated_ -**Note:** The BrowserView API is currently experimental and may change or be -removed in future Electron releases. +Returns `BrowserView[]` - a sorted by z-index array of all BrowserViews that have been attached +with `addBrowserView` or `setBrowserView`. The top-most BrowserView is the last element of the array. -#### `win.setTitleBarOverlay(options)` _Windows_ +> **Note** +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.setTitleBarOverlay(options)` _Windows_ _Linux_ * `options` Object - * `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. - * `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. - * `height` Integer (optional) _Windows_ - The height of the title bar and Window Controls Overlay in pixels. + * `color` String (optional) - The CSS color of the Window Controls Overlay when enabled. + * `symbolColor` String (optional) - The CSS color of the symbols on the Window Controls Overlay when enabled. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. + +On a window with Window Controls Overlay already enabled, this method updates the style of the title bar overlay. -On a Window with Window Controls Overlay already enabled, this method updates -the style of the title bar overlay. +On Linux, the `symbolColor` is automatically calculated to have minimum accessible contrast to the `color` if not explicitly set. -[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70 [page-visibility-api]: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API [quick-look]: https://en.wikipedia.org/wiki/Quick_Look [vibrancy-docs]: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc [window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level -[chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter -[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis -[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables +[window-session-end-event]:../api/structures/window-session-end-event.md diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 81410a281816f..21490bf1f1018 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -2,7 +2,7 @@ > Make HTTP/HTTPS requests. -Process: [Main](../glossary.md#main-process)<br /> +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)<br /> _This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ `ClientRequest` implements the [Writable Stream](https://nodejs.org/api/stream.html#stream_writable_streams) @@ -17,18 +17,22 @@ following properties: method. * `url` string (optional) - The request URL. Must be provided in the absolute form with the protocol scheme specified as http or https. + * `headers` Record\<string, string | string[]\> (optional) - Headers to be sent + with the request. * `session` Session (optional) - The [`Session`](session.md) instance with which the request is associated. * `partition` string (optional) - The name of the [`partition`](session.md) with which the request is associated. Defaults to the empty string. The `session` option supersedes `partition`. Thus if a `session` is explicitly specified, `partition` is ignored. - * `credentials` string (optional) - Can be `include` or `omit`. Whether to - send [credentials](https://fetch.spec.whatwg.org/#credentials) with this + * `credentials` string (optional) - Can be `include`, `omit` or + `same-origin`. Whether to send + [credentials](https://fetch.spec.whatwg.org/#credentials) with this request. If set to `include`, credentials from the session associated with the request will be used. If set to `omit`, credentials will not be sent with the request (and the `'login'` event will not be triggered in the - event of a 401). This matches the behavior of the + event of a 401). If set to `same-origin`, `origin` must also be specified. + This matches the behavior of the [fetch](https://fetch.spec.whatwg.org/#concept-request-credentials-mode) option of the same name. If this option is not specified, authentication data from the session will be sent, and cookies will not be sent (unless @@ -49,6 +53,13 @@ following properties: [`request.followRedirect`](#requestfollowredirect) is invoked synchronously during the [`redirect`](#event-redirect) event. Defaults to `follow`. * `origin` string (optional) - The origin URL of the request. + * `referrerPolicy` string (optional) - can be "", `no-referrer`, + `no-referrer-when-downgrade`, `origin`, `origin-when-cross-origin`, + `unsafe-url`, `same-origin`, `strict-origin`, or + `strict-origin-when-cross-origin`. Defaults to + `strict-origin-when-cross-origin`. + * `cache` string (optional) - can be `default`, `no-store`, `reload`, + `no-cache`, `force-cache` or `only-if-cached`. `options` properties such as `protocol`, `host`, `hostname`, `port` and `path` strictly follow the Node.js model as described in the @@ -56,7 +67,7 @@ strictly follow the Node.js model as described in the For instance, we could have created the same request to 'github.com' as follows: -```JavaScript +```js const request = net.request({ method: 'GET', protocol: 'https:', @@ -95,7 +106,7 @@ The `callback` function is expected to be called back with user credentials: * `username` string * `password` string -```JavaScript +```js @ts-type={request:Electron.ClientRequest} request.on('login', (authInfo, callback) => { callback('username', 'password') }) @@ -104,9 +115,9 @@ request.on('login', (authInfo, callback) => { Providing empty credentials will cancel the request and report an authentication error on the response object: -```JavaScript +```js @ts-type={request:Electron.ClientRequest} request.on('response', (response) => { - console.log(`STATUS: ${response.statusCode}`); + console.log(`STATUS: ${response.statusCode}`) response.on('error', (error) => { console.log(`ERROR: ${JSON.stringify(error)}`) }) @@ -149,7 +160,7 @@ Returns: * `statusCode` Integer * `method` string * `redirectUrl` string -* `responseHeaders` Record<string, string[]> +* `responseHeaders` Record\<string, string[]\> Emitted when the server returns a redirect response (e.g. 301 Moved Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will @@ -234,6 +245,8 @@ it is not allowed to add or remove a custom header. * `encoding` string (optional) * `callback` Function (optional) +Returns `this`. + Sends the last chunk of the request data. Subsequent write or end operations will not be allowed. The `finish` event is emitted just after the end operation. diff --git a/docs/api/clipboard.md b/docs/api/clipboard.md index 3d43c3715de4c..c4328e2871720 100644 --- a/docs/api/clipboard.md +++ b/docs/api/clipboard.md @@ -2,12 +2,12 @@ > Perform copy and paste operations on the system clipboard. -Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) (non-sandboxed only) On Linux, there is also a `selection` clipboard. To manipulate it you need to pass `selection` to each method: -```javascript +```js const { clipboard } = require('electron') clipboard.writeText('Example string', 'selection') @@ -148,10 +148,7 @@ clipboard. ```js const { clipboard } = require('electron') -clipboard.writeBookmark({ - text: 'https://electronjs.org', - bookmark: 'Electron Homepage' -}) +clipboard.writeBookmark('Electron Homepage', 'https://electronjs.org') ``` ### `clipboard.readFindText()` _macOS_ @@ -226,7 +223,7 @@ clipboard.writeBuffer('public/utf8-plain-text', buffer) const ret = clipboard.readBuffer('public/utf8-plain-text') -console.log(buffer.equals(out)) +console.log(buffer.equals(ret)) // true ``` diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index d628b0549c1dd..6c80fde7c1794 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -6,7 +6,7 @@ You can use [app.commandLine.appendSwitch][append-switch] to append them in your app's main script before the [ready][ready] event of the [app][app] module is emitted: -```javascript +```js const { app } = require('electron') app.commandLine.appendSwitch('remote-debugging-port', '8315') app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') @@ -38,7 +38,7 @@ Without `*` prefix the URL has to match exactly. ### --disable-ntlm-v2 -Disables NTLM v2 for posix platforms, no effect elsewhere. +Disables NTLM v2 for POSIX platforms, no effect elsewhere. ### --disable-http-cache @@ -61,7 +61,7 @@ throttling in one window, you can take the hack of Forces the maximum disk space to be used by the disk cache, in bytes. -### --enable-logging[=file] +### --enable-logging\[=file] Prints Chromium's logging to stderr (or a log file). @@ -116,14 +116,20 @@ Ignore the connections limit for `domains` list separated by `,`. ### --js-flags=`flags` -Specifies the flags passed to the Node.js engine. It has to be passed when starting -Electron if you want to enable the `flags` in the main process. +Specifies the flags passed to the [V8 engine](https://v8.dev). In order to enable the `flags` in the main process, +this switch must be passed on startup. ```sh $ electron --js-flags="--harmony_proxies --harmony_collections" your-app ``` -See the [Node.js documentation][node-cli] or run `node --help` in your terminal for a list of available flags. Additionally, run `node --v8-options` to see a list of flags that specifically refer to Node.js's V8 JavaScript engine. +Run `node --v8-options` or `electron --js-flags="--help"` in your terminal for the list of available flags. These can be used to enable early-stage JavaScript features, or log and manipulate garbage collection, among other things. + +For example, to trace V8 optimization and deoptimization: + +```sh +$ electron --js-flags="--trace-opt --trace-deopt" your-app +``` ### --lang @@ -179,7 +185,7 @@ list of hosts. This flag has an effect only if used in tandem with For example: -```javascript +```js const { app } = require('electron') app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678') ``` @@ -235,25 +241,38 @@ Force using discrete GPU when there are multiple GPUs available. Force using integrated GPU when there are multiple GPUs available. +### --xdg-portal-required-version=`version` + +Sets the minimum required version of XDG portal implementation to `version` +in order to use the portal backend for file dialogs on linux. File dialogs +will fallback to using gtk or kde depending on the desktop environment when +the required version is unavailable. Current default is set to `3`. + ## Node.js Flags Electron supports some of the [CLI flags][node-cli] supported by Node.js. **Note:** Passing unsupported command line switches to Electron when it is not running in `ELECTRON_RUN_AS_NODE` will have no effect. -### --inspect-brk[=[host:]port] +### `--inspect-brk\[=\[host:]port]` Activate inspector on host:port and break at start of user script. Default host:port is 127.0.0.1:9229. Aliased to `--debug-brk=[host:]port`. -### --inspect-port=[host:]port +#### `--inspect-brk-node[=[host:]port]` + +Activate inspector on `host:port` and break at start of the first internal +JavaScript script executed when the inspector is available. +Default `host:port` is `127.0.0.1:9229`. + +### `--inspect-port=\[host:]port` Set the `host:port` to be used when the inspector is activated. Useful when activating the inspector by sending the SIGUSR1 signal. Default host is `127.0.0.1`. Aliased to `--debug-port=[host:]port`. -### --inspect[=[host:]port] +### `--inspect\[=\[host:]port]` Activate inspector on `host:port`. Default is `127.0.0.1:9229`. @@ -263,16 +282,39 @@ See the [Debugging the Main Process][debugging-main-process] guide for more deta Aliased to `--debug[=[host:]port`. -### --inspect-publish-uid=stderr,http +### `--inspect-publish-uid=stderr,http` Specify ways of the inspector web socket url exposure. -By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list. +By default inspector websocket url is available in stderr and under /json/list endpoint on `http://host:port/json/list`. + +### `--no-deprecation` + +Silence deprecation warnings. + +### `--throw-deprecation` + +Throw errors for deprecations. + +### `--trace-deprecation` + +Print stack traces for deprecations. + +### `--trace-warnings` + +Print stack traces for process warnings (including deprecations). + +### `--dns-result-order=order` + +Set the default value of the `verbatim` parameter in the Node.js [`dns.lookup()`](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback) and [`dnsPromises.lookup()`](https://nodejs.org/api/dns.html#dnspromiseslookuphostname-options) functions. The value could be: + +* `ipv4first`: sets default `verbatim` `false`. +* `verbatim`: sets default `verbatim` `true`. + +The default is `verbatim` and `dns.setDefaultResultOrder()` have higher priority than `--dns-result-order`. [app]: app.md [append-switch]: command-line.md#commandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files [debugging-main-process]: ../tutorial/debugging-main-process.md [logging]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h [node-cli]: https://nodejs.org/api/cli.html diff --git a/docs/api/command-line.md b/docs/api/command-line.md index 9d36a03161b36..63046d734624d 100644 --- a/docs/api/command-line.md +++ b/docs/api/command-line.md @@ -7,7 +7,7 @@ _This class is not exported from the `'electron'` module. It is only available a The following example shows how to check if the `--disable-gpu` flag is set. -```javascript +```js const { app } = require('electron') app.commandLine.hasSwitch('disable-gpu') ``` diff --git a/docs/api/content-tracing.md b/docs/api/content-tracing.md index ec8e3f7979701..f4646f2ad3e67 100644 --- a/docs/api/content-tracing.md +++ b/docs/api/content-tracing.md @@ -10,7 +10,7 @@ This module does not include a web interface. To view recorded traces, use **Note:** You should not use this module until the `ready` event of the app module is emitted. -```javascript +```js const { app, contentTracing } = require('electron') app.whenReady().then(() => { @@ -35,8 +35,8 @@ The `contentTracing` module has the following methods: Returns `Promise<string[]>` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request Get a set of category groups. The category groups can change as new code paths -are reached. See also the [list of built-in tracing -categories](https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h). +are reached. See also the +[list of built-in tracing categories](https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h). > **NOTE:** Electron adds a non-default tracing category called `"electron"`. > This category can be used to capture Electron-specific tracing events. diff --git a/docs/api/context-bridge.md b/docs/api/context-bridge.md index 5d62220bd6070..1776b7c61a1f9 100644 --- a/docs/api/context-bridge.md +++ b/docs/api/context-bridge.md @@ -1,12 +1,21 @@ # contextBridge +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + > Create a safe, bi-directional, synchronous bridge across isolated contexts Process: [Renderer](../glossary.md#renderer-process) An example of exposing an API to a renderer from an isolated preload script is given below: -```javascript +```js // Preload (Isolated World) const { contextBridge, ipcRenderer } = require('electron') @@ -18,7 +27,7 @@ contextBridge.exposeInMainWorld( ) ``` -```javascript +```js @ts-nocheck // Renderer (Main World) window.electron.doThing() @@ -46,6 +55,26 @@ The `contextBridge` module has the following methods: * `apiKey` string - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. * `api` any - Your API, more information on what this API can be and how it works is available below. +### `contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)` + +* `worldId` Integer - The ID of the world to inject the API into. `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. Using 999 would expose the object for preload context. We recommend using 1000+ while creating isolated world. +* `apiKey` string - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. +* `api` any - Your API, more information on what this API can be and how it works is available below. + +### `contextBridge.executeInMainWorld(executionScript)` _Experimental_ + +<!-- TODO(samuelmaddock): add generics to map the `args` types to the `func` params --> + +* `executionScript` Object + * `func` (...args: any[]) => any - A JavaScript function to execute. This function will be serialized which means + that any bound parameters and execution context will be lost. + * `args` any[] (optional) - An array of arguments to pass to the provided function. These + arguments will be copied between worlds in accordance with + [the table of supported types.](#parameter--error--return-type-support) + +Returns `any` - A copy of the resulting value from executing the function in the main world. +[Refer to the table](#parameter--error--return-type-support) on how values are copied between worlds. + ## Usage ### API @@ -58,8 +87,8 @@ the API become immutable and updates on either side of the bridge do not result An example of a complex API is shown below: -```javascript -const { contextBridge } = require('electron') +```js +const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld( 'electron', @@ -84,6 +113,26 @@ contextBridge.exposeInMainWorld( ) ``` +An example of `exposeInIsolatedWorld` is shown below: + +```js +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInIsolatedWorld( + 1004, + 'electron', + { + doThing: () => ipcRenderer.send('do-a-thing') + } +) +``` + +```js @ts-nocheck +// Renderer (In isolated world id1004) + +window.electron.doThing() +``` + ### API Functions `Function` values that you bind through the `contextBridge` are proxied through Electron to ensure that contexts remain isolated. This @@ -103,7 +152,7 @@ has been included below for completeness: | `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. | | `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type | | `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) | -| `Promise` | Complex | ✅ | ✅ | N/A +| `Promise` | Complex | ✅ | ✅ | N/A | | `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. | | [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types | | `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. | @@ -112,6 +161,25 @@ has been included below for completeness: If the type you care about is not in the above table, it is probably not supported. +### Exposing ipcRenderer + +Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will result in +an empty object on the receiving side of the bridge. Sending over `ipcRenderer` in full can let any +code send any message, which is a security footgun. To interact through `ipcRenderer`, provide a safe wrapper +like below: + +```js +// Preload (Isolated World) +contextBridge.exposeInMainWorld('electron', { + onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args)) +}) +``` + +```js @ts-nocheck +// Renderer (Main World) +window.electron.onMyEventName(data => { /* ... */ }) +``` + ### Exposing Node Global Symbols The `contextBridge` can be used by the preload script to give your renderer access to Node APIs. @@ -119,9 +187,9 @@ The table of supported types described above also applies to Node APIs that you Please note that many Node APIs grant access to local system resources. Be very cautious about which globals and APIs you expose to untrusted remote content. -```javascript +```js const { contextBridge } = require('electron') -const crypto = require('crypto') +const crypto = require('node:crypto') contextBridge.exposeInMainWorld('nodeCrypto', { sha256sum (data) { const hash = crypto.createHash('sha256') diff --git a/docs/api/cookies.md b/docs/api/cookies.md index 99b02ded75e83..8a3576d3fc60b 100644 --- a/docs/api/cookies.md +++ b/docs/api/cookies.md @@ -10,7 +10,7 @@ a `Session`. For example: -```javascript +```js const { session } = require('electron') // Query all cookies. @@ -22,7 +22,7 @@ session.defaultSession.cookies.get({}) }) // Query all cookies associated with a specific url. -session.defaultSession.cookies.get({ url: 'http://www.github.com' }) +session.defaultSession.cookies.get({ url: 'https://www.github.com' }) .then((cookies) => { console.log(cookies) }).catch((error) => { @@ -31,7 +31,7 @@ session.defaultSession.cookies.get({ url: 'http://www.github.com' }) // Set a cookie with the given cookie data; // may overwrite equivalent cookies if they exist. -const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' } +const cookie = { url: 'https://www.github.com', name: 'dummy_name', value: 'dummy' } session.defaultSession.cookies.set(cookie) .then(() => { // success @@ -78,6 +78,7 @@ The following methods are available on instances of `Cookies`: * `path` string (optional) - Retrieves cookies whose path matches `path`. * `secure` boolean (optional) - Filters cookies by their Secure property. * `session` boolean (optional) - Filters out session or persistent cookies. + * `httpOnly` boolean (optional) - Filters cookies by httpOnly. Returns `Promise<Cookie[]>` - A promise which resolves an array of cookie objects. @@ -118,4 +119,8 @@ Removes the cookies matching `url` and `name` Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed -Writes any unwritten cookies data to disk. +Writes any unwritten cookies data to disk + +Cookies written by any method will not be written to disk immediately, but will be written every 30 seconds or 512 operations + +Calling this method can cause the cookie to be written to disk immediately. diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index 9ef7ecc313281..26c685f8a48a3 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -7,7 +7,7 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer The following is an example of setting up Electron to automatically submit crash reports to a remote server: -```javascript +```js const { crashReporter } = require('electron') crashReporter.start({ submitURL: 'https://your-domain.com/url-to-submit' }) @@ -16,7 +16,7 @@ crashReporter.start({ submitURL: 'https://your-domain.com/url-to-submit' }) For setting up a server to accept and process crash reports, you can use following projects: -* [socorro](https://github.com/mozilla/socorro) +* [socorro](https://github.com/mozilla-services/socorro) * [mini-breakpad-server](https://github.com/electron/mini-breakpad-server) > **Note:** Electron uses Crashpad, not Breakpad, to collect and upload @@ -59,14 +59,14 @@ The `crashReporter` module has the following methods: number of crashes uploaded to 1/hour. Default is `false`. * `compress` boolean (optional) - If true, crash reports will be compressed and uploaded with `Content-Encoding: gzip`. Default is `true`. - * `extra` Record<string, string> (optional) - Extra string key/value + * `extra` Record\<string, string\> (optional) - Extra string key/value annotations that will be sent along with crash reports that are generated in the main process. Only string values are supported. Crashes generated in child processes will not contain these extra parameters to crash reports generated from child processes, call [`addExtraParameter`](#crashreporteraddextraparameterkey-value) from the child process. - * `globalExtra` Record<string, string> (optional) - Extra string key/value + * `globalExtra` Record\<string, string\> (optional) - Extra string key/value annotations that will be sent along with any crash reports generated in any process. These annotations cannot be changed once the crash reporter has been started. If a key is present in both the global extra parameters and @@ -100,7 +100,7 @@ longer than the maximum length will be truncated. ### `crashReporter.getLastCrashReport()` -Returns [`CrashReport`](structures/crash-report.md) - The date and ID of the +Returns [`CrashReport | null`](structures/crash-report.md) - The date and ID of the last crash report. Only crash reports that have been uploaded will be returned; even if a crash report is present on disk it will not be returned until it is uploaded. In the case that there are no uploaded reports, `null` is returned. diff --git a/docs/api/debugger.md b/docs/api/debugger.md index d8cf9eddc03dd..26a4b7c6a9f9c 100644 --- a/docs/api/debugger.md +++ b/docs/api/debugger.md @@ -8,7 +8,7 @@ _This class is not exported from the `'electron'` module. It is only available a Chrome Developer Tools has a [special binding][rdp] available at JavaScript runtime that allows interacting with pages and instrumenting them. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -59,7 +59,6 @@ Returns: Emitted whenever the debugging target issues an instrumentation event. [rdp]: https://chromedevtools.github.io/devtools-protocol/ -[`webContents.findInPage`]: web-contents.md#contentsfindinpagetext-options ### Instance Methods diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index fa4874e3c86f7..89f6f120062f7 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -1,85 +1,77 @@ # desktopCapturer > Access information about media sources that can be used to capture audio and -> video from the desktop using the [`navigator.mediaDevices.getUserMedia`] API. +> video from the desktop using the [`navigator.mediaDevices.getUserMedia`][] API. Process: [Main](../glossary.md#main-process) The following example shows how to capture video from a desktop window whose title is `Electron`: -```javascript -// In the main process. -const { desktopCapturer } = require('electron') +```js +// main.js +const { app, BrowserWindow, desktopCapturer, session } = require('electron') -desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => { - for (const source of sources) { - if (source.name === 'Electron') { - mainWindow.webContents.send('SET_SOURCE', source.id) - return - } - } -}) -``` +app.whenReady().then(() => { + const mainWindow = new BrowserWindow() -```javascript -// In the preload script. -const { ipcRenderer } = require('electron') - -ipcRenderer.on('SET_SOURCE', async (event, sourceId) => { - try { - const stream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sourceId, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } + session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + desktopCapturer.getSources({ types: ['screen'] }).then((sources) => { + // Grant access to the first screen found. + callback({ video: sources[0], audio: 'loopback' }) }) - handleStream(stream) - } catch (e) { - handleError(e) - } + // If true, use the system picker if available. + // Note: this is currently experimental. If the system picker + // is available, it will be used and the media request handler + // will not be invoked. + }, { useSystemPicker: true }) + + mainWindow.loadFile('index.html') }) +``` -function handleStream (stream) { - const video = document.querySelector('video') - video.srcObject = stream - video.onloadedmetadata = (e) => video.play() -} +```js +// renderer.js +const startButton = document.getElementById('startButton') +const stopButton = document.getElementById('stopButton') +const video = document.querySelector('video') + +startButton.addEventListener('click', () => { + navigator.mediaDevices.getDisplayMedia({ + audio: true, + video: { + width: 320, + height: 240, + frameRate: 30 + } + }).then(stream => { + video.srcObject = stream + video.onloadedmetadata = (e) => video.play() + }).catch(e => console.log(e)) +}) -function handleError (e) { - console.log(e) -} +stopButton.addEventListener('click', () => { + video.pause() +}) ``` -To capture video from a source provided by `desktopCapturer` the constraints -passed to [`navigator.mediaDevices.getUserMedia`] must include -`chromeMediaSource: 'desktop'`, and `audio: false`. +```html +<!-- index.html --> +<html> +<meta http-equiv="content-security-policy" content="script-src 'self' 'unsafe-inline'" /> + <body> + <button id="startButton" class="button">Start</button> + <button id="stopButton" class="button">Stop</button> + <video width="320" height="240" autoplay></video> + <script src="renderer.js"></script> + </body> +</html> +``` -To capture both audio and video from the entire desktop the constraints passed -to [`navigator.mediaDevices.getUserMedia`] must include `chromeMediaSource: 'desktop'`, -for both `audio` and `video`, but should not include a `chromeMediaSourceId` constraint. +See [`navigator.mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) for more information. -```javascript -const constraints = { - audio: { - mandatory: { - chromeMediaSource: 'desktop' - } - }, - video: { - mandatory: { - chromeMediaSource: 'desktop' - } - } -} -``` +**Note:** `navigator.mediaDevices.getDisplayMedia` does not permit the use of `deviceId` for +selection of a source - see [specification](https://w3c.github.io/mediacapture-screen-share/#constraints). ## Methods @@ -89,7 +81,7 @@ The `desktopCapturer` module has the following methods: * `options` Object * `types` string[] - An array of strings that lists the types of desktop sources - to be captured, available types are `screen` and `window`. + to be captured, available types can be `screen` and `window`. * `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail should be scaled to. Default is `150` x `150`. Set width or height to 0 when you do not need the thumbnails. This will save the processing time required for capturing the content of each @@ -101,7 +93,7 @@ The `desktopCapturer` module has the following methods: Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured. **Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher, -which can detected by [`systemPreferences.getMediaAccessStatus`]. +which can detected by [`systemPreferences.getMediaAccessStatus`][]. [`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia [`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos diff --git a/docs/api/dialog.md b/docs/api/dialog.md index bc536e15baee1..27590bf6c209c 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process) An example of showing a dialog to select multiple files: -```javascript +```js const { dialog } = require('electron') console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })) ``` @@ -15,9 +15,9 @@ console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] The `dialog` module has the following methods: -### `dialog.showOpenDialogSync([browserWindow, ]options)` +### `dialog.showOpenDialogSync([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `title` string (optional) * `defaultPath` string (optional) @@ -47,12 +47,12 @@ The `dialog` module has the following methods: Returns `string[] | undefined`, the file paths chosen by the user; if the dialog is cancelled it returns `undefined`. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed or selected when you want to limit the user to a specific type. For example: -```javascript +```js { filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, @@ -72,15 +72,20 @@ and a directory selector, so if you set `properties` to `['openFile', 'openDirectory']` on these platforms, a directory selector will be shown. -```js +```js @ts-type={mainWindow:Electron.BaseWindow} dialog.showOpenDialogSync(mainWindow, { properties: ['openFile', 'openDirectory'] }) ``` -### `dialog.showOpenDialog([browserWindow, ]options)` +**Note:** On Linux `defaultPath` is not supported when using portal file chooser +dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version` +[command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion) +to force gtk or kde dialogs. + +### `dialog.showOpenDialog([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `title` string (optional) * `defaultPath` string (optional) @@ -114,12 +119,12 @@ Returns `Promise<Object>` - Resolve with an object containing the following: * `filePaths` string[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. * `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).) -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed or selected when you want to limit the user to a specific type. For example: -```javascript +```js { filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, @@ -139,7 +144,7 @@ and a directory selector, so if you set `properties` to `['openFile', 'openDirectory']` on these platforms, a directory selector will be shown. -```js +```js @ts-type={mainWindow:Electron.BaseWindow} dialog.showOpenDialog(mainWindow, { properties: ['openFile', 'openDirectory'] }).then(result => { @@ -150,9 +155,14 @@ dialog.showOpenDialog(mainWindow, { }) ``` -### `dialog.showSaveDialogSync([browserWindow, ]options)` +**Note:** On Linux `defaultPath` is not supported when using portal file chooser +dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version` +[command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion) +to force gtk or kde dialogs. + +### `dialog.showSaveDialogSync([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. * `defaultPath` string (optional) - Absolute directory path, absolute file @@ -174,16 +184,16 @@ dialog.showOpenDialog(mainWindow, { * `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list. * `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path. -Returns `string | undefined`, the path of the file chosen by the user; if the dialog is cancelled it returns `undefined`. +Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed, see `dialog.showOpenDialog` for an example. -### `dialog.showSaveDialog([browserWindow, ]options)` +### `dialog.showSaveDialog([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. * `defaultPath` string (optional) - Absolute directory path, absolute file @@ -207,10 +217,10 @@ The `filters` specifies an array of file types that can be displayed, see Returns `Promise<Object>` - Resolve with an object containing the following: * `canceled` boolean - whether or not the dialog was canceled. -* `filePath` string (optional) - If the dialog is canceled, this will be `undefined`. +* `filePath` string - If the dialog is canceled, this will be an empty string. * `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).) -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed, see `dialog.showOpenDialog` for an example. @@ -218,15 +228,15 @@ The `filters` specifies an array of file types that can be displayed, see **Note:** On macOS, using the asynchronous version is recommended to avoid issues when expanding and collapsing the dialog. -### `dialog.showMessageBoxSync([browserWindow, ]options)` +### `dialog.showMessageBoxSync([wndow, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `message` string - Content of the message box. - * `type` string (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or - `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless - you set an icon using the `"icon"` option. On macOS, both `"warning"` and - `"error"` display the same warning icon. + * `type` string (optional) - Can be `none`, `info`, `error`, `question` or + `warning`. On Windows, `question` displays the same icon as `info`, unless + you set an icon using the `icon` option. On macOS, both `warning` and + `error` display the same warning icon. * `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will @@ -258,18 +268,18 @@ Returns `Integer` - the index of the clicked button. Shows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. -If `browserWindow` is not shown dialog will not be attached to it. In such case it will be displayed as an independent window. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. +If `window` is not shown dialog will not be attached to it. In such case it will be displayed as an independent window. -### `dialog.showMessageBox([browserWindow, ]options)` +### `dialog.showMessageBox([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `message` string - Content of the message box. - * `type` string (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or - `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless - you set an icon using the `"icon"` option. On macOS, both `"warning"` and - `"error"` display the same warning icon. + * `type` string (optional) - Can be `none`, `info`, `error`, `question` or + `warning`. On Windows, `question` displays the same icon as `info`, unless + you set an icon using the `icon` option. On macOS, both `warning` and + `error` display the same warning icon. * `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will @@ -313,7 +323,7 @@ Returns `Promise<Object>` - resolves with a promise containing the following pro Shows a message box. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. ### `dialog.showErrorBox(title, content)` @@ -327,9 +337,9 @@ it is usually used to report errors in early stage of startup. If called before the app `ready`event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. -### `dialog.showCertificateTrustDialog([browserWindow, ]options)` _macOS_ _Windows_ +### `dialog.showCertificateTrustDialog([window, ]options)` _macOS_ _Windows_ -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. * `message` string - The message to display to the user. @@ -338,19 +348,19 @@ Returns `Promise<void>` - resolves when the certificate trust dialog is shown. On macOS, this displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the -certificate. If you provide a `browserWindow` argument the dialog will be +certificate. If you provide a `window` argument the dialog will be attached to the parent window, making it modal. On Windows the options are more limited, due to the Win32 APIs used: * The `message` argument is not used, as the OS provides its own confirmation dialog. -* The `browserWindow` argument is ignored since it is not possible to make +* The `window` argument is ignored since it is not possible to make this confirmation dialog modal. ## Bookmarks array -`showOpenDialog`, `showOpenDialogSync`, `showSaveDialog`, and `showSaveDialogSync` will return a `bookmarks` array. +`showOpenDialog` and `showSaveDialog` resolve to an object with a `bookmarks` field. This field is an array of Base64 encoded strings that contain the [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) data for the saved file. The `securityScopedBookmarks` option must be enabled for this to be present. | Build Type | securityScopedBookmarks boolean | Return Type | Return Value | |------------|---------------------------------|:-----------:|--------------------------------| @@ -362,10 +372,10 @@ On Windows the options are more limited, due to the Win32 APIs used: ## Sheets On macOS, dialogs are presented as sheets attached to a window if you provide -a [`BrowserWindow`](browser-window.md) reference in the `browserWindow` parameter, or modals if no +a [`BaseWindow`](base-window.md) reference in the `window` parameter, or modals if no window is provided. -You can call `BrowserWindow.getCurrentWindow().setSheetOffset(offset)` to change +You can call `BaseWindow.getCurrentWindow().setSheetOffset(offset)` to change the offset from the window frame where sheets are attached. [AbortSignal]: https://nodejs.org/api/globals.html#globals_class_abortsignal diff --git a/docs/api/dock.md b/docs/api/dock.md index 3e798e793192e..ea6ad93db7857 100644 --- a/docs/api/dock.md +++ b/docs/api/dock.md @@ -7,7 +7,7 @@ _This class is not exported from the `'electron'` module. It is only available a The following example shows how to bounce your icon on the dock. -```javascript +```js const { app } = require('electron') app.dock.bounce() ``` @@ -79,3 +79,5 @@ Returns `Menu | null` - The application's [dock menu][dock-menu]. * `image` ([NativeImage](native-image.md) | string) Sets the `image` associated with this dock icon. + +[dock-menu]: https://developer.apple.com/design/human-interface-guidelines/dock-menus diff --git a/docs/api/download-item.md b/docs/api/download-item.md index 0a362d522f91e..dc2c0d1a893e4 100644 --- a/docs/api/download-item.md +++ b/docs/api/download-item.md @@ -9,7 +9,7 @@ _This class is not exported from the `'electron'` module. It is only available a It is used in `will-download` event of `Session` class, and allows users to control the download item. -```javascript +```js // In the main process. const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -145,6 +145,10 @@ Returns `string` - The file name of the download item. disk. If user changes the file name in a prompted download saving dialog, the actual name of saved file will be different. +#### `downloadItem.getCurrentBytesPerSecond()` + +Returns `Integer` - The current download speed in bytes per second. + #### `downloadItem.getTotalBytes()` Returns `Integer` - The total size in bytes of the download item. @@ -155,6 +159,10 @@ If the size is unknown, it returns 0. Returns `Integer` - The received bytes of the download item. +#### `downloadItem.getPercentComplete()` + +Returns `Integer` - The download completion in percent. + #### `downloadItem.getContentDisposition()` Returns `string` - The Content-Disposition field from the response @@ -184,6 +192,10 @@ Returns `string` - ETag header value. Returns `Double` - Number of seconds since the UNIX epoch when the download was started. +#### `downloadItem.getEndTime()` + +Returns `Double` - Number of seconds since the UNIX epoch when the download ended. + ### Instance Properties #### `downloadItem.savePath` diff --git a/docs/api/environment-variables.md b/docs/api/environment-variables.md index ba3d5cf99e6de..643b5fb7be419 100644 --- a/docs/api/environment-variables.md +++ b/docs/api/environment-variables.md @@ -51,6 +51,18 @@ Unsupported options are: --http-parser ``` +If the [`nodeOptions` fuse](../tutorial/fuses.md#nodeoptions) is disabled, `NODE_OPTIONS` will be ignored. + +### `NODE_EXTRA_CA_CERTS` + +See [Node.js cli documentation](https://github.com/nodejs/node/blob/main/doc/api/cli.md#node_extra_ca_certsfile) for details. + +```sh +export NODE_EXTRA_CA_CERTS=/path/to/cert.pem +``` + +If the [`nodeOptions` fuse](../tutorial/fuses.md#nodeoptions) is disabled, `NODE_EXTRA_CA_CERTS` will be ignored. + ### `GOOGLE_API_KEY` Geolocation support in Electron requires the use of Google Cloud Platform's @@ -59,7 +71,7 @@ geolocation webservice. To enable this feature, acquire a and place the following code in your main process file, before opening any browser windows that will make geolocation requests: -```javascript +```js process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE' ``` @@ -92,6 +104,8 @@ you would when running the normal Node.js executable, with the exception of the These flags are disabled owing to the fact that Electron uses BoringSSL instead of OpenSSL when building Node.js' `crypto` module, and so will not work as designed. +If the [`runAsNode` fuse](../tutorial/fuses.md#L13) is disabled, `ELECTRON_RUN_AS_NODE` will be ignored. + ### `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ Don't attach to the current console session. @@ -111,6 +125,16 @@ Options: * `kioclient5` * `kioclient` +### `ELECTRON_OZONE_PLATFORM_HINT` _Linux_ + +Selects the preferred platform backend used on Linux. The default one is `x11`. `auto` selects Wayland if possible, X11 otherwise. + +Options: + +* `auto` +* `wayland` +* `x11` + ## Development Variables The following environment variables are intended primarily for development and @@ -121,21 +145,16 @@ debugging purposes. Prints Chromium's internal logging to the console. Setting this variable is the same as passing `--enable-logging` -on the command line. For more info, see `--enable-logging` in [command-line -switches](./command-line-switches.md#--enable-loggingfile). +on the command line. For more info, see `--enable-logging` in +[command-line switches](./command-line-switches.md#--enable-loggingfile). ### `ELECTRON_LOG_FILE` Sets the file destination for Chromium's internal logging. Setting this variable is the same as passing `--log-file` -on the command line. For more info, see `--log-file` in [command-line -switches](./command-line-switches.md#--log-filepath). - -### `ELECTRON_DEBUG_DRAG_REGIONS` - -Adds coloration to draggable regions on [`BrowserView`](./browser-view.md)s on macOS - draggable regions will be colored -green and non-draggable regions will be colored red to aid debugging. +on the command line. For more info, see `--log-file` in +[command-line switches](./command-line-switches.md#--log-filepath). ### `ELECTRON_DEBUG_NOTIFICATIONS` diff --git a/docs/api/extensions.md b/docs/api/extensions.md index c8fbb015a1f74..e375725db90d3 100644 --- a/docs/api/extensions.md +++ b/docs/api/extensions.md @@ -1,9 +1,8 @@ # Chrome Extension Support -Electron supports a subset of the [Chrome Extensions -API][chrome-extensions-api-index], primarily to support DevTools extensions and -Chromium-internal extensions, but it also happens to support some other -extension capabilities. +Electron supports a subset of the [Chrome Extensions API][chrome-extensions-api-index], +primarily to support DevTools extensions and Chromium-internal extensions, +but it also happens to support some other extension capabilities. [chrome-extensions-api-index]: https://developer.chrome.com/extensions/api_index @@ -20,7 +19,7 @@ work). Extensions are installed per-`session`. To load an extension, call ```js const { session } = require('electron') -session.loadExtension('path/to/unpacked/extension').then(({ id }) => { +session.defaultSession.loadExtension('path/to/unpacked/extension').then(({ id }) => { // ... }) ``` @@ -40,18 +39,41 @@ We support the following extensions APIs, with some caveats. Other APIs may additionally be supported, but support for any APIs not listed here is provisional and may be removed. +### Supported Manifest Keys + +- `name` +- `version` +- `author` +- `permissions` +- `content_scripts` +- `default_locale` +- `devtools_page` +- `short_name` +- `host_permissions` (Manifest V3) +- `manifest_version` +- `background` (Manifest V2) +- `minimum_chrome_version` + +See [Manifest file format](https://developer.chrome.com/docs/extensions/mv3/manifest/) for more information about the purpose of each possible key. + ### `chrome.devtools.inspectedWindow` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_inspectedWindow) for more information. + ### `chrome.devtools.network` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_network) for more information. + ### `chrome.devtools.panels` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_panels) for more information. + ### `chrome.extension` The following properties of `chrome.extension` are supported: @@ -63,6 +85,25 @@ The following methods of `chrome.extension` are supported: - `chrome.extension.getURL` - `chrome.extension.getBackgroundPage` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/extension) for more information. + +### `chrome.management` + +The following methods of `chrome.management` are supported: + +- `chrome.management.getAll` +- `chrome.management.get` +- `chrome.management.getSelf` +- `chrome.management.getPermissionWarningsById` +- `chrome.management.getPermissionWarningsByManifest` + +The following events of `chrome.management` are supported: + +- `chrome.management.onEnabled` +- `chrome.management.onDisabled` + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/management) for more information. + ### `chrome.runtime` The following properties of `chrome.runtime` are supported: @@ -89,10 +130,23 @@ The following events of `chrome.runtime` are supported: - `chrome.runtime.onConnect` - `chrome.runtime.onMessage` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/runtime) for more information. + +### `chrome.scripting` + +All features of this API are supported. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/scripting) for more information. + ### `chrome.storage` -Only `chrome.storage.local` is supported; `chrome.storage.sync` and -`chrome.storage.managed` are not. +The following methods of `chrome.storage` are supported: + +- `chrome.storage.local` + +`chrome.storage.sync` and `chrome.storage.managed` are **not** supported. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/storage) for more information. ### `chrome.tabs` @@ -101,6 +155,8 @@ The following methods of `chrome.tabs` are supported: - `chrome.tabs.sendMessage` - `chrome.tabs.reload` - `chrome.tabs.executeScript` +- `chrome.tabs.query` (partial support) + - supported properties: `url`, `title`, `audible`, `active`, `muted`. - `chrome.tabs.update` (partial support) - supported properties: `url`, `muted`. @@ -108,20 +164,12 @@ The following methods of `chrome.tabs` are supported: > tab". Since Electron has no such concept, passing `-1` as a tab ID is not > supported and will raise an error. -### `chrome.management` - -The following methods of `chrome.management` are supported: - -- `chrome.management.getAll` -- `chrome.management.get` -- `chrome.management.getSelf` -- `chrome.management.getPermissionWarningsById` -- `chrome.management.getPermissionWarningsByManifest` -- `chrome.management.onEnabled` -- `chrome.management.onDisabled` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/tabs) for more information. ### `chrome.webRequest` All features of this API are supported. > **NOTE:** Electron's [`webRequest`](web-request.md) module takes precedence over `chrome.webRequest` if there are conflicting handlers. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/webRequest) for more information. diff --git a/docs/api/file-object.md b/docs/api/file-object.md deleted file mode 100644 index ea0ec4e4ecb95..0000000000000 --- a/docs/api/file-object.md +++ /dev/null @@ -1,31 +0,0 @@ -# `File` Object - -> Use the HTML5 `File` API to work natively with files on the filesystem. - -The DOM's File interface provides abstraction around native files in order to -let users work on native files directly with the HTML5 file API. Electron has -added a `path` attribute to the `File` interface which exposes the file's real -path on filesystem. - -Example of getting a real path from a dragged-onto-the-app file: - -```html -<div id="holder"> - Drag your file here -</div> - -<script> - document.addEventListener('drop', (e) => { - e.preventDefault(); - e.stopPropagation(); - - for (const f of e.dataTransfer.files) { - console.log('File(s) you dragged here: ', f.path) - } - }); - document.addEventListener('dragover', (e) => { - e.preventDefault(); - e.stopPropagation(); - }); -</script> -``` diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md index 52609c981dd58..142bdbaba1adf 100644 --- a/docs/api/global-shortcut.md +++ b/docs/api/global-shortcut.md @@ -12,9 +12,17 @@ shortcuts. not have the keyboard focus. This module cannot be used before the `ready` event of the app module is emitted. -```javascript +Please also note that it is also possible to use Chromium's +`GlobalShortcutsPortal` implementation, which allows apps to bind global +shortcuts when running within a Wayland session. + +```js const { app, globalShortcut } = require('electron') +// Enable usage of Portal's globalShortcuts. This is essential for cases when +// the app runs in a Wayland session. +app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal') + app.whenReady().then(() => { // Register a 'CommandOrControl+X' shortcut listener. const ret = globalShortcut.register('CommandOrControl+X', () => { @@ -66,7 +74,7 @@ the app has been authorized as a [trusted accessibility client](https://develope ### `globalShortcut.registerAll(accelerators, callback)` -* `accelerators` string[] - an array of [Accelerator](accelerator.md)s. +* `accelerators` [Accelerator](accelerator.md)[] - an array of [Accelerator](accelerator.md)s. * `callback` Function Registers a global shortcut of all `accelerator` items in `accelerators`. The `callback` is called when any of the registered shortcuts are pressed by the user. diff --git a/docs/api/in-app-purchase.md b/docs/api/in-app-purchase.md index 1520a0ce3a927..38078ecf29dd7 100644 --- a/docs/api/in-app-purchase.md +++ b/docs/api/in-app-purchase.md @@ -21,10 +21,12 @@ Returns: The `inAppPurchase` module has the following methods: -### `inAppPurchase.purchaseProduct(productID[, quantity])` +### `inAppPurchase.purchaseProduct(productID[, opts])` -* `productID` string - The identifiers of the product to purchase. (The identifier of `com.example.app.product1` is `product1`). -* `quantity` Integer (optional) - The number of items the user wants to purchase. +* `productID` string +* `opts` Integer | Object (optional) - If specified as an integer, defines the quantity. + * `quantity` Integer (optional) - The number of items the user wants to purchase. + * `username` string (optional) - The string that associates the transaction with a user account on your service (applicationUsername). Returns `Promise<boolean>` - Returns `true` if the product is valid and added to the payment queue. diff --git a/docs/api/incoming-message.md b/docs/api/incoming-message.md index 92b9dec58f169..3802b97e62c98 100644 --- a/docs/api/incoming-message.md +++ b/docs/api/incoming-message.md @@ -2,7 +2,7 @@ > Handle responses to HTTP/HTTPS requests. -Process: [Main](../glossary.md#main-process)<br /> +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)<br /> _This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ `IncomingMessage` implements the [Readable Stream](https://nodejs.org/api/stream.html#stream_readable_streams) @@ -31,7 +31,7 @@ Emitted when a request has been canceled during an ongoing HTTP transaction. Returns: -`error` Error - Typically holds an error string identifying failure root cause. +* `error` Error - Typically holds an error string identifying failure root cause. Emitted when an error was encountered while streaming response data events. For instance, if the server closes the underlying while the response is still @@ -89,7 +89,7 @@ tuples. So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values. Header names are not lowercased, and duplicates are not merged. -```javascript +```js @ts-type={response:Electron.IncomingMessage} // Prints something like: // // [ 'user-agent', @@ -100,5 +100,5 @@ duplicates are not merged. // '127.0.0.1:8000', // 'ACCEPT', // '*/*' ] -console.log(request.rawHeaders) +console.log(response.rawHeaders) ``` diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index e7c9800a25b50..b5b84a2176fd5 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -16,7 +16,7 @@ process, it handles asynchronous and synchronous messages sent from a renderer process (web page). Messages sent from a renderer will be emitted to this module. -For usage examples, check out the [IPC tutorial]. +For usage examples, check out the [IPC tutorial][]. ## Sending messages @@ -32,7 +32,7 @@ process, see [webContents.send][web-contents-send] for more information. ## Methods -The `ipcMain` module has the following method to listen for events: +The `ipcMain` module has the following methods to listen for events: ### `ipcMain.on(channel, listener)` @@ -44,6 +44,16 @@ The `ipcMain` module has the following method to listen for events: Listens to `channel`, when a new message arrives `listener` would be called with `listener(event, args...)`. +### `ipcMain.off(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcMainEvent][ipc-main-event] + * `...args` any[] + +Removes the specified `listener` from the listener array for the specified +`channel`. + ### `ipcMain.once(channel, listener)` * `channel` string @@ -54,25 +64,33 @@ Listens to `channel`, when a new message arrives `listener` would be called with Adds a one time `listener` function for the event. This `listener` is invoked only the next time a message is sent to `channel`, after which it is removed. +### `ipcMain.addListener(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcMainEvent][ipc-main-event] + * `...args` any[] + +Alias for [`ipcMain.on`](#ipcmainonchannel-listener). + ### `ipcMain.removeListener(channel, listener)` * `channel` string * `listener` Function * `...args` any[] -Removes the specified `listener` from the listener array for the specified -`channel`. +Alias for [`ipcMain.off`](#ipcmainoffchannel-listener). ### `ipcMain.removeAllListeners([channel])` * `channel` string (optional) -Removes listeners of the specified `channel`. +Removes all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. ### `ipcMain.handle(channel, listener)` * `channel` string -* `listener` Function<Promise\<void> | any> +* `listener` Function\<Promise\<any\> | any\> * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] * `...args` any[] @@ -83,14 +101,14 @@ If `listener` returns a Promise, the eventual result of the promise will be returned as a reply to the remote caller. Otherwise, the return value of the listener will be used as the value of the reply. -```js title='Main Process' +```js title='Main Process' @ts-type={somePromise:(...args:unknown[])=>Promise<unknown>} ipcMain.handle('my-invokable-ipc', async (event, ...args) => { const result = await somePromise(...args) return result }) ``` -```js title='Renderer Process' +```js title='Renderer Process' @ts-type={arg1:unknown} @ts-type={arg2:unknown} async () => { const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2) // ... @@ -109,8 +127,8 @@ provided to the renderer process. Please refer to ### `ipcMain.handleOnce(channel, listener)` * `channel` string -* `listener` Function<Promise\<void> | any> - * `event` IpcMainInvokeEvent +* `listener` Function\<Promise\<any\> | any\> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] * `...args` any[] Handles a single `invoke`able IPC message, then removes the listener. See @@ -122,17 +140,6 @@ Handles a single `invoke`able IPC message, then removes the listener. See Removes any handler for `channel`, if present. -## IpcMainEvent object - -The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-main-event`][ipc-main-event] structure docs. - -## IpcMainInvokeEvent object - -The documentation for the `event` object passed to `handle` callbacks can be -found in the [`ipc-main-invoke-event`][ipc-main-invoke-event] -structure docs. - [IPC tutorial]: ../tutorial/ipc.md [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [web-contents-send]: ../api/web-contents.md#contentssendchannel-args diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index dae89527aa42c..7f2afc41e7c10 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -7,6 +7,15 @@ hide_title: false # ipcRenderer +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + > Communicate asynchronously from a renderer process to the main process. Process: [Renderer](../glossary.md#renderer-process) @@ -26,36 +35,65 @@ The `ipcRenderer` module has the following method to listen for events and send * `channel` string * `listener` Function - * `event` IpcRendererEvent + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] Listens to `channel`, when a new message arrives `listener` would be called with `listener(event, args...)`. +:::warning +Do not expose the `event` argument to the renderer for security reasons! Wrap any +callback that you receive from the renderer in another function like this: +`ipcRenderer.on('my-channel', (event, ...args) => callback(...args))`. +Not wrapping the callback in such a function would expose dangerous Electron APIs +to the renderer process. See the +[security guide](../tutorial/security.md#20-do-not-expose-electron-apis-to-untrusted-web-content) +for more info. +::: + +### `ipcRenderer.off(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] + * `...args` any[] + +Removes the specified `listener` from the listener array for the specified +`channel`. + ### `ipcRenderer.once(channel, listener)` * `channel` string * `listener` Function - * `event` IpcRendererEvent + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] Adds a one time `listener` function for the event. This `listener` is invoked only the next time a message is sent to `channel`, after which it is removed. -### `ipcRenderer.removeListener(channel, listener)` +### `ipcRenderer.addListener(channel, listener)` * `channel` string * `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] -Removes the specified `listener` from the listener array for the specified -`channel`. +Alias for [`ipcRenderer.on`](#ipcrendereronchannel-listener). -### `ipcRenderer.removeAllListeners(channel)` +### `ipcRenderer.removeListener(channel, listener)` * `channel` string +* `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] + * `...args` any[] -Removes all listeners, or those of the specified `channel`. +Alias for [`ipcRenderer.off`](#ipcrendereroffchannel-listener). + +### `ipcRenderer.removeAllListeners([channel])` + +* `channel` string (optional) + +Removes all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. ### `ipcRenderer.send(channel, ...args)` @@ -63,8 +101,8 @@ Removes all listeners, or those of the specified `channel`. * `...args` any[] Send an asynchronous message to the main process via `channel`, along with -arguments. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. @@ -91,25 +129,17 @@ If you want to receive a single response from the main process, like the result Returns `Promise<any>` - Resolves with the response from the main process. Send a message to the main process via `channel` and expect a result -asynchronously. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +asynchronously. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE:** Sending non-standard JavaScript types such as DOM objects or -> special Electron objects will throw an exception. -> -> Since the main process does not have support for DOM objects such as -> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over -> Electron's IPC to the main process, as the main process would have no way to decode -> them. Attempting to send such objects over IPC will result in an error. - The main process should listen for `channel` with [`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener). For example: -```javascript +```js @ts-type={someArgument:unknown} @ts-type={doSomeWork:(arg:unknown)=>Promise<unknown>} // Renderer process ipcRenderer.invoke('some-name', someArgument).then((result) => { // ... @@ -126,6 +156,21 @@ If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRender If you do not need a response to the message, consider using [`ipcRenderer.send`](#ipcrenderersendchannel-args). +> **Note** +> Sending non-standard JavaScript types such as DOM objects or +> special Electron objects will throw an exception. +> +> Since the main process does not have support for DOM objects such as +> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over +> Electron's IPC to the main process, as the main process would have no way to decode +> them. Attempting to send such objects over IPC will result in an error. + +> **Note** +> If the handler in the main process throws an error, +> the promise returned by `invoke` will reject. +> However, the `Error` object in the renderer process +> will not be the same as the one thrown in the main process. + ### `ipcRenderer.sendSync(channel, ...args)` * `channel` string @@ -134,8 +179,8 @@ If you do not need a response to the message, consider using [`ipcRenderer.send` Returns `any` - The value sent back by the [`ipcMain`](./ipc-main.md) handler. Send a message to the main process via `channel` and expect a result -synchronously. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`], so prototype chains will not be +synchronously. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. @@ -182,16 +227,8 @@ ipcMain.on('port', (e, msg) => { }) ``` -For more information on using `MessagePort` and `MessageChannel`, see the [MDN -documentation](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel). - -### `ipcRenderer.sendTo(webContentsId, channel, ...args)` - -* `webContentsId` number -* `channel` string -* `...args` any[] - -Sends a message to a window with `webContentsId` via `channel`. +For more information on using `MessagePort` and `MessageChannel`, see the +[MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel). ### `ipcRenderer.sendToHost(channel, ...args)` @@ -201,12 +238,8 @@ Sends a message to a window with `webContentsId` via `channel`. Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in the host page instead of the main process. -## Event object - -The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-renderer-event`](./structures/ipc-renderer-event.md) structure docs. - [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [`window.postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage [`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort +[ipc-renderer-event]: ./structures/ipc-renderer-event.md diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 3d38a292b4c41..0bc80b2bd37c1 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -10,11 +10,11 @@ See [`Menu`](menu.md) for examples. * `options` Object * `click` Function (optional) - Will be called with - `click(menuItem, browserWindow, event)` when the menu item is clicked. + `click(menuItem, window, event)` when the menu item is clicked. * `menuItem` MenuItem - * `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open. + * `window` [BaseWindow](base-window.md) | undefined - This will not be defined if no window is open. * `event` [KeyboardEvent](structures/keyboard-event.md) - * `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, 'showSubstitutions', 'toggleSmartQuotes', 'toggleSmartDashes', 'toggleTextReplacement', `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the + * `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `showSubstitutions`, `toggleSmartQuotes`, `toggleSmartDashes`, `toggleTextReplacement`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `showAllTabs`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the `click` property will be ignored. See [roles](#roles). * `type` string (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. @@ -25,7 +25,7 @@ See [`Menu`](menu.md) for examples. * `icon` ([NativeImage](native-image.md) | string) (optional) * `enabled` boolean (optional) - If false, the menu item will be greyed out and unclickable. - * `acceleratorWorksWhenHidden` boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible`. + * `acceleratorWorksWhenHidden` boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible. * `visible` boolean (optional) - If false, the menu item will be entirely hidden. * `checked` boolean (optional) - Should only be specified for `checkbox` or `radio` type menu items. @@ -38,20 +38,20 @@ See [`Menu`](menu.md) for examples. `Menu.buildFromTemplate`. * `id` string (optional) - Unique within a single menu. If defined then it can be used as a reference to this item by the position attribute. - * `before` string[] (optional) - Inserts this item before the item with the specified label. If + * `before` string[] (optional) - Inserts this item before the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. Also implies that the menu item in question should be placed in the same “group” as the item. - * `after` string[] (optional) - Inserts this item after the item with the specified label. If the + * `after` string[] (optional) - Inserts this item after the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. * `beforeGroupContaining` string[] (optional) - Provides a means for a single context menu to declare the placement of their containing group before the containing group of the item - with the specified label. + with the specified id. * `afterGroupContaining` string[] (optional) - Provides a means for a single context menu to declare the placement of their containing group after the containing group of the item - with the specified label. + with the specified id. -**Note:** `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development. This property is only usable on macOS High Sierra 10.13 or newer. +**Note:** `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development. ### Roles @@ -111,11 +111,12 @@ The following additional roles are available on _macOS_: * `toggleTabBar` - Map to the `toggleTabBar` action. * `selectNextTab` - Map to the `selectNextTab` action. * `selectPreviousTab` - Map to the `selectPreviousTab` action. +* `showAllTabs` - Map to the `showAllTabs` action. * `mergeAllWindows` - Map to the `mergeAllWindows` action. * `moveTabToNewWindow` - Map to the `moveTabToNewWindow` action. * `window` - The submenu is a "Window" menu. * `help` - The submenu is a "Help" menu. -* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is *not* the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron. +* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is _not_ the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron. * `recentDocuments` - The submenu is an "Open Recent" menu. * `clearRecentDocuments` - Map to the `clearRecentDocuments` action. * `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share. @@ -145,7 +146,7 @@ A `Function` that is fired when the MenuItem receives a click event. It can be called with `menuItem.click(event, focusedWindow, focusedWebContents)`. * `event` [KeyboardEvent](structures/keyboard-event.md) -* `focusedWindow` [BrowserWindow](browser-window.md) +* `focusedWindow` [BaseWindow](browser-window.md) * `focusedWebContents` [WebContents](web-contents.md) #### `menuItem.submenu` @@ -159,7 +160,7 @@ A `string` indicating the type of the item. Can be `normal`, `separator`, `subme #### `menuItem.role` -A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` +A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `showAllTabs`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` #### `menuItem.accelerator` diff --git a/docs/api/menu.md b/docs/api/menu.md index ec5d46100e991..b9a8a7b09e07f 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -72,7 +72,7 @@ The `menu` object has the following instance methods: #### `menu.popup([options])` * `options` Object (optional) - * `window` [BrowserWindow](browser-window.md) (optional) - Default is the focused window. + * `window` [BaseWindow](base-window.md) (optional) - Default is the focused window. * `x` number (optional) - Default is the current mouse cursor position. Must be declared if `y` is declared. * `y` number (optional) - Default is the current mouse cursor position. @@ -80,15 +80,19 @@ The `menu` object has the following instance methods: * `positioningItem` number (optional) _macOS_ - The index of the menu item to be positioned under the mouse cursor at the specified coordinates. Default is -1. + * `sourceType` string (optional) _Windows_ _Linux_ - This should map to the `menuSourceType` + provided by the `context-menu` event. It is not recommended to set this value manually, + only provide values you receive from other APIs or leave it `undefined`. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. * `callback` Function (optional) - Called when menu is closed. -Pops up this menu as a context menu in the [`BrowserWindow`](browser-window.md). +Pops up this menu as a context menu in the [`BaseWindow`](base-window.md). -#### `menu.closePopup([browserWindow])` +#### `menu.closePopup([window])` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window. +* `window` [BaseWindow](base-window.md) (optional) - Default is the focused window. -Closes the context menu in the `browserWindow`. +Closes the context menu in the `window`. #### `menu.append(menuItem)` @@ -147,27 +151,29 @@ can have a submenu. An example of creating the application menu with the simple template API: -```javascript +```js @ts-expect-error=[107] const { app, Menu } = require('electron') const isMac = process.platform === 'darwin' const template = [ // { role: 'appMenu' } - ...(isMac ? [{ - label: app.name, - submenu: [ - { role: 'about' }, - { type: 'separator' }, - { role: 'services' }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideOthers' }, - { role: 'unhide' }, - { type: 'separator' }, - { role: 'quit' } - ] - }] : []), + ...(isMac + ? [{ + label: app.name, + submenu: [ + { role: 'about' }, + { type: 'separator' }, + { role: 'services' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' } + ] + }] + : []), // { role: 'fileMenu' } { label: 'File', @@ -185,23 +191,25 @@ const template = [ { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, - ...(isMac ? [ - { role: 'pasteAndMatchStyle' }, - { role: 'delete' }, - { role: 'selectAll' }, - { type: 'separator' }, - { - label: 'Speech', - submenu: [ - { role: 'startSpeaking' }, - { role: 'stopSpeaking' } + ...(isMac + ? [ + { role: 'pasteAndMatchStyle' }, + { role: 'delete' }, + { role: 'selectAll' }, + { type: 'separator' }, + { + label: 'Speech', + submenu: [ + { role: 'startSpeaking' }, + { role: 'stopSpeaking' } + ] + } ] - } - ] : [ - { role: 'delete' }, - { type: 'separator' }, - { role: 'selectAll' } - ]) + : [ + { role: 'delete' }, + { type: 'separator' }, + { role: 'selectAll' } + ]) ] }, // { role: 'viewMenu' } @@ -225,14 +233,16 @@ const template = [ submenu: [ { role: 'minimize' }, { role: 'zoom' }, - ...(isMac ? [ - { type: 'separator' }, - { role: 'front' }, - { type: 'separator' }, - { role: 'window' } - ] : [ - { role: 'close' } - ]) + ...(isMac + ? [ + { type: 'separator' }, + { role: 'front' }, + { type: 'separator' }, + { role: 'window' } + ] + : [ + { role: 'close' } + ]) ] }, { @@ -261,7 +271,7 @@ menu on behalf of the renderer. Below is an example of showing a menu when the user right clicks the page: -```js +```js @ts-expect-error=[21] // renderer window.addEventListener('contextmenu', (e) => { e.preventDefault() @@ -283,7 +293,7 @@ ipcMain.on('show-context-menu', (event) => { { label: 'Menu Item 2', type: 'checkbox', checked: true } ] const menu = Menu.buildFromTemplate(template) - menu.popup(BrowserWindow.fromWebContents(event.sender)) + menu.popup({ window: BrowserWindow.fromWebContents(event.sender) }) }) ``` @@ -317,7 +327,7 @@ name, no matter what label you set. To change it, modify your app bundle's [About Information Property List Files][AboutInformationPropertyListFiles] for more information. -## Setting Menu for Specific Browser Window (*Linux* *Windows*) +## Setting Menu for Specific Browser Window (_Linux_ _Windows_) The [`setMenu` method][setMenu] of browser windows can set the menu of certain browser windows. @@ -326,16 +336,16 @@ browser windows. You can make use of `before`, `after`, `beforeGroupContaining`, `afterGroupContaining` and `id` to control how the item will be placed when building a menu with `Menu.buildFromTemplate`. -* `before` - Inserts this item before the item with the specified label. If the +* `before` - Inserts this item before the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. Also implies that the menu item in question should be placed in the same “group” as the item. -* `after` - Inserts this item after the item with the specified label. If the +* `after` - Inserts this item after the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. Also implies that the menu item in question should be placed in the same “group” as the item. * `beforeGroupContaining` - Provides a means for a single context menu to declare - the placement of their containing group before the containing group of the item with the specified label. + the placement of their containing group before the containing group of the item with the specified id. * `afterGroupContaining` - Provides a means for a single context menu to declare - the placement of their containing group after the containing group of the item with the specified label. + the placement of their containing group after the containing group of the item with the specified id. By default, items will be inserted in the order they exist in the template unless one of the specified positioning keywords is used. @@ -343,7 +353,7 @@ By default, items will be inserted in the order they exist in the template unles Template: -```javascript +```js [ { id: '1', label: 'one' }, { id: '2', label: 'two' }, @@ -363,7 +373,7 @@ Menu: Template: -```javascript +```js [ { id: '1', label: 'one' }, { type: 'separator' }, @@ -387,7 +397,7 @@ Menu: Template: -```javascript +```js [ { id: '1', label: 'one', after: ['3'] }, { id: '2', label: 'two', before: ['1'] }, diff --git a/docs/api/message-channel-main.md b/docs/api/message-channel-main.md index 670cda868f599..18339848db6ac 100644 --- a/docs/api/message-channel-main.md +++ b/docs/api/message-channel-main.md @@ -17,7 +17,8 @@ Example: ```js // Main process -const { MessageChannelMain } = require('electron') +const { BrowserWindow, MessageChannelMain } = require('electron') +const w = new BrowserWindow() const { port1, port2 } = new MessageChannelMain() w.webContents.postMessage('port', null, [port2]) port1.postMessage({ some: 'message' }) @@ -26,9 +27,9 @@ port1.postMessage({ some: 'message' }) const { ipcRenderer } = require('electron') ipcRenderer.on('port', (e) => { // e.ports is a list of ports sent along with this message - e.ports[0].on('message', (messageEvent) => { + e.ports[0].onmessage = (messageEvent) => { console.log(messageEvent.data) - }) + } }) ``` diff --git a/docs/api/message-port-main.md b/docs/api/message-port-main.md index 5309843916653..371d358f94cb0 100644 --- a/docs/api/message-port-main.md +++ b/docs/api/message-port-main.md @@ -56,3 +56,4 @@ Emitted when the remote end of a MessagePortMain object becomes disconnected. [`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort [Channel Messaging API]: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 0ad349bb081a4..91ee4e68ef042 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -4,36 +4,41 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) -In Electron, for the APIs that take images, you can pass either file paths or -`NativeImage` instances. An empty image will be used when `null` is passed. +The `nativeImage` module provides a unified interface for manipulating +system images. These can be handy if you want to provide multiple scaled +versions of the same icon or take advantage of macOS [template images][template-image]. -For example, when creating a tray or setting a window's icon, you can pass an -image file path as a `string`: +Electron APIs that take image files accept either file paths or +`NativeImage` instances. An empty and transparent image will be used when `null` is passed. -```javascript +For example, when creating a [Tray](../api/tray.md) or setting a [BrowserWindow](../api/browser-window.md)'s +icon, you can either pass an image file path as a string: + +```js title='Main Process' const { BrowserWindow, Tray } = require('electron') -const appIcon = new Tray('/Users/somebody/images/icon.png') +const tray = new Tray('/Users/somebody/images/icon.png') const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' }) -console.log(appIcon, win) ``` -Or read the image from the clipboard, which returns a `NativeImage`: +or generate a `NativeImage` instance from the same file: + +```js title='Main Process' +const { BrowserWindow, nativeImage, Tray } = require('electron') -```javascript -const { clipboard, Tray } = require('electron') -const image = clipboard.readImage() -const appIcon = new Tray(image) -console.log(appIcon) +const trayIcon = nativeImage.createFromPath('/Users/somebody/images/icon.png') +const appIcon = nativeImage.createFromPath('/Users/somebody/images/window.png') +const tray = new Tray(trayIcon) +const win = new BrowserWindow({ icon: appIcon }) ``` ## Supported Formats -Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended -because of its support for transparency and lossless compression. +Currently, `PNG` and `JPEG` image formats are supported across all platforms. +`PNG` is recommended because of its support for transparency and lossless compression. On Windows, you can also load `ICO` icons from file paths. For best visual -quality, it is recommended to include at least the following sizes in the: +quality, we recommend including at least the following sizes: * Small icon * 16x16 (100% DPI scale) @@ -47,22 +52,30 @@ quality, it is recommended to include at least the following sizes in the: * 64x64 (200% DPI scale) * 256x256 -Check the *Size requirements* section in [this article][icons]. +Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference. + +[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling + +:::note -[icons]:https://msdn.microsoft.com/en-us/library/windows/desktop/dn742485(v=vs.85).aspx +EXIF metadata is currently not supported and will not be taken into account during +image encoding and decoding. + +::: ## High Resolution Image -On platforms that have high-DPI support such as Apple Retina displays, you can -append `@2x` after image's base filename to mark it as a high resolution image. +On platforms that support high pixel density displays (such as Apple Retina), +you can append `@2x` after image's base filename to mark it as a 2x scale +high resolution image. For example, if `icon.png` is a normal image that has standard resolution, then -`icon@2x.png` will be treated as a high resolution image that has double DPI -density. +`icon@2x.png` will be treated as a high resolution image that has double +Dots per Inch (DPI) density. If you want to support displays with different DPI densities at the same time, you can put images with different sizes in the same folder and use the filename -without DPI suffixes. For example: +without DPI suffixes within Electron. For example: ```plaintext images/ @@ -71,10 +84,9 @@ images/ └── icon@3x.png ``` -```javascript +```js title='Main Process' const { Tray } = require('electron') -const appIcon = new Tray('/Users/somebody/images/icon.png') -console.log(appIcon) +const appTray = new Tray('/Users/somebody/images/icon.png') ``` The following suffixes for DPI are also supported: @@ -91,27 +103,23 @@ The following suffixes for DPI are also supported: * `@4x` * `@5x` -## Template Image +## Template Image _macOS_ -Template images consist of black and an alpha channel. +On macOS, [template images][template-image] consist of black and an alpha channel. Template images are not intended to be used as standalone images and are usually mixed with other content to create the desired final appearance. -The most common case is to use template images for a menu bar icon, so it can +The most common case is to use template images for a menu bar (Tray) icon, so it can adapt to both light and dark menu bars. -**Note:** Template image is only supported on macOS. - -To mark an image as a template image, its filename should end with the word -`Template`. For example: - -* `xxxTemplate.png` -* `xxxTemplate@2x.png` +To mark an image as a template image, its base filename should end with the word +`Template` (e.g. `xxxTemplate.png`). You can also specify template images at +different DPI densities (e.g. `xxxTemplate@2x.png`). ## Methods The `nativeImage` module has the following methods, all of which return -an instance of the `NativeImage` class: +an instance of the [`NativeImage`](#class-nativeimage) class: ### `nativeImage.createEmpty()` @@ -119,16 +127,18 @@ Returns `NativeImage` Creates an empty `NativeImage` instance. -### `nativeImage.createThumbnailFromPath(path, maxSize)` _macOS_ _Windows_ +### `nativeImage.createThumbnailFromPath(path, size)` _macOS_ _Windows_ * `path` string - path to a file that we intend to construct a thumbnail out of. -* `maxSize` [Size](structures/size.md) - the maximum width and height (positive numbers) the thumbnail returned can be. The Windows implementation will ignore `maxSize.height` and scale the height according to `maxSize.width`. +* `size` [Size](structures/size.md) - the desired width and height (positive numbers) of the thumbnail. Returns `Promise<NativeImage>` - fulfilled with the file's thumbnail preview image, which is a [NativeImage](native-image.md). +Note: The Windows implementation will ignore `size.height` and scale the height according to `size.width`. + ### `nativeImage.createFromPath(path)` -* `path` string +* `path` string - path to a file that we intend to construct an image out of. Returns `NativeImage` @@ -136,8 +146,8 @@ Creates a new `NativeImage` instance from a file located at `path`. This method returns an empty image if the `path` does not exist, cannot be read, or is not a valid image. -```javascript -const nativeImage = require('electron').nativeImage +```js +const { nativeImage } = require('electron') const image = nativeImage.createFromPath('/Users/somebody/images/icon.png') console.log(image) @@ -174,7 +184,7 @@ Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JP Returns `NativeImage` -Creates a new `NativeImage` instance from `dataURL`. +Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string. ### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_ @@ -183,14 +193,14 @@ Creates a new `NativeImage` instance from `dataURL`. Returns `NativeImage` -Creates a new `NativeImage` instance from the NSImage that maps to the -given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/) -for a list of possible values. +Creates a new `NativeImage` instance from the `NSImage` that maps to the +given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388) +documentation for a list of possible values. The `hslShift` is applied to the image with the following rules: * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map - to 0 and 360 on the hue color wheel (red). + to 0 and 360 on the hue color wheel (red). * `hsl_shift[1]` (saturation): A saturation shift for the image, with the following key values: 0 = remove all color. @@ -207,7 +217,9 @@ This means that `[-1, 0, 1]` will make the image completely white and In some cases, the `NSImageName` doesn't match its string representation; one example of this is `NSFolderImageName`, whose string representation would actually be `NSFolder`. Therefore, you'll need to determine the correct string representation for your image before passing it in. This can be done with the following: -`echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test` +```sh +echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test +``` where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc). @@ -245,10 +257,19 @@ data. #### `image.toDataURL([options])` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/41752 + description: "`nativeImage.toDataURL` will preserve PNG colorspace" + breaking-changes-header: behavior-changed-nativeimagetodataurl-will-preserve-png-colorspace +``` +--> + * `options` Object (optional) * `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `string` - The data URL of the image. +Returns `string` - The [Data URL][data-url] of the image. #### `image.getBitmap([options])` @@ -264,7 +285,7 @@ current event loop tick; otherwise the data might be changed or destroyed. #### `image.getNativeHandle()` _macOS_ Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of -the image. On macOS, a pointer to `NSImage` instance would be returned. +the image. On macOS, a pointer to `NSImage` instance is returned. Notice that the returned pointer is a weak pointer to the underlying native image instead of a copy, so you _must_ ensure that the associated @@ -286,11 +307,11 @@ If `scaleFactor` is passed, this will return the size corresponding to the image * `option` boolean -Marks the image as a template image. +Marks the image as a macOS [template image][template-image]. #### `image.isTemplateImage()` -Returns `boolean` - Whether the image is a template image. +Returns `boolean` - Whether the image is a macOS [template image][template-image]. #### `image.crop(rect)` @@ -304,7 +325,7 @@ Returns `NativeImage` - The cropped image. * `width` Integer (optional) - Defaults to the image's width. * `height` Integer (optional) - Defaults to the image's height. * `quality` string (optional) - The desired quality of the resize image. - Possible values are `good`, `better`, or `best`. The default is `best`. + Possible values include `good`, `better`, or `best`. The default is `best`. These values express a desired quality/speed tradeoff. They are translated into an algorithm-specific method that depends on the capabilities (CPU, GPU) of the underlying platform. It is possible for all three methods @@ -319,13 +340,13 @@ will be preserved in the resized image. * `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `Number` - The image's aspect ratio. +Returns `Number` - The image's aspect ratio (width divided by height). If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value. #### `image.getScaleFactors()` -Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage. +Returns `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`. #### `image.addRepresentation(options)` @@ -340,15 +361,17 @@ Returns `Number[]` - An array of all scale factors corresponding to representati encoded PNG or JPEG image. Add an image representation for a specific scale factor. This can be used -to explicitly add different scale factor representations to an image. This +to programmatically add different scale factor representations to an image. This can be called on empty images. -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer - ### Instance Properties #### `nativeImage.isMacTemplateImage` _macOS_ -A `boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template). +A `boolean` property that determines whether the image is considered a [template image][template-image]. Please note that this property only has an effect on macOS. + +[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer +[data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs +[template-image]: https://developer.apple.com/documentation/appkit/nsimage/1520017-template diff --git a/docs/api/native-theme.md b/docs/api/native-theme.md index 3235eba9a78da..e6bdd6c806067 100644 --- a/docs/api/native-theme.md +++ b/docs/api/native-theme.md @@ -72,3 +72,7 @@ or is being instructed to use an inverted color scheme. A `boolean` indicating whether Chromium is in forced colors mode, controlled by system accessibility settings. Currently, Windows high contrast is the only system setting that triggers forced colors mode. + +### `nativeTheme.prefersReducedTransparency` _Readonly_ + +A `boolean` that indicates the whether the user has chosen via system accessibility settings to reduce transparency at the OS level. diff --git a/docs/api/navigation-history.md b/docs/api/navigation-history.md new file mode 100644 index 0000000000000..16d53ce37b116 --- /dev/null +++ b/docs/api/navigation-history.md @@ -0,0 +1,76 @@ +## Class: NavigationHistory + +> Manage a list of navigation entries, representing the user's browsing history within the application. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +Each navigation entry corresponds to a specific page. The indexing system follows a sequential order, where the first available navigation entry is at index 0, representing the earliest visited page, and the latest navigation entry is at index N, representing the most recent page. Maintaining this ordered list of navigation entries enables seamless navigation both backward and forward through the user's browsing history. + +### Instance Methods + +#### `navigationHistory.canGoBack()` + +Returns `boolean` - Whether the browser can go back to previous web page. + +#### `navigationHistory.canGoForward()` + +Returns `boolean` - Whether the browser can go forward to next web page. + +#### `navigationHistory.canGoToOffset(offset)` + +* `offset` Integer + +Returns `boolean` - Whether the web page can go to the specified `offset` from the current entry. + +#### `navigationHistory.clear()` + +Clears the navigation history. + +#### `navigationHistory.getActiveIndex()` + +Returns `Integer` - The index of the current page, from which we would go back/forward or reload. + +#### `navigationHistory.getEntryAtIndex(index)` + +* `index` Integer + +Returns [`NavigationEntry`](structures/navigation-entry.md) - Navigation entry at the given index. + +If index is out of bounds (greater than history length or less than 0), null will be returned. + +#### `navigationHistory.goBack()` + +Makes the browser go back a web page. + +#### `navigationHistory.goForward()` + +Makes the browser go forward a web page. + +#### `navigationHistory.goToIndex(index)` + +* `index` Integer + +Navigates browser to the specified absolute web page index. + +#### `navigationHistory.goToOffset(offset)` + +* `offset` Integer + +Navigates to the specified offset from the current entry. + +#### `navigationHistory.length()` + +Returns `Integer` - History length. + +#### `navigationHistory.removeEntryAtIndex(index)` + +* `index` Integer + +Removes the navigation entry at the given index. Can't remove entry at the "current active index". + +Returns `boolean` - Whether the navigation entry was removed from the webContents history. + +#### `navigationHistory.getAllEntries()` + +Returns [`NavigationEntry[]`](structures/navigation-entry.md) - WebContents complete history. diff --git a/docs/api/net-log.md b/docs/api/net-log.md index fec5f3d14432a..f9b04212c043f 100644 --- a/docs/api/net-log.md +++ b/docs/api/net-log.md @@ -4,8 +4,8 @@ Process: [Main](../glossary.md#main-process) -```javascript -const { netLog } = require('electron') +```js +const { app, netLog } = require('electron') app.whenReady().then(async () => { await netLog.startLogging('/path/to/net-log') diff --git a/docs/api/net.md b/docs/api/net.md index ffbff49d054b4..464c078a54258 100644 --- a/docs/api/net.md +++ b/docs/api/net.md @@ -2,7 +2,7 @@ > Issue HTTP/HTTPS requests using Chromium's native networking library -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process) The `net` module is a client-side API for issuing HTTP(S) requests. It is similar to the [HTTP](https://nodejs.org/api/http.html) and @@ -26,7 +26,7 @@ Node.js. Example usage: -```javascript +```js const { app } = require('electron') app.whenReady().then(() => { const { net } = require('electron') @@ -54,7 +54,7 @@ The `net` module has the following methods: ### `net.request(options)` -* `options` (ClientRequestConstructorOptions | string) - The `ClientRequest` constructor options. +* `options` ([ClientRequestConstructorOptions](client-request.md#new-clientrequestoptions) | string) - The `ClientRequest` constructor options. Returns [`ClientRequest`](./client-request.md) @@ -63,6 +63,63 @@ Creates a [`ClientRequest`](./client-request.md) instance using the provided The `net.request` method would be used to issue both secure and insecure HTTP requests according to the specified protocol scheme in the `options` object. +### `net.fetch(input[, init])` + +* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request) +* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional) + +Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). + +Sends a request, similarly to how `fetch()` works in the renderer, using +Chrome's network stack. This differs from Node's `fetch()`, which uses +Node.js's HTTP stack. + +Example: + +```js +async function example () { + const response = await net.fetch('https://my.app') + if (response.ok) { + const body = await response.json() + // ... use the result. + } +} +``` + +This method will issue requests from the [default session](session.md#sessiondefaultsession). +To send a `fetch` request from another session, use [ses.fetch()](session.md#sesfetchinput-init). + +See the MDN documentation for +[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more +details. + +Limitations: + +* `net.fetch()` does not support the `data:` or `blob:` schemes. +* The value of the `integrity` option is ignored. +* The `.type` and `.url` values of the returned `Response` object are + incorrect. + +By default, requests made with `net.fetch` can be made to [custom protocols](protocol.md) +as well as `file:`, and will trigger [webRequest](web-request.md) handlers if present. +When the non-standard `bypassCustomProtocolHandlers` option is set in RequestInit, +custom protocol handlers will not be called for this request. This allows forwarding an +intercepted request to the built-in handler. [webRequest](web-request.md) +handlers will still be triggered when bypassing custom protocols. + +```js +protocol.handle('https', (req) => { + if (req.url === 'https://my-app.com') { + return new Response('<body>my app</body>') + } else { + return net.fetch(req, { bypassCustomProtocolHandlers: true }) + } +}) +``` + +Note: in the [utility process](../glossary.md#utility-process) custom protocols +are not supported. + ### `net.isOnline()` Returns `boolean` - Whether there is currently internet connection. @@ -73,6 +130,44 @@ won't be able to connect to remote sites. However, a return value of whether a particular connection attempt to a particular remote site will be successful. +### `net.resolveHost(host, [options])` + +* `host` string - Hostname to resolve. +* `options` Object (optional) + * `queryType` string (optional) - Requested DNS query type. If unspecified, + resolver will pick A or AAAA (or both) based on IPv4/IPv6 settings: + * `A` - Fetch only A records + * `AAAA` - Fetch only AAAA records. + * `source` string (optional) - The source to use for resolved addresses. + Default allows the resolver to pick an appropriate source. Only affects use + of big external sources (e.g. calling the system for resolution or using + DNS). Even if a source is specified, results can still come from cache, + resolving "localhost" or IP literals, etc. One of the following values: + * `any` (default) - Resolver will pick an appropriate source. Results could + come from DNS, MulticastDNS, HOSTS file, etc + * `system` - Results will only be retrieved from the system or OS, e.g. via + the `getaddrinfo()` system call + * `dns` - Results will only come from DNS queries + * `mdns` - Results will only come from Multicast DNS queries + * `localOnly` - No external sources will be used. Results will only come + from fast local sources that are available no matter the source setting, + e.g. cache, hosts file, IP literal resolution, etc. + * `cacheUsage` string (optional) - Indicates what DNS cache entries, if any, + can be used to provide a response. One of the following values: + * `allowed` (default) - Results may come from the host cache if non-stale + * `staleAllowed` - Results may come from the host cache even if stale (by + expiration or network changes) + * `disallowed` - Results will not come from the host cache. + * `secureDnsPolicy` string (optional) - Controls the resolver's Secure DNS + behavior for this request. One of the following values: + * `allow` (default) + * `disable` + +Returns [`Promise<ResolvedHost>`](structures/resolved-host.md) - Resolves with the resolved IP addresses for the `host`. + +This method will resolve hosts from the [default session](session.md#sessiondefaultsession). +To resolve a host from another session, use [ses.resolveHost()](session.md#sesresolvehosthost-options). + ## Properties ### `net.online` _Readonly_ diff --git a/docs/api/notification.md b/docs/api/notification.md index 9731efca08813..efaa93b39e217 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -4,9 +4,12 @@ Process: [Main](../glossary.md#main-process) -## Using in the renderer process +:::info Renderer process notifications -If you want to show Notifications from a renderer process you should use the [HTML5 Notification API](../tutorial/notifications.md) +If you want to show notifications from a renderer process you should use the +[web Notifications API](../tutorial/notifications.md) + +::: ## Class: Notification @@ -29,11 +32,11 @@ Returns `boolean` - Whether or not desktop notifications are supported on the cu ### `new Notification([options])` * `options` Object (optional) - * `title` string (optional) - A title for the notification, which will be shown at the top of the notification window when it is shown. + * `title` string (optional) - A title for the notification, which will be displayed at the top of the notification window when it is shown. * `subtitle` string (optional) _macOS_ - A subtitle for the notification, which will be displayed below the title. * `body` string (optional) - The body text of the notification, which will be displayed below the title or subtitle. - * `silent` boolean (optional) - Whether or not to emit an OS notification noise when showing the notification. - * `icon` (string | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. + * `silent` boolean (optional) - Whether or not to suppress the OS notification noise when showing the notification. + * `icon` (string | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. If a string is passed, it must be a valid path to a local icon file. * `hasReply` boolean (optional) _macOS_ - Whether or not to add an inline reply option to the notification. * `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'. * `replyPlaceholder` string (optional) _macOS_ - The placeholder to write in the inline reply input field. @@ -47,8 +50,11 @@ Returns `boolean` - Whether or not desktop notifications are supported on the cu Objects created with `new Notification` emit the following events: -**Note:** Some events are only available on specific operating systems and are -labeled as such. +:::info + +Some events are only available on specific operating systems and are labeled as such. + +::: #### Event: 'show' @@ -56,7 +62,7 @@ Returns: * `event` Event -Emitted when the notification is shown to the user, note this could be fired +Emitted when the notification is shown to the user. Note that this event can be fired multiple times as a notification can be shown multiple times through the `show()` method. @@ -79,6 +85,8 @@ Emitted when the notification is closed by manual intervention from the user. This event is not guaranteed to be emitted in all cases where the notification is closed. +On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again. + #### Event: 'reply' _macOS_ Returns: @@ -106,14 +114,13 @@ Emitted when an error is encountered while creating and showing the native notif ### Instance Methods -Objects created with `new Notification` have the following instance methods: +Objects created with the `new Notification()` constructor have the following instance methods: #### `notification.show()` -Immediately shows the notification to the user, please note this means unlike the -HTML5 Notification implementation, instantiating a `new Notification` does -not immediately show it to the user, you need to call this method before the OS -will display it. +Immediately shows the notification to the user. Unlike the web notification API, +instantiating a `new Notification()` does not immediately show it to the user. Instead, you need to +call this method before the OS will display it. If the notification has been shown before, this method will dismiss the previously shown notification and create a new one with identical properties. @@ -122,6 +129,8 @@ shown notification and create a new one with identical properties. Dismisses the notification. +On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center. + ### Instance Properties #### `notification.title` @@ -160,7 +169,7 @@ A `boolean` property representing whether the notification has a reply action. A `string` property representing the urgency level of the notification. Can be 'normal', 'critical', or 'low'. -Default is 'low' - see [NotifyUrgency](https://developer.gnome.org/notification-spec/#urgency-levels) for more information. +Default is 'low' - see [NotifyUrgency](https://developer-old.gnome.org/notification-spec/#urgency-levels) for more information. #### `notification.timeoutType` _Linux_ _Windows_ diff --git a/docs/api/parent-port.md b/docs/api/parent-port.md new file mode 100644 index 0000000000000..4b181b474b933 --- /dev/null +++ b/docs/api/parent-port.md @@ -0,0 +1,48 @@ +# parentPort + +> Interface for communication with parent process. + +Process: [Utility](../glossary.md#utility-process) + +`parentPort` is an [EventEmitter][event-emitter]. +_This object is not exported from the `'electron'` module. It is only available as a property of the process object in the Electron API._ + +```js +// Main process +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.postMessage({ message: 'hello' }) +child.on('message', (data) => { + console.log(data) // hello world! +}) + +// Child process +process.parentPort.on('message', (e) => { + process.parentPort.postMessage(`${e.data} world!`) +}) +``` + +## Events + +The `parentPort` object emits the following events: + +### Event: 'message' + +Returns: + +* `messageEvent` Object + * `data` any + * `ports` MessagePortMain[] + +Emitted when the process receives a message. Messages received on +this port will be queued up until a handler is registered for this +event. + +## Methods + +### `parentPort.postMessage(message)` + +* `message` any + +Sends a message from the process to its parent. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/power-monitor.md b/docs/api/power-monitor.md index 1292ea1f05fce..0801f81a0717e 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -24,6 +24,32 @@ Emitted when the system changes to AC power. Emitted when system changes to battery power. +### Event: 'thermal-state-change' _macOS_ + +* `state` string - The system's new thermal state. Can be `unknown`, `nominal`, `fair`, `serious`, `critical`. + +Emitted when the thermal state of the system changes. Notification of a change +in the thermal status of the system, such as entering a critical temperature +range. Depending on the severity, the system might take steps to reduce said +temperature, for example, throttling the CPU or switching on the fans if +available. + +Apps may react to the new state by reducing expensive computing tasks (e.g. +video encoding), or notifying the user. The same state might be received +repeatedly. + +See https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/RespondToThermalStateChanges.html + +### Event: 'speed-limit-change' _macOS_ _Windows_ + +Returns: + +* `limit` number - The operating system's advertised speed limit for CPUs, in percent. + +Notification of a change in the operating system's advertised speed limit for +CPUs, in percent. Values below 100 indicate that the system is impairing +processing power due to thermal management. + ### Event: 'shutdown' _Linux_ _macOS_ Emitted when the system is about to reboot or shut down. If the event handler @@ -55,7 +81,7 @@ The `powerMonitor` module has the following methods: * `idleThreshold` Integer -Returns `string` - The system's current state. Can be `active`, `idle`, `locked` or `unknown`. +Returns `string` - The system's current idle state. Can be `active`, `idle`, `locked` or `unknown`. Calculate the system idle state. `idleThreshold` is the amount of time (in seconds) before considered idle. `locked` is available on supported systems only. @@ -66,6 +92,10 @@ Returns `Integer` - Idle time in seconds Calculate system idle time in seconds. +### `powerMonitor.getCurrentThermalState()` _macOS_ + +Returns `string` - The system's current thermal state. Can be `unknown`, `nominal`, `fair`, `serious`, or `critical`. + ### `powerMonitor.isOnBatteryPower()` Returns `boolean` - Whether the system is on battery power. diff --git a/docs/api/power-save-blocker.md b/docs/api/power-save-blocker.md index 257fc76f3da54..ee57287258df0 100644 --- a/docs/api/power-save-blocker.md +++ b/docs/api/power-save-blocker.md @@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process) For example: -```javascript +```js const { powerSaveBlocker } = require('electron') const id = powerSaveBlocker.start('prevent-display-sleep') @@ -49,6 +49,8 @@ is used. Stops the specified power save blocker. +Returns `boolean` - Whether the specified `powerSaveBlocker` has been stopped. + ### `powerSaveBlocker.isStarted(id)` * `id` Integer - The power save blocker id returned by `powerSaveBlocker.start`. diff --git a/docs/api/process.md b/docs/api/process.md index 4573899912997..bcf339233f865 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -21,7 +21,6 @@ In sandboxed renderers the `process` object contains only a subset of the APIs: * `getSystemMemoryInfo()` * `getSystemVersion()` * `getCPUUsage()` -* `getIOCounters()` * `uptime()` * `argv` * `execPath` @@ -49,8 +48,11 @@ beginning to load the web page or the main script. ### `process.defaultApp` _Readonly_ -A `boolean`. When app is started by being passed as parameter to the default app, this +A `boolean`. When the app is started by being passed as parameter to the default Electron executable, this property is `true` in the main process, otherwise it is `undefined`. +For example when running the app with `electron .`, it is `true`, +even if the app is packaged ([`isPackaged`](app.md#appispackaged-readonly)) is `true`. +This can be useful to determine how many arguments will need to be sliced off from `process.argv`. ### `process.isMainFrame` _Readonly_ @@ -113,6 +115,7 @@ A `string` representing the current process's type, can be: * `browser` - The main process * `renderer` - A renderer process * `worker` - In a web worker +* `utility` - In a node process launched as a service ### `process.versions.chrome` _Readonly_ @@ -134,6 +137,11 @@ Each frame has its own JavaScript context. When contextIsolation is enabled, the world also has a separate JavaScript context. This property is only available in the renderer process. +### `process.parentPort` + +A [`Electron.ParentPort`](parent-port.md) property if this is a [`UtilityProcess`](utility-process.md) +(or `null` otherwise) allowing communication with the parent process. + ## Methods The `process` object has the following methods: @@ -153,10 +161,6 @@ The time is represented as number of milliseconds since epoch. It returns null i Returns [`CPUUsage`](structures/cpu-usage.md) -### `process.getIOCounters()` _Windows_ _Linux_ - -Returns [`IOCounters`](structures/io-counters.md) - ### `process.getHeapStatistics()` Returns `Object`: diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 7a2b334016191..1af780827c80b 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -7,14 +7,15 @@ Process: [Main](../glossary.md#main-process) An example of implementing a protocol that has the same effect as the `file://` protocol: -```javascript -const { app, protocol } = require('electron') -const path = require('path') +```js +const { app, protocol, net } = require('electron') +const path = require('node:path') +const url = require('node:url') app.whenReady().then(() => { - protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + protocol.handle('atom', (request) => { + const filePath = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString()) }) }) ``` @@ -34,20 +35,21 @@ a different session and your custom protocol will not work if you just use To have your custom protocol work in combination with a custom session, you need to register it to that session explicitly. -```javascript -const { session, app, protocol } = require('electron') -const path = require('path') +```js +const { app, BrowserWindow, net, protocol, session } = require('electron') +const path = require('node:path') +const url = require('url') app.whenReady().then(() => { const partition = 'persist:example' const ses = session.fromPartition(partition) - ses.protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + ses.protocol.handle('atom', (request) => { + const filePath = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.resolve(__dirname, filePath)).toString()) }) - mainWindow = new BrowserWindow({ webPreferences: { partition } }) + const mainWindow = new BrowserWindow({ webPreferences: { partition } }) }) ``` @@ -63,22 +65,22 @@ The `protocol` module has the following methods: module gets emitted and can be called only once. Registers the `scheme` as standard, secure, bypasses content security policy for -resources, allows registering ServiceWorker, supports fetch API, and streaming -video/audio. Specify a privilege with the value of `true` to enable the capability. +resources, allows registering ServiceWorker, supports fetch API, streaming +video/audio, and V8 code cache. Specify a privilege with the value of `true` to +enable the capability. An example of registering a privileged scheme, that bypasses Content Security Policy: -```javascript +```js const { protocol } = require('electron') protocol.registerSchemesAsPrivileged([ { scheme: 'foo', privileges: { bypassCSP: true } } ]) ``` -A standard scheme adheres to what RFC 3986 calls [generic URI -syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and -`https` are standard schemes, while `file` is not. +A standard scheme adheres to what RFC 3986 calls [generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3). +For example `http` and `https` are standard schemes, while `file` is not. Registering a scheme as standard allows relative and absolute resources to be resolved correctly when served. Otherwise the scheme will behave like the @@ -108,7 +110,93 @@ The `<video>` and `<audio>` HTML elements expect protocols to buffer their responses by default. The `stream` flag configures those elements to correctly expect streaming responses. -### `protocol.registerFileProtocol(scheme, handler)` +### `protocol.handle(scheme, handler)` + +* `scheme` string - scheme to handle, for example `https` or `my-app`. This is + the bit before the `:` in a URL. +* `handler` Function\<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise\<GlobalResponse\>\> + * `request` [GlobalRequest](https://nodejs.org/api/globals.html#request) + +Register a protocol handler for `scheme`. Requests made to URLs with this +scheme will delegate to this handler to determine what response should be sent. + +Either a `Response` or a `Promise<Response>` can be returned. + +Example: + +```js +const { app, net, protocol } = require('electron') +const path = require('node:path') +const { pathToFileURL } = require('url') + +protocol.registerSchemesAsPrivileged([ + { + scheme: 'app', + privileges: { + standard: true, + secure: true, + supportFetchAPI: true + } + } +]) + +app.whenReady().then(() => { + protocol.handle('app', (req) => { + const { host, pathname } = new URL(req.url) + if (host === 'bundle') { + if (pathname === '/') { + return new Response('<h1>hello, world</h1>', { + headers: { 'content-type': 'text/html' } + }) + } + // NB, this checks for paths that escape the bundle, e.g. + // app://bundle/../../secret_file.txt + const pathToServe = path.resolve(__dirname, pathname) + const relativePath = path.relative(__dirname, pathToServe) + const isSafe = relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath) + if (!isSafe) { + return new Response('bad', { + status: 400, + headers: { 'content-type': 'text/html' } + }) + } + + return net.fetch(pathToFileURL(pathToServe).toString()) + } else if (host === 'api') { + return net.fetch('https://api.my-server.com/' + pathname, { + method: req.method, + headers: req.headers, + body: req.body + }) + } + }) +}) +``` + +See the MDN docs for [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) for more details. + +### `protocol.unhandle(scheme)` + +* `scheme` string - scheme for which to remove the handler. + +Removes a protocol handler registered with `protocol.handle`. + +### `protocol.isProtocolHandled(scheme)` + +* `scheme` string + +Returns `boolean` - Whether `scheme` is already handled. + +### `protocol.registerFileProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -129,7 +217,16 @@ path or an object that has a `path` property, e.g. `callback(filePath)` or By default the `scheme` is treated like `http:`, which is parsed differently from protocols that follow the "generic URI syntax" like `file:`. -### `protocol.registerBufferProtocol(scheme, handler)` +### `protocol.registerBufferProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -147,13 +244,22 @@ property. Example: -```javascript +```js protocol.registerBufferProtocol('atom', (request, callback) => { callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) }) ``` -### `protocol.registerStringProtocol(scheme, handler)` +### `protocol.registerStringProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -169,13 +275,22 @@ The usage is the same with `registerFileProtocol`, except that the `callback` should be called with either a `string` or an object that has the `data` property. -### `protocol.registerHttpProtocol(scheme, handler)` +### `protocol.registerHttpProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` ProtocolResponse + * `response` [ProtocolResponse](structures/protocol-response.md) Returns `boolean` - Whether the protocol was successfully registered @@ -184,7 +299,16 @@ Registers a protocol of `scheme` that will send an HTTP request as a response. The usage is the same with `registerFileProtocol`, except that the `callback` should be called with an object that has the `url` property. -### `protocol.registerStreamProtocol(scheme, handler)` +### `protocol.registerStreamProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -202,7 +326,7 @@ has the `data` property. Example: -```javascript +```js const { protocol } = require('electron') const { PassThrough } = require('stream') @@ -227,13 +351,22 @@ protocol.registerStreamProtocol('atom', (request, callback) => { It is possible to pass any object that implements the readable stream API (emits `data`/`end`/`error` events). For example, here's how a file could be returned: -```javascript +```js protocol.registerStreamProtocol('atom', (request, callback) => { callback(fs.createReadStream('index.html')) }) ``` -### `protocol.unregisterProtocol(scheme)` +### `protocol.unregisterProtocol(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string @@ -241,13 +374,31 @@ Returns `boolean` - Whether the protocol was successfully unregistered Unregisters the custom protocol of `scheme`. -### `protocol.isProtocolRegistered(scheme)` +### `protocol.isProtocolRegistered(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string Returns `boolean` - Whether `scheme` is already registered. -### `protocol.interceptFileProtocol(scheme, handler)` +### `protocol.interceptFileProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -260,7 +411,16 @@ Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a file as a response. -### `protocol.interceptStringProtocol(scheme, handler)` +### `protocol.interceptStringProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -273,7 +433,16 @@ Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a `string` as a response. -### `protocol.interceptBufferProtocol(scheme, handler)` +### `protocol.interceptBufferProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -286,7 +455,16 @@ Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a `Buffer` as a response. -### `protocol.interceptHttpProtocol(scheme, handler)` +### `protocol.interceptHttpProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -299,7 +477,16 @@ Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a new HTTP request as a response. -### `protocol.interceptStreamProtocol(scheme, handler)` +### `protocol.interceptStreamProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string * `handler` Function @@ -312,7 +499,16 @@ Returns `boolean` - Whether the protocol was successfully intercepted Same as `protocol.registerStreamProtocol`, except that it replaces an existing protocol handler. -### `protocol.uninterceptProtocol(scheme)` +### `protocol.uninterceptProtocol(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string @@ -320,7 +516,16 @@ Returns `boolean` - Whether the protocol was successfully unintercepted Remove the interceptor installed for `scheme` and restore its original handler. -### `protocol.isProtocolIntercepted(scheme)` +### `protocol.isProtocolIntercepted(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> * `scheme` string diff --git a/docs/api/push-notifications.md b/docs/api/push-notifications.md index cad396bc03d56..01c0e830e5b87 100644 --- a/docs/api/push-notifications.md +++ b/docs/api/push-notifications.md @@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process) For example, when registering for push notifications via Apple push notification services (APNS): -```javascript +```js const { pushNotifications, Notification } = require('electron') pushNotifications.registerForAPNSNotifications().then((token) => { @@ -26,7 +26,8 @@ The `pushNotification` module emits the following events: Returns: -* `userInfo` Record<String, any> +* `event` Event +* `userInfo` Record\<String, any\> Emitted when the app receives a remote notification while running. See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc @@ -39,7 +40,7 @@ The `pushNotification` module has the following methods: Returns `Promise<string>` -Registers the app with Apple Push Notification service (APNS) to receive [Badge, Sound, and Alert](https://developer.apple.com/documentation/appkit/sremotenotificationtype?language=objc) notifications. If registration is successful, the promise will be resolved with the APNS device token. Otherwise, the promise will be rejected with an error message. +Registers the app with Apple Push Notification service (APNS) to receive [Badge, Sound, and Alert](https://developer.apple.com/documentation/appkit/nsremotenotificationtype?language=objc) notifications. If registration is successful, the promise will be resolved with the APNS device token. Otherwise, the promise will be rejected with an error message. See: https://developer.apple.com/documentation/appkit/nsapplication/1428476-registerforremotenotificationtyp?language=objc ### `pushNotifications.unregisterForAPNSNotifications()` _macOS_ diff --git a/docs/api/safe-storage.md b/docs/api/safe-storage.md index 471351c9c1cd3..d9c7dc3feab47 100644 --- a/docs/api/safe-storage.md +++ b/docs/api/safe-storage.md @@ -4,7 +4,19 @@ Process: [Main](../glossary.md#main-process) -This module protects data stored on disk from being accessed by other applications or users with full disk access. +This module adds extra protection to data being stored on disk by using OS-provided cryptography systems. Current +security semantics for each platform are outlined below. + +* **macOS**: Encryption keys are stored for your app in [Keychain Access](https://support.apple.com/en-ca/guide/keychain-access/kyca1083/mac) in a way that prevents +other applications from loading them without user override. Therefore, content is protected from other users and other apps running in the same userspace. +* **Windows**: Encryption keys are generated via [DPAPI](https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata). +As per the Windows documentation: "Typically, only a user with the same logon credential as the user who encrypted the data can typically +decrypt the data". Therefore, content is protected from other users on the same machine, but not from other apps running in the +same userspace. +* **Linux**: Encryption keys are generated and stored in a secret store that varies depending on your window manager and system setup. Options currently supported are `kwallet`, `kwallet5`, `kwallet6` and `gnome-libsecret`, but more may be available in future versions of Electron. As such, the +security semantics of content protected via the `safeStorage` API vary between window managers and secret stores. + * Note that not all Linux setups have an available secret store. If no secret store is available, items stored in using the `safeStorage` API will be unprotected +as they are encrypted via hardcoded plaintext password. You can detect when this happens when `safeStorage.getSelectedStorageBackend()` returns `basic_text`. Note that on Mac, access to the system Keychain is required and these calls can block the current thread to collect user input. @@ -38,3 +50,28 @@ Returns `string` - the decrypted string. Decrypts the encrypted buffer obtained with `safeStorage.encryptString` back into a string. This function will throw an error if decryption fails. + +### `safeStorage.setUsePlainTextEncryption(usePlainText)` + +* `usePlainText` boolean + +This function on Linux will force the module to use an in memory password for creating +symmetric key that is used for encrypt/decrypt functions when a valid OS password +manager cannot be determined for the current active desktop environment. This function +is a no-op on Windows and MacOS. + +### `safeStorage.getSelectedStorageBackend()` _Linux_ + +Returns `string` - User friendly name of the password manager selected on Linux. + +This function will return one of the following values: + +* `basic_text` - When the desktop environment is not recognised or if the following +command line flag is provided `--password-store="basic"`. +* `gnome_libsecret` - When the desktop environment is `X-Cinnamon`, `Deepin`, `GNOME`, `Pantheon`, `XFCE`, `UKUI`, `unity` or if the following command line flag is provided `--password-store="gnome-libsecret"`. +* `kwallet` - When the desktop session is `kde4` or if the following command line flag +is provided `--password-store="kwallet"`. +* `kwallet5` - When the desktop session is `kde5` or if the following command line flag +is provided `--password-store="kwallet5"`. +* `kwallet6` - When the desktop session is `kde6`. +* `unknown` - When the function is called before app has emitted the `ready` event. diff --git a/docs/api/screen.md b/docs/api/screen.md index a576a5902c523..4f68a2018b062 100644 --- a/docs/api/screen.md +++ b/docs/api/screen.md @@ -14,20 +14,29 @@ property, so writing `let { screen } = require('electron')` will not work. An example of creating a window that fills the whole screen: -```javascript fiddle='docs/fiddles/screen/fit-screen' -const { app, BrowserWindow, screen } = require('electron') +```fiddle docs/fiddles/screen/fit-screen +// Retrieve information about screen size, displays, cursor position, etc. +// +// For more info, see: +// https://www.electronjs.org/docs/latest/api/screen + +const { app, BrowserWindow, screen } = require('electron/main') + +let mainWindow = null -let win app.whenReady().then(() => { - const { width, height } = screen.getPrimaryDisplay().workAreaSize - win = new BrowserWindow({ width, height }) - win.loadURL('https://github.com') + // Create a window that fills the screen's available work area. + const primaryDisplay = screen.getPrimaryDisplay() + const { width, height } = primaryDisplay.workAreaSize + + mainWindow = new BrowserWindow({ width, height }) + mainWindow.loadURL('https://electronjs.org') }) ``` Another example of creating a window in the external display: -```javascript +```js const { app, BrowserWindow, screen } = require('electron') let win diff --git a/docs/api/service-worker-main.md b/docs/api/service-worker-main.md new file mode 100644 index 0000000000000..a1c3889661cae --- /dev/null +++ b/docs/api/service-worker-main.md @@ -0,0 +1,34 @@ +# ServiceWorkerMain + +> An instance of a Service Worker representing a version of a script for a given scope. + +Process: [Main](../glossary.md#main-process) + +## Class: ServiceWorkerMain + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +### Instance Methods + +#### `serviceWorker.isDestroyed()` _Experimental_ + +Returns `boolean` - Whether the service worker has been destroyed. + +#### `serviceWorker.startTask()` _Experimental_ + +Returns `Object`: + +- `end` Function - Method to call when the task has ended. If never called, the service won't terminate while otherwise idle. + +Initiate a task to keep the service worker alive until ended. + +### Instance Properties + +#### `serviceWorker.scope` _Readonly_ _Experimental_ + +A `string` representing the scope URL of the service worker. + +#### `serviceWorker.versionId` _Readonly_ _Experimental_ + +A `number` representing the ID of the specific version of the service worker script in its scope. diff --git a/docs/api/service-workers.md b/docs/api/service-workers.md index ec9f33d3e18ac..0d3796a93687e 100644 --- a/docs/api/service-workers.md +++ b/docs/api/service-workers.md @@ -10,7 +10,7 @@ a `Session`. For example: -```javascript +```js const { session } = require('electron') // Get all service workers. @@ -56,6 +56,17 @@ Returns: Emitted when a service worker has been registered. Can occur after a call to [`navigator.serviceWorker.register('/sw.js')`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register) successfully resolves or when a Chrome extension is loaded. +#### Event: 'running-status-changed' _Experimental_ + +Returns: + +* `details` Event\<\> + * `versionId` number - ID of the updated service worker version + * `runningStatus` string - Running status. + Possible values include `starting`, `running`, `stopping`, or `stopped`. + +Emitted when a service worker's running status has changed. + ### Instance Methods The following methods are available on instances of `ServiceWorkers`: @@ -64,10 +75,56 @@ The following methods are available on instances of `ServiceWorkers`: Returns `Record<number, ServiceWorkerInfo>` - A [ServiceWorkerInfo](structures/service-worker-info.md) object where the keys are the service worker version ID and the values are the information about that service worker. -#### `serviceWorkers.getFromVersionID(versionId)` +#### `serviceWorkers.getInfoFromVersionID(versionId)` -* `versionId` number +* `versionId` number - ID of the service worker version Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker If the service worker does not exist or is not running this method will throw an exception. + +#### `serviceWorkers.getFromVersionID(versionId)` _Deprecated_ + +* `versionId` number - ID of the service worker version + +Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker + +If the service worker does not exist or is not running this method will throw an exception. + +**Deprecated:** Use the new `serviceWorkers.getInfoFromVersionID` API. + +#### `serviceWorkers.getWorkerFromVersionID(versionId)` _Experimental_ + +* `versionId` number - ID of the service worker version + +Returns [`ServiceWorkerMain | undefined`](service-worker-main.md) - Instance of the service worker associated with the given version ID. If there's no associated version, or its running status has changed to 'stopped', this will return `undefined`. + +#### `serviceWorkers.startWorkerForScope(scope)` _Experimental_ + +* `scope` string - The scope of the service worker to start. + +Returns `Promise<ServiceWorkerMain>` - Resolves with the service worker when it's started. + +Starts the service worker or does nothing if already running. + +<!-- TODO(samuelmaddock): extend example to send IPC after starting worker --> + +```js +const { app, session } = require('electron') +const { serviceWorkers } = session.defaultSession + +// Collect service workers scopes +const workerScopes = Object.values(serviceWorkers.getAllRunning()).map((info) => info.scope) + +app.on('browser-window-created', async (event, window) => { + for (const scope of workerScopes) { + try { + // Ensure worker is started + await serviceWorkers.startWorkerForScope(scope) + } catch (error) { + console.error(`Failed to start service worker for ${scope}`) + console.error(error) + } + } +}) +``` diff --git a/docs/api/session.md b/docs/api/session.md index f405d133ba523..cc6a22e59b06e 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -9,11 +9,11 @@ The `session` module can be used to create new `Session` objects. You can also access the `session` of existing pages by using the `session` property of [`WebContents`](web-contents.md), or from the `session` module. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') const ses = win.webContents.session console.log(ses.getUserAgent()) @@ -27,7 +27,8 @@ The `session` module has the following methods: * `partition` string * `options` Object (optional) - * `cache` boolean - Whether to enable cache. + * `cache` boolean - Whether to enable cache. Default is `true` unless the + [`--disable-http-cache` switch](command-line-switches.md#--disable-http-cache) is used. Returns `Session` - A session instance from `partition` string. When there is an existing `Session` with the same `partition`, it will be returned; otherwise a new @@ -42,6 +43,23 @@ To create a `Session` with `options`, you have to ensure the `Session` with the `partition` has never been used before. There is no way to change the `options` of an existing `Session` object. +### `session.fromPath(path[, options])` + +* `path` string +* `options` Object (optional) + * `cache` boolean - Whether to enable cache. Default is `true` unless the + [`--disable-http-cache` switch](command-line-switches.md#--disable-http-cache) is used. + +Returns `Session` - A session instance from the absolute path as specified by the `path` +string. When there is an existing `Session` with the same absolute path, it +will be returned; otherwise a new `Session` instance will be created with `options`. The +call will throw an error if the path is not an absolute path. Additionally, an error will +be thrown if an empty string is provided. + +To create a `Session` with `options`, you have to ensure the `Session` with the +`path` has never been used before. There is no way to change the `options` +of an existing `Session` object. + ## Properties The `session` module has the following properties: @@ -59,7 +77,7 @@ _This class is not exported from the `'electron'` module. It is only available a You can create a `Session` object in the `session` module: -```javascript +```js const { session } = require('electron') const ses = session.fromPartition('persist:name') console.log(ses.getUserAgent()) @@ -82,12 +100,12 @@ Emitted when Electron is about to download `item` in `webContents`. Calling `event.preventDefault()` will cancel the download and `item` will not be available from next tick of the process. -```javascript +```js @ts-expect-error=[4] const { session } = require('electron') session.defaultSession.on('will-download', (event, item, webContents) => { event.preventDefault() require('got')(item.getURL()).then((response) => { - require('fs').writeFileSync('/somewhere', response.body) + require('node:fs').writeFileSync('/somewhere', response.body) }) }) ``` @@ -127,6 +145,71 @@ Returns: Emitted after an extension is loaded and all necessary browser state is initialized to support the start of the extension's background page. +#### Event: 'file-system-access-restricted' + +Returns: + +* `event` Event +* `details` Object + * `origin` string - The origin that initiated access to the blocked path. + * `isDirectory` boolean - Whether or not the path is a directory. + * `path` string - The blocked path attempting to be accessed. +* `callback` Function + * `action` string - The action to take as a result of the restricted path access attempt. + * `allow` - This will allow `path` to be accessed despite restricted status. + * `deny` - This will block the access request and trigger an [`AbortError`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort). + * `tryAgain` - This will open a new file picker and allow the user to choose another path. + +```js +const { app, dialog, BrowserWindow, session } = require('electron') + +async function createWindow () { + const mainWindow = new BrowserWindow() + + await mainWindow.loadURL('https://buzzfeed.com') + + session.defaultSession.on('file-system-access-restricted', async (e, details, callback) => { + const { origin, path } = details + const { response } = await dialog.showMessageBox({ + message: `Are you sure you want ${origin} to open restricted path ${path}?`, + title: 'File System Access Restricted', + buttons: ['Choose a different folder', 'Allow', 'Cancel'], + cancelId: 2 + }) + + if (response === 0) { + callback('tryAgain') + } else if (response === 1) { + callback('allow') + } else { + callback('deny') + } + }) + + mainWindow.webContents.executeJavaScript(` + window.showDirectoryPicker({ + id: 'electron-demo', + mode: 'readwrite', + startIn: 'downloads', + }).catch(e => { + console.log(e) + })`, true + ) +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) +``` + #### Event: 'preconnect' Returns: @@ -187,7 +270,8 @@ Returns: * `event` Event * `details` Object * `deviceList` [HIDDevice[]](structures/hid-device.md) - * `frame` [WebFrameMain](web-frame-main.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. * `callback` Function * `deviceId` string | null (optional) @@ -195,10 +279,10 @@ Emitted when a HID device needs to be selected when a call to `navigator.hid.requestDevice` is made. `callback` should be called with `deviceId` to be selected; passing no arguments to `callback` will cancel the request. Additionally, permissioning on `navigator.hid` can -be further managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler) -and [ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler). +be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler) +and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler). -```javascript +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} const { app, BrowserWindow } = require('electron') let win = null @@ -237,9 +321,9 @@ app.whenReady().then(() => { win.webContents.session.on('select-hid-device', (event, details, callback) => { event.preventDefault() const selectedDevice = details.deviceList.find((device) => { - return device.vendorId === '9025' && device.productId === '67' + return device.vendorId === 9025 && device.productId === 67 }) - callback(selectedPort?.deviceId) + callback(selectedDevice?.deviceId) }) }) ``` @@ -250,8 +334,9 @@ Returns: * `event` Event * `details` Object - * `device` [HIDDevice[]](structures/hid-device.md) - * `frame` [WebFrameMain](web-frame-main.md) + * `device` [HIDDevice](structures/hid-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. Emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired if a new device becomes available before @@ -265,8 +350,9 @@ Returns: * `event` Event * `details` Object - * `device` [HIDDevice[]](structures/hid-device.md) - * `frame` [WebFrameMain](web-frame-main.md) + * `device` [HIDDevice](structures/hid-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. Emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired if a device has been removed before the callback @@ -280,7 +366,7 @@ Returns: * `event` Event * `details` Object - * `device` [HIDDevice[]](structures/hid-device.md) + * `device` [HIDDevice](structures/hid-device.md) * `origin` string (optional) - The origin that the device has been revoked from. Emitted after `HIDDevice.forget()` has been called. This event can be used @@ -304,7 +390,7 @@ cancel the request. Additionally, permissioning on `navigator.serial` can be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler) with the `serial` permission. -```javascript +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} const { app, BrowserWindow } = require('electron') let win = null @@ -385,6 +471,162 @@ callback from `select-serial-port` is called. This event is intended for use when using a UI to ask users to pick a port so that the UI can be updated to remove the specified port. +#### Event: 'serial-port-revoked' + +Returns: + +* `event` Event +* `details` Object + * `port` [SerialPort](structures/serial-port.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `origin` string - The origin that the device has been revoked from. + +Emitted after `SerialPort.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when `setDevicePermissionHandler` is used. + +```js +// Browser Process +const { app, BrowserWindow } = require('electron') + +app.whenReady().then(() => { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.webContents.session.on('serial-port-revoked', (event, details) => { + console.log(`Access revoked for serial device from origin ${details.origin}`) + }) +}) +``` + +```js @ts-nocheck +// Renderer Process + +const portConnect = async () => { + // Request a port. + const port = await navigator.serial.requestPort() + + // Wait for the serial port to open. + await port.open({ baudRate: 9600 }) + + // ...later, revoke access to the serial port. + await port.forget() +} +``` + +#### Event: 'select-usb-device' + +Returns: + +* `event` Event +* `details` Object + * `deviceList` [USBDevice[]](structures/usb-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. +* `callback` Function + * `deviceId` string (optional) + +Emitted when a USB device needs to be selected when a call to +`navigator.usb.requestDevice` is made. `callback` should be called with +`deviceId` to be selected; passing no arguments to `callback` will +cancel the request. Additionally, permissioning on `navigator.usb` can +be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler) +and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler). + +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} @ts-type={updateGrantedDevices:(devices:Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)=>void} +const { app, BrowserWindow } = require('electron') + +let win = null + +app.whenReady().then(() => { + win = new BrowserWindow() + + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'usb') { + // Add logic here to determine if permission should be given to allow USB selection + return true + } + return false + }) + + // Optionally, retrieve previously persisted devices from a persistent store (fetchGrantedDevices needs to be implemented by developer to fetch persisted permissions) + const grantedDevices = fetchGrantedDevices() + + win.webContents.session.setDevicePermissionHandler((details) => { + if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'usb') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.usb.requestDevice` first) + return true + } + + // Search through the list of devices that have previously been granted permission + return grantedDevices.some((grantedDevice) => { + return grantedDevice.vendorId === details.device.vendorId && + grantedDevice.productId === details.device.productId && + grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber + }) + } + return false + }) + + win.webContents.session.on('select-usb-device', (event, details, callback) => { + event.preventDefault() + const selectedDevice = details.deviceList.find((device) => { + return device.vendorId === 9025 && device.productId === 67 + }) + if (selectedDevice) { + // Optionally, add this to the persisted devices (updateGrantedDevices needs to be implemented by developer to persist permissions) + grantedDevices.push(selectedDevice) + updateGrantedDevices(grantedDevices) + } + callback(selectedDevice?.deviceId) + }) +}) +``` + +#### Event: 'usb-device-added' + +Returns: + +* `event` Event +* `device` [USBDevice](structures/usb-device.md) +* `webContents` [WebContents](web-contents.md) + +Emitted after `navigator.usb.requestDevice` has been called and +`select-usb-device` has fired if a new device becomes available before +the callback from `select-usb-device` is called. This event is intended for +use when using a UI to ask users to pick a device so that the UI can be updated +with the newly added device. + +#### Event: 'usb-device-removed' + +Returns: + +* `event` Event +* `device` [USBDevice](structures/usb-device.md) +* `webContents` [WebContents](web-contents.md) + +Emitted after `navigator.usb.requestDevice` has been called and +`select-usb-device` has fired if a device has been removed before the callback +from `select-usb-device` is called. This event is intended for use when using +a UI to ask users to pick a device so that the UI can be updated to remove the +specified device. + +#### Event: 'usb-device-revoked' + +Returns: + +* `event` Event +* `details` Object + * `device` [USBDevice](structures/usb-device.md) + * `origin` string (optional) - The origin that the device has been revoked from. + +Emitted after `USBDevice.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when +`setDevicePermissionHandler` is used. + ### Instance Methods The following methods are available on instances of `Session`: @@ -404,12 +646,12 @@ Clears the session’s HTTP cache. * `options` Object (optional) * `origin` string (optional) - Should follow `window.location.origin`’s representation `scheme://host:port`. - * `storages` string[] (optional) - The types of storages to clear, can contain: - `appcache`, `cookies`, `filesystem`, `indexdb`, `localstorage`, + * `storages` string[] (optional) - The types of storages to clear, can be + `cookies`, `filesystem`, `indexdb`, `localstorage`, `shadercache`, `websql`, `serviceworkers`, `cachestorage`. If not specified, clear all storage types. - * `quotas` string[] (optional) - The types of quotas to clear, can contain: - `temporary`, `persistent`, `syncable`. If not specified, clear all quotas. + * `quotas` string[] (optional) - The types of quotas to clear, can be + `temporary`, `syncable`. If not specified, clear all quotas. Returns `Promise<void>` - resolves when the storage data has been cleared. @@ -419,104 +661,49 @@ Writes any unwritten DOMStorage data to disk. #### `ses.setProxy(config)` -* `config` Object - * `mode` string (optional) - The proxy mode. Should be one of `direct`, - `auto_detect`, `pac_script`, `fixed_servers` or `system`. If it's - unspecified, it will be automatically determined based on other specified - options. - * `direct` - In direct mode all connections are created directly, without any proxy involved. - * `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can - be downloaded at http://wpad/wpad.dat. - * `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is - retrieved from the URL specified in the `pacScript`. This is the default mode - if `pacScript` is specified. - * `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`. - This is the default mode if `proxyRules` is specified. - * `system` - In system mode the proxy configuration is taken from the operating system. - Note that the system mode is different from setting no proxy configuration. - In the latter case, Electron falls back to the system settings - only if no command-line options influence the proxy configuration. - * `pacScript` string (optional) - The URL associated with the PAC file. - * `proxyRules` string (optional) - Rules indicating which proxies to use. - * `proxyBypassRules` string (optional) - Rules indicating which URLs should - bypass the proxy settings. +* `config` [ProxyConfig](structures/proxy-config.md) Returns `Promise<void>` - Resolves when the proxy setting process is complete. Sets the proxy settings. -When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules` -option is ignored and `pacScript` configuration is applied. - You may need `ses.closeAllConnections` to close currently in flight connections to prevent pooled sockets using previous proxy from being reused by future requests. -The `proxyRules` has to follow the rules below: +#### `ses.resolveHost(host, [options])` -```sh -proxyRules = schemeProxies[";"<schemeProxies>] -schemeProxies = [<urlScheme>"="]<proxyURIList> -urlScheme = "http" | "https" | "ftp" | "socks" -proxyURIList = <proxyURL>[","<proxyURIList>] -proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>] -``` - -For example: - -* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and - HTTP proxy `foopy2:80` for `ftp://` URLs. -* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. -* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing - over to `bar` if `foopy:80` is unavailable, and after that using no proxy. -* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. -* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail - over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. -* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no - proxy if `foopy` is unavailable. -* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use - `socks4://foopy2` for all other URLs. - -The `proxyBypassRules` is a comma separated list of rules described below: - -* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` - - Match all hostnames that match the pattern HOSTNAME_PATTERN. - - Examples: - "foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99", - "https://x.*.y.com:99" - -* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` - - Match a particular domain suffix. - - Examples: - ".google.com", ".com", "http://.google.com" - -* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` - - Match URLs which are IP address literals. - - Examples: - "127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99" - -* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` - - Match any URL that is to an IP literal that falls between the - given range. IP range is specified using CIDR notation. - - Examples: - "192.168.1.1/16", "fefe:13::abc/33". - -* `<local>` - - Match local addresses. The meaning of `<local>` is whether the - host matches one of: "127.0.0.1", "::1", "localhost". +* `host` string - Hostname to resolve. +* `options` Object (optional) + * `queryType` string (optional) - Requested DNS query type. If unspecified, + resolver will pick A or AAAA (or both) based on IPv4/IPv6 settings: + * `A` - Fetch only A records + * `AAAA` - Fetch only AAAA records. + * `source` string (optional) - The source to use for resolved addresses. + Default allows the resolver to pick an appropriate source. Only affects use + of big external sources (e.g. calling the system for resolution or using + DNS). Even if a source is specified, results can still come from cache, + resolving "localhost" or IP literals, etc. One of the following values: + * `any` (default) - Resolver will pick an appropriate source. Results could + come from DNS, MulticastDNS, HOSTS file, etc + * `system` - Results will only be retrieved from the system or OS, e.g. via + the `getaddrinfo()` system call + * `dns` - Results will only come from DNS queries + * `mdns` - Results will only come from Multicast DNS queries + * `localOnly` - No external sources will be used. Results will only come + from fast local sources that are available no matter the source setting, + e.g. cache, hosts file, IP literal resolution, etc. + * `cacheUsage` string (optional) - Indicates what DNS cache entries, if any, + can be used to provide a response. One of the following values: + * `allowed` (default) - Results may come from the host cache if non-stale + * `staleAllowed` - Results may come from the host cache even if stale (by + expiration or network changes) + * `disallowed` - Results will not come from the host cache. + * `secureDnsPolicy` string (optional) - Controls the resolver's Secure DNS + behavior for this request. One of the following values: + * `allow` (default) + * `disable` + +Returns [`Promise<ResolvedHost>`](structures/resolved-host.md) - Resolves with the resolved IP addresses for the `host`. #### `ses.resolveProxy(url)` @@ -549,16 +736,18 @@ Sets download saving directory. By default, the download directory will be the Emulates network with the given configuration for the `session`. -```javascript +```js +const win = new BrowserWindow() + // To emulate a GPRS connection with 50kbps throughput and 500 ms latency. -window.webContents.session.enableNetworkEmulation({ +win.webContents.session.enableNetworkEmulation({ latency: 500, downloadThroughput: 6400, uploadThroughput: 6400 }) // To emulate a network outage. -window.webContents.session.enableNetworkEmulation({ offline: true }) +win.webContents.session.enableNetworkEmulation({ offline: true }) ``` #### `ses.preconnect(options)` @@ -575,6 +764,60 @@ Returns `Promise<void>` - Resolves when all connections are closed. **Note:** It will terminate / fail all requests currently in flight. +#### `ses.fetch(input[, init])` + +* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request) +* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional) + +Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). + +Sends a request, similarly to how `fetch()` works in the renderer, using +Chrome's network stack. This differs from Node's `fetch()`, which uses +Node.js's HTTP stack. + +Example: + +```js +async function example () { + const response = await net.fetch('https://my.app') + if (response.ok) { + const body = await response.json() + // ... use the result. + } +} +``` + +See also [`net.fetch()`](net.md#netfetchinput-init), a convenience method which +issues requests from the [default session](#sessiondefaultsession). + +See the MDN documentation for +[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more +details. + +Limitations: + +* `net.fetch()` does not support the `data:` or `blob:` schemes. +* The value of the `integrity` option is ignored. +* The `.type` and `.url` values of the returned `Response` object are + incorrect. + +By default, requests made with `net.fetch` can be made to [custom protocols](protocol.md) +as well as `file:`, and will trigger [webRequest](web-request.md) handlers if present. +When the non-standard `bypassCustomProtocolHandlers` option is set in RequestInit, +custom protocol handlers will not be called for this request. This allows forwarding an +intercepted request to the built-in handler. [webRequest](web-request.md) +handlers will still be triggered when bypassing custom protocols. + +```js +protocol.handle('https', (req) => { + if (req.url === 'https://my-app.com') { + return new Response('<body>my app</body>') + } else { + return net.fetch(req, { bypassCustomProtocolHandlers: true }) + } +}) +``` + #### `ses.disableNetworkEmulation()` Disables any network emulation already active for the `session`. Resets to @@ -606,7 +849,7 @@ calling `callback(-2)` rejects it. Calling `setCertificateVerifyProc(null)` will revert back to default certificate verify proc. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -628,26 +871,28 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => { * `webContents` [WebContents](web-contents.md) - WebContents requesting the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. * `permission` string - The type of requested permission. * `clipboard-read` - Request access to read from the clipboard. + * `clipboard-sanitized-write` - Request access to write to the clipboard. + * `display-capture` - Request access to capture the screen via the [Screen Capture API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API). + * `fullscreen` - Request control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). + * `geolocation` - Request access to the user's location via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) + * `idle-detection` - Request access to the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector). * `media` - Request access to media devices such as camera, microphone and speakers. - * `display-capture` - Request access to capture the screen. * `mediaKeySystem` - Request access to DRM protected content. - * `geolocation` - Request access to user's current location. - * `notifications` - Request notification creation and the ability to display them in the user's system tray. - * `midi` - Request MIDI access in the `webmidi` API. - * `midiSysex` - Request the use of system exclusive messages in the `webmidi` API. - * `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. - * `fullscreen` - Request for the app to enter fullscreen mode. + * `midi` - Request MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification) + * `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame. + * `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame. * `openExternal` - Request to open links in external applications. - * `unknown` - An unrecognized permission request + * `speaker-selection` - Request to enumerate and select audio output devices via the [speaker-selection permissions policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/speaker-selection). + * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API. + * `unknown` - An unrecognized permission request. + * `fileSystem` - Request access to read, write, and file management capabilities using the [File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API). * `callback` Function * `permissionGranted` boolean - Allow or deny the permission. - * `details` Object - Some properties are only available on certain permission types. - * `externalURL` string (optional) - The url of the `openExternal` request. - * `securityOrigin` string (optional) - The security origin of the `media` request. - * `mediaTypes` string[] (optional) - The types of media access being requested, elements can be `video` - or `audio` - * `requestingUrl` string - The last URL the requesting frame loaded - * `isMainFrame` boolean - Whether the frame making the request is the main frame + * `details` [PermissionRequest](structures/permission-request.md) | [FilesystemPermissionRequest](structures/filesystem-permission-request.md) | [MediaAccessPermissionRequest](structures/media-access-permission-request.md) | [OpenExternalPermissionRequest](structures/open-external-permission-request.md) - Additional information about the permission being requested. Sets the handler which can be used to respond to permission requests for the `session`. Calling `callback(true)` will allow the permission and `callback(false)` will reject it. @@ -655,7 +900,7 @@ To clear the handler, call `setPermissionRequestHandler(null)`. Please note tha you must also implement `setPermissionCheckHandler` to get complete permission handling. Most web APIs do a permission check and then make a permission request if the check is denied. -```javascript +```js const { session } = require('electron') session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => { if (webContents.getURL() === 'some-host' && permission === 'notifications') { @@ -670,7 +915,24 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents * `handler` Function\<boolean> | null * `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively. - * `permission` string - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, `hid`, or `serial`. + * `permission` string - Type of permission check. + * `clipboard-read` - Request access to read from the clipboard. + * `clipboard-sanitized-write` - Request access to write to the clipboard. + * `geolocation` - Access the user's geolocation data via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) + * `fullscreen` - Control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). + * `hid` - Access the HID protocol to manipulate HID devices via the [WebHID API](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API). + * `idle-detection` - Access the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector). + * `media` - Access to media devices such as camera, microphone and speakers. + * `mediaKeySystem` - Access to DRM protected content. + * `midi` - Enable MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `midiSysex` - Use system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `notifications` - Configure and display desktop notifications to the user with the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification). + * `openExternal` - Open links in external applications. + * `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame. + * `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API). + * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API). * `requestingOrigin` string - The origin URL of the permission check * `details` Object - Some properties are only available on certain permission types. * `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks. @@ -686,7 +948,7 @@ you must also implement `setPermissionRequestHandler` to get complete permission Most web APIs do a permission check and then make a permission request if the check is denied. To clear the handler, call `setPermissionCheckHandler(null)`. -```javascript +```js const { session } = require('electron') const url = require('url') session.fromPartition('some-partition').setPermissionCheckHandler((webContents, permission, requestingOrigin) => { @@ -698,13 +960,82 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents, }) ``` +#### `ses.setDisplayMediaRequestHandler(handler[, opts])` + +* `handler` Function | null + * `request` Object + * `frame` [WebFrameMain](web-frame-main.md) | null - Frame that is requesting access to media. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `securityOrigin` String - Origin of the page making the request. + * `videoRequested` Boolean - true if the web content requested a video stream. + * `audioRequested` Boolean - true if the web content requested an audio stream. + * `userGesture` Boolean - Whether a user gesture was active when this request was triggered. + * `callback` Function + * `streams` Object + * `video` Object | [WebFrameMain](web-frame-main.md) (optional) + * `id` String - The id of the stream being granted. This will usually + come from a [DesktopCapturerSource](structures/desktop-capturer-source.md) + object. + * `name` String - The name of the stream being granted. This will + usually come from a [DesktopCapturerSource](structures/desktop-capturer-source.md) + object. + * `audio` String | [WebFrameMain](web-frame-main.md) (optional) - If + a string is specified, can be `loopback` or `loopbackWithMute`. + Specifying a loopback device will capture system audio, and is + currently only supported on Windows. If a WebFrameMain is specified, + will capture audio from that frame. + * `enableLocalEcho` Boolean (optional) - If `audio` is a [WebFrameMain](web-frame-main.md) + and this is set to `true`, then local playback of audio will not be muted (e.g. using `MediaRecorder` + to record `WebFrameMain` with this flag set to `true` will allow audio to pass through to the speakers + while recording). Default is `false`. +* `opts` Object (optional) _macOS_ _Experimental_ + * `useSystemPicker` Boolean - true if the available native system picker should be used. Default is `false`. _macOS_ _Experimental_ + +This handler will be called when web content requests access to display media +via the `navigator.mediaDevices.getDisplayMedia` API. Use the +[desktopCapturer](desktop-capturer.md) API to choose which stream(s) to grant +access to. + +`useSystemPicker` allows an application to use the system picker instead of providing a specific video source from `getSources`. +This option is experimental, and currently available for MacOS 15+ only. If the system picker is available and `useSystemPicker` +is set to `true`, the handler will not be invoked. + +```js +const { session, desktopCapturer } = require('electron') + +session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + desktopCapturer.getSources({ types: ['screen'] }).then((sources) => { + // Grant access to the first screen found. + callback({ video: sources[0] }) + }) + // Use the system picker if available. + // Note: this is currently experimental. If the system picker + // is available, it will be used and the media request handler + // will not be invoked. +}, { useSystemPicker: true }) +``` + +Passing a [WebFrameMain](web-frame-main.md) object as a video or audio stream +will capture the video or audio stream from that frame. + +```js +const { session } = require('electron') + +session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + // Allow the tab to capture itself. + callback({ video: request.frame }) +}) +``` + +Passing `null` instead of a function resets the handler to its default state. + #### `ses.setDevicePermissionHandler(handler)` * `handler` Function\<boolean> | null * `details` Object - * `deviceType` string - The type of device that permission is being requested on, can be `hid` or `serial`. + * `deviceType` string - The type of device that permission is being requested on, can be `hid`, `serial`, or `usb`. * `origin` string - The origin URL of the device permission check. - * `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for. + * `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md) | [USBDevice](structures/usb-device.md) - the device that permission is being requested for. Sets the handler which can be used to respond to device permission checks for the `session`. Returning `true` will allow the device to be permitted and `false` will reject it. @@ -712,11 +1043,11 @@ To clear the handler, call `setDevicePermissionHandler(null)`. This handler can be used to provide default permissioning to devices without first calling for permission to devices (eg via `navigator.hid.requestDevice`). If this handler is not defined, the default device permissions as granted through device selection (eg via `navigator.hid.requestDevice`) will be used. -Additionally, the default behavior of Electron is to store granted device permision in memory. +Additionally, the default behavior of Electron is to store granted device permission in memory. If longer term storage is needed, a developer can store granted device permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`. -```javascript +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} const { app, BrowserWindow } = require('electron') let win = null @@ -730,6 +1061,8 @@ app.whenReady().then(() => { return true } else if (permission === 'serial') { // Add logic here to determine if permission should be given to allow serial port selection + } else if (permission === 'usb') { + // Add logic here to determine if permission should be given to allow USB device selection } return false }) @@ -762,13 +1095,128 @@ app.whenReady().then(() => { win.webContents.session.on('select-hid-device', (event, details, callback) => { event.preventDefault() const selectedDevice = details.deviceList.find((device) => { - return device.vendorId === '9025' && device.productId === '67' + return device.vendorId === 9025 && device.productId === 67 + }) + callback(selectedDevice?.deviceId) + }) +}) +``` + +#### `ses.setUSBProtectedClassesHandler(handler)` + +* `handler` Function\<string[]> | null + * `details` Object + * `protectedClasses` string[] - The current list of protected USB classes. Possible class values include: + * `audio` + * `audio-video` + * `hid` + * `mass-storage` + * `smart-card` + * `video` + * `wireless` + +Sets the handler which can be used to override which [USB classes are protected](https://wicg.github.io/webusb/#usbinterface-interface). +The return value for the handler is a string array of USB classes which should be considered protected (eg not available in the renderer). Valid values for the array are: + +* `audio` +* `audio-video` +* `hid` +* `mass-storage` +* `smart-card` +* `video` +* `wireless` + +Returning an empty string array from the handler will allow all USB classes; returning the passed in array will maintain the default list of protected USB classes (this is also the default behavior if a handler is not defined). +To clear the handler, call `setUSBProtectedClassesHandler(null)`. + +```js +const { app, BrowserWindow } = require('electron') + +let win = null + +app.whenReady().then(() => { + win = new BrowserWindow() + + win.webContents.session.setUSBProtectedClassesHandler((details) => { + // Allow all classes: + // return [] + // Keep the current set of protected classes: + // return details.protectedClasses + // Selectively remove classes: + return details.protectedClasses.filter((usbClass) => { + // Exclude classes except for audio classes + return usbClass.indexOf('audio') === -1 }) - callback(selectedPort?.deviceId) }) }) ``` +#### `ses.setBluetoothPairingHandler(handler)` _Windows_ _Linux_ + +* `handler` Function | null + * `details` Object + * `deviceId` string + * `pairingKind` string - The type of pairing prompt being requested. + One of the following values: + * `confirm` + This prompt is requesting confirmation that the Bluetooth device should + be paired. + * `confirmPin` + This prompt is requesting confirmation that the provided PIN matches the + pin displayed on the device. + * `providePin` + This prompt is requesting that a pin be provided for the device. + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this handler. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `pin` string (optional) - The pin value to verify if `pairingKind` is `confirmPin`. + * `callback` Function + * `response` Object + * `confirmed` boolean - `false` should be passed in if the dialog is canceled. + If the `pairingKind` is `confirm` or `confirmPin`, this value should indicate + if the pairing is confirmed. If the `pairingKind` is `providePin` the value + should be `true` when a value is provided. + * `pin` string | null (optional) - When the `pairingKind` is `providePin` + this value should be the required pin for the Bluetooth device. + +Sets a handler to respond to Bluetooth pairing requests. This handler +allows developers to handle devices that require additional validation +before pairing. When a handler is not defined, any pairing on Linux or Windows +that requires additional validation will be automatically cancelled. +macOS does not require a handler because macOS handles the pairing +automatically. To clear the handler, call `setBluetoothPairingHandler(null)`. + +```js +const { app, BrowserWindow, session } = require('electron') +const path = require('node:path') + +function createWindow () { + let bluetoothPinCallback = null + + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + bluetoothPinCallback = callback + // Send a IPC message to the renderer to prompt the user to confirm the pairing. + // Note that this will require logic in the renderer to handle this message and + // display a prompt to the user. + mainWindow.webContents.send('bluetooth-pairing-request', details) + }) + + // Listen for an IPC message from the renderer to get the response for the Bluetooth pairing. + mainWindow.webContents.ipc.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) + }) +} + +app.whenReady().then(() => { + createWindow() +}) +``` + #### `ses.clearHostResolverCache()` Returns `Promise<void>` - Resolves when the operation is complete. @@ -783,7 +1231,7 @@ Clears the host resolver cache. Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication. -```javascript +```js const { session } = require('electron') // consider any url ending with `example.com`, `foobar.com`, `baz` // for integrated authentication. @@ -846,16 +1294,18 @@ reused for new connections. Returns `Promise<Buffer>` - resolves with blob data. -#### `ses.downloadURL(url)` +#### `ses.downloadURL(url[, options])` * `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url`. The API will generate a [DownloadItem](download-item.md) that can be accessed with the [will-download](#event-will-download) event. **Note:** This does not perform any security checks that relate to a page's origin, -unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl). +unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl-options). #### `ses.createInterruptedDownload(options)` @@ -880,18 +1330,43 @@ the initial state will be `interrupted`. The download will start only when the Returns `Promise<void>` - resolves when the session’s HTTP authentication cache has been cleared. -#### `ses.setPreloads(preloads)` +#### `ses.setPreloads(preloads)` _Deprecated_ * `preloads` string[] - An array of absolute path to preload scripts Adds scripts that will be executed on ALL web contents that are associated with this session just before normal `preload` scripts run. -#### `ses.getPreloads()` +**Deprecated:** Use the new `ses.registerPreloadScript` API. + +#### `ses.getPreloads()` _Deprecated_ Returns `string[]` an array of paths to preload scripts that have been registered. +**Deprecated:** Use the new `ses.getPreloadScripts` API. This will only return preload script paths +for `frame` context types. + +#### `ses.registerPreloadScript(script)` + +* `script` [PreloadScriptRegistration](structures/preload-script-registration.md) - Preload script + +Registers preload script that will be executed in its associated context type in this session. For +`frame` contexts, this will run prior to any preload defined in the web preferences of a +WebContents. + +Returns `string` - The ID of the registered preload script. + +#### `ses.unregisterPreloadScript(id)` + +* `id` string - Preload script ID + +Unregisters script. + +#### `ses.getPreloadScripts()` + +Returns [`PreloadScript[]`](structures/preload-script.md): An array of paths to preload scripts that have been registered. + #### `ses.setCodeCachePath(path)` * `path` String - Absolute path to store the v8 generated JS code cache from the renderer. @@ -899,6 +1374,10 @@ registered. Sets the directory to store the generated JS [code cache](https://v8.dev/blog/code-caching-for-devs) for this session. The directory is not required to be created by the user before this call, the runtime will create if it does not exist otherwise will use the existing directory. If directory cannot be created, then code cache will not be used and all operations related to code cache will fail silently inside the runtime. By default, the directory will be `Code Cache` under the respective user data folder. +Note that by default code cache is only enabled for http(s) URLs, to enable code +cache for custom protocols, `codeCache: true` and `standard: true` must be +specified when registering the protocol. + #### `ses.clearCodeCaches(options)` * `options` Object @@ -906,6 +1385,36 @@ respective user data folder. Returns `Promise<void>` - resolves when the code cache clear operation is complete. +#### `ses.getSharedDictionaryUsageInfo()` + +Returns `Promise<SharedDictionaryUsageInfo[]>` - an array of shared dictionary information entries in Chromium's networking service's storage. + +Shared dictionaries are used to power advanced compression of data sent over the wire, specifically with Brotli and ZStandard. You don't need to call any of the shared dictionary APIs in Electron to make use of this advanced web feature, but if you do, they allow deeper control and inspection of the shared dictionaries used during decompression. + +To get detailed information about a specific shared dictionary entry, call `getSharedDictionaryInfo(options)`. + +#### `ses.getSharedDictionaryInfo(options)` + +* `options` Object + * `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. + * `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. + +Returns `Promise<SharedDictionaryInfo[]>` - an array of shared dictionary information entries in Chromium's networking service's storage. + +To get information about all present shared dictionaries, call `getSharedDictionaryUsageInfo()`. + +#### `ses.clearSharedDictionaryCache()` + +Returns `Promise<void>` - resolves when the dictionary cache has been cleared, both in memory and on disk. + +#### `ses.clearSharedDictionaryCacheForIsolationKey(options)` + +* `options` Object + * `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. + * `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. + +Returns `Promise<void>` - resolves when the dictionary cache has been cleared for the specified isolation key, both in memory and on disk. + #### `ses.setSpellCheckerEnabled(enable)` * `enable` boolean @@ -932,7 +1441,7 @@ Returns `string[]` - An array of language codes the spellchecker is enabled for. will fallback to using `en-US`. By default on launch if this setting is an empty list Electron will try to populate this setting with the current OS locale. This setting is persisted across restarts. -**Note:** On macOS the OS spellchecker is used and has its own list of languages. This API is a no-op on macOS. +**Note:** On macOS the OS spellchecker is used and has its own list of languages. On macOS, this API will return whichever languages have been configured by the OS. #### `ses.setSpellCheckerDictionaryDownloadURL(url)` @@ -1001,9 +1510,9 @@ extension to be loaded. ```js const { app, session } = require('electron') -const path = require('path') +const path = require('node:path') -app.on('ready', async () => { +app.whenReady().then(async () => { await session.defaultSession.loadExtension( path.join(__dirname, 'react-devtools'), // allowFileAccess is required to load the devtools extension on file:// URLs. @@ -1035,7 +1544,7 @@ is emitted. * `extensionId` string - ID of extension to query -Returns `Extension` | `null` - The loaded extension with the given ID. +Returns `Extension | null` - The loaded extension with the given ID. **Note:** This API cannot be called before the `ready` event of the `app` module is emitted. @@ -1052,6 +1561,41 @@ is emitted. Returns `string | null` - The absolute file system path where data for this session is persisted on disk. For in memory sessions this returns `null`. +#### `ses.clearData([options])` + +* `options` Object (optional) + * `dataTypes` String[] (optional) - The types of data to clear. By default, this will clear all types of data. This + can potentially include data types not explicitly listed here. (See Chromium's + [`BrowsingDataRemover`][browsing-data-remover] for the full list.) + * `backgroundFetch` - Background Fetch + * `cache` - Cache (includes `cachestorage` and `shadercache`) + * `cookies` - Cookies + * `downloads` - Downloads + * `fileSystems` - File Systems + * `indexedDB` - IndexedDB + * `localStorage` - Local Storage + * `serviceWorkers` - Service Workers + * `webSQL` - WebSQL + * `origins` String[] (optional) - Clear data for only these origins. Cannot be used with `excludeOrigins`. + * `excludeOrigins` String[] (optional) - Clear data for all origins except these ones. Cannot be used with `origins`. + * `avoidClosingConnections` boolean (optional) - Skips deleting cookies that would close current network connections. (Default: `false`) + * `originMatchingMode` String (optional) - The behavior for matching data to origins. + * `third-parties-included` (default) - Storage is matched on origin in first-party contexts and top-level-site in third-party contexts. + * `origin-in-all-contexts` - Storage is matched on origin only in all contexts. + +Returns `Promise<void>` - resolves when all data has been cleared. + +Clears various different types of data. + +This method clears more types of data and is more thorough than the +`clearStorageData` method. + +**Note:** Cookies are stored at a broader scope than origins. When removing cookies and filtering by `origins` (or `excludeOrigins`), the cookies will be removed at the [registrable domain](https://url.spec.whatwg.org/#host-registrable-domain) level. For example, clearing cookies for the origin `https://really.specific.origin.example.com/` will end up clearing all cookies for `example.com`. Clearing cookies for the origin `https://my.website.example.co.uk/` will end up clearing all cookies for `example.co.uk`. + +**Note:** Clearing cache data will also clear the shared dictionary cache. This means that any dictionaries used for compression may be reloaded after clearing the cache. If you wish to clear the shared dictionary cache but leave other cached data intact, you may want to use the `clearSharedDictionaryCache` method. + +For more information, refer to Chromium's [`BrowsingDataRemover` interface][browsing-data-remover]. + ### Instance Properties The following properties are available on instances of `Session`: @@ -1086,15 +1630,15 @@ A [`WebRequest`](web-request.md) object for this session. A [`Protocol`](protocol.md) object for this session. -```javascript +```js const { app, session } = require('electron') -const path = require('path') +const path = require('node:path') app.whenReady().then(() => { const protocol = session.fromPartition('some-partition').protocol if (!protocol.registerFileProtocol('atom', (request, callback) => { const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + callback({ path: path.normalize(path.join(__dirname, url)) }) })) { console.error('Failed to register protocol') } @@ -1105,7 +1649,7 @@ app.whenReady().then(() => { A [`NetLog`](net-log.md) object for this session. -```javascript +```js const { app, session } = require('electron') app.whenReady().then(async () => { @@ -1116,3 +1660,5 @@ app.whenReady().then(async () => { console.log('Net-logs written to', path) }) ``` + +[browsing-data-remover]: https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/browsing_data_remover.h diff --git a/docs/api/shell.md b/docs/api/shell.md index a0e34c0dbe61d..1008b73c164d2 100644 --- a/docs/api/shell.md +++ b/docs/api/shell.md @@ -8,7 +8,7 @@ The `shell` module provides functions related to desktop integration. An example of opening a URL in the user's default browser: -```javascript +```js const { shell } = require('electron') shell.openExternal('https://github.com') @@ -36,10 +36,12 @@ Open the given file in the desktop's default manner. ### `shell.openExternal(url[, options])` -* `url` string - Max 2081 characters on windows. +* `url` string - Max 2081 characters on Windows. * `options` Object (optional) * `activate` boolean (optional) _macOS_ - `true` to bring the opened application to the foreground. The default is `true`. * `workingDirectory` string (optional) _Windows_ - The working directory. + * `logUsage` boolean (optional) _Windows_ - Indicates a user initiated launch that enables tracking of frequently used programs and other behaviors. + The default is `false`. Returns `Promise<void>` diff --git a/docs/api/structures/base-window-options.md b/docs/api/structures/base-window-options.md new file mode 100644 index 0000000000000..771445be06e08 --- /dev/null +++ b/docs/api/structures/base-window-options.md @@ -0,0 +1,158 @@ +# BaseWindowConstructorOptions Object + +* `width` Integer (optional) - Window's width in pixels. Default is `800`. +* `height` Integer (optional) - Window's height in pixels. Default is `600`. +* `x` Integer (optional) - (**required** if y is used) Window's left offset from screen. + Default is to center the window. +* `y` Integer (optional) - (**required** if x is used) Window's top offset from screen. + Default is to center the window. +* `useContentSize` boolean (optional) - The `width` and `height` would be used as web + page's size, which means the actual window's size will include window + frame's size and be slightly larger. Default is `false`. +* `center` boolean (optional) - Show window in the center of the screen. Default is `false`. +* `minWidth` Integer (optional) - Window's minimum width. Default is `0`. +* `minHeight` Integer (optional) - Window's minimum height. Default is `0`. +* `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. +* `maxHeight` Integer (optional) - Window's maximum height. Default is no limit. +* `resizable` boolean (optional) - Whether window is resizable. Default is `true`. +* `movable` boolean (optional) _macOS_ _Windows_ - Whether window is + movable. This is not implemented on Linux. Default is `true`. +* `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is + minimizable. This is not implemented on Linux. Default is `true`. +* `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is + maximizable. This is not implemented on Linux. Default is `true`. +* `closable` boolean (optional) _macOS_ _Windows_ - Whether window is + closable. This is not implemented on Linux. Default is `true`. +* `focusable` boolean (optional) - Whether the window can be focused. Default is + `true`. On Windows setting `focusable: false` also implies setting + `skipTaskbar: true`. On Linux setting `focusable: false` makes the window + stop interacting with wm, so the window will always stay on top in all + workspaces. +* `alwaysOnTop` boolean (optional) - Whether the window should always stay on top of + other windows. Default is `false`. +* `fullscreen` boolean (optional) - Whether the window should show in fullscreen. When + explicitly set to `false` the fullscreen button will be hidden or disabled + on macOS. Default is `false`. +* `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen + mode. On macOS, also whether the maximize/zoom button should toggle full + screen mode or maximize window. Default is `true`. +* `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on + macOS. Default is `false`. +* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar. + Default is `false`. +* `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control. +* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`. +* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. +* `icon` ([NativeImage](../native-image.md) | string) (optional) - The window icon. On Windows it is + recommended to use `ICO` icons to get best visual effects, you can also + leave it undefined so the executable's icon will be used. +* `show` boolean (optional) - Whether window should be shown when created. Default is + `true`. +* `frame` boolean (optional) - Specify `false` to create a + [frameless window](../../tutorial/custom-window-styles.md#frameless-windows). Default is `true`. +* `parent` BaseWindow (optional) - Specify parent window. Default is `null`. +* `modal` boolean (optional) - Whether this is a modal window. This only works when the + window is a child window. Default is `false`. +* `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an + inactive window will also click through to the web contents. Default is + `false` on macOS. This option is not configurable on other platforms. +* `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing. + Default is `false`. +* `autoHideMenuBar` boolean (optional) - Auto hide the menu bar unless the `Alt` + key is pressed. Default is `false`. +* `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to + be resized larger than screen. Only relevant for macOS, as other OSes + allow larger-than-screen windows by default. Default is `false`. +* `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](../browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information. +* `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`. +* `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of + the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This + is only implemented on Windows and macOS. +* `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on + some GTK+3 desktop environments. Default is `false`. +* `transparent` boolean (optional) - Makes the window [transparent](../../tutorial/custom-window-styles.md#transparent-windows). + Default is `false`. On Windows, does not work unless the window is frameless. +* `type` string (optional) - The type of window, default is normal window. See more about + this below. +* `visualEffectState` string (optional) _macOS_ - Specify how the material + appearance should reflect window activity state on macOS. Must be used + with the `vibrancy` property. Possible values are: + * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. + * `active` - The backdrop should always appear active. + * `inactive` - The backdrop should always appear inactive. +* `titleBarStyle` string (optional) - The style of window title bar. + Default is `default`. Possible values are: + * `default` - Results in the standard title bar for macOS or Windows respectively. + * `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows and Linux, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown. + * `hiddenInset` _macOS_ - Results in a hidden title bar + with an alternative look where the traffic light buttons are slightly + more inset from the window edge. + * `customButtonsOnHover` _macOS_ - Results in a hidden + title bar and a full size content window, the traffic light buttons will + display when being hovered over in the top left of the window. + **Note:** This option is currently experimental. +* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. + * `color` String (optional) _Windows_ _Linux_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color. + * `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. Default is system height. +* `trafficLightPosition` [Point](point.md) (optional) _macOS_ - + Set a custom position for the traffic light buttons in frameless windows. +* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window + should have rounded corners on macOS. Default is `true`. Setting this property + to `false` will prevent the window from being fullscreenable. +* `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on + Windows, which adds standard window frame. Setting it to `false` will remove + window shadow and window animations. Default is `true`. +* `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to + the window, only on macOS. Can be `appearance-based`, `titlebar`, `selection`, + `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, + `tooltip`, `content`, `under-window`, or `under-page`. +* `backgroundMaterial` string (optional) _Windows_ - Set the window's + system-drawn background material, including behind the non-client area. + Can be `auto`, `none`, `mica`, `acrylic` or `tabbed`. See [win.setBackgroundMaterial](../browser-window.md#winsetbackgroundmaterialmaterial-windows) for more information. +* `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on + macOS when option-clicking the green stoplight button on the toolbar or by + clicking the Window > Zoom menu item. If `true`, the window will grow to + the preferred width of the web page when zoomed, `false` will cause it to + zoom to the width of the screen. This will also affect the behavior when + calling `maximize()` directly. Default is `false`. +* `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows + opening the window as a native tab. Windows with the same + tabbing identifier will be grouped together. This also adds a native new + tab button to your window's tab bar and allows your `app` and window to + receive the `new-window-for-tab` event. + +When setting minimum or maximum window size with `minWidth`/`maxWidth`/ +`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from +passing a size that does not follow size constraints to `setBounds`/`setSize` or +to the constructor of `BrowserWindow`. + +The possible values and behaviors of the `type` option are platform dependent. +Possible values are: + +* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, + `notification`. + * The `desktop` type places the window at the desktop background window level + (kCGDesktopWindowLevel - 1). However, note that a desktop window will not + receive focus, keyboard, or mouse events. You can still use globalShortcut to + receive input sparingly. + * The `dock` type creates a dock-like window behavior. + * The `toolbar` type creates a window with a toolbar appearance. + * The `splash` type behaves in a specific way. It is not + draggable, even if the CSS styling of the window's body contains + -webkit-app-region: drag. This type is commonly used for splash screens. + * The `notification` type creates a window that behaves like a system notification. +* On macOS, possible types are `desktop`, `textured`, `panel`. + * The `textured` type adds metal gradient appearance. This option is **deprecated**. + * The `desktop` type places the window at the desktop background window level + (`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive + focus, keyboard or mouse events, but you can use `globalShortcut` to receive + input sparingly. + * The `panel` type enables the window to float on top of full-screened apps + by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally + reserved for NSPanel, at runtime. Also, the window will appear on all + spaces (desktops). +* On Windows, possible type is `toolbar`. + +[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables +[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis diff --git a/docs/api/structures/browser-window-options.md b/docs/api/structures/browser-window-options.md new file mode 100644 index 0000000000000..a505798eb0a5b --- /dev/null +++ b/docs/api/structures/browser-window-options.md @@ -0,0 +1,4 @@ +# BrowserWindowConstructorOptions Object extends `BaseWindowConstructorOptions` + +* `webPreferences` [WebPreferences](web-preferences.md?inline) (optional) - Settings of web page's features. +* `paintWhenInitiallyHidden` boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`. diff --git a/docs/api/structures/cpu-usage.md b/docs/api/structures/cpu-usage.md index 00c267533a1ee..645da762bab67 100644 --- a/docs/api/structures/cpu-usage.md +++ b/docs/api/structures/cpu-usage.md @@ -2,6 +2,8 @@ * `percentCPUUsage` number - Percentage of CPU used since the last call to getCPUUsage. First call returns 0. +* `cumulativeCPUUsage` number (optional) - Total seconds of CPU time used since process + startup. * `idleWakeupsPerSecond` number - The number of average idle CPU wakeups per second since the last call to getCPUUsage. First call returns 0. Will always return 0 on Windows. diff --git a/docs/api/structures/custom-scheme.md b/docs/api/structures/custom-scheme.md index 402a17506a1bd..3476ede7a43d6 100644 --- a/docs/api/structures/custom-scheme.md +++ b/docs/api/structures/custom-scheme.md @@ -9,3 +9,5 @@ * `supportFetchAPI` boolean (optional) - Default false. * `corsEnabled` boolean (optional) - Default false. * `stream` boolean (optional) - Default false. + * `codeCache` boolean (optional) - Enable V8 code cache for the scheme, only + works when `standard` is also set to true. Default false. diff --git a/docs/api/structures/desktop-capturer-source.md b/docs/api/structures/desktop-capturer-source.md index 1740ee7924f52..e898ebd523628 100644 --- a/docs/api/structures/desktop-capturer-source.md +++ b/docs/api/structures/desktop-capturer-source.md @@ -2,7 +2,7 @@ * `id` string - The identifier of a window or screen that can be used as a `chromeMediaSourceId` constraint when calling - [`navigator.webkitGetUserMedia`]. The format of the identifier will be + [`navigator.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia). The format of the identifier will be `window:XX:YY` or `screen:ZZ:0`. XX is the windowID/handle. YY is 1 for the current process, and 0 for all others. ZZ is a sequential number that represents the screen, and it does not equal to the index in the diff --git a/docs/api/structures/display.md b/docs/api/structures/display.md index 8782d34d1b46b..f58e22acb709e 100644 --- a/docs/api/structures/display.md +++ b/docs/api/structures/display.md @@ -1,21 +1,25 @@ # Display Object -* `id` number - Unique identifier associated with the display. +* `accelerometerSupport` string - Can be `available`, `unavailable`, `unknown`. +* `bounds` [Rectangle](rectangle.md) - the bounds of the display in DIP points. +* `colorDepth` number - The number of bits per pixel. +* `colorSpace` string - represent a color space (three-dimensional object which contains all realizable color combinations) for the purpose of color conversions. +* `depthPerComponent` number - The number of bits per color component. +* `detected` boolean - `true`` if the display is detected by the system. +* `displayFrequency` number - The display refresh rate. +* `id` number - Unique identifier associated with the display. A value of of -1 means the display is invalid or the correct `id` is not yet known, and a value of -10 means the display is a virtual display assigned to a unified desktop. +* `internal` boolean - `true` for an internal display and `false` for an external display. +* `label` string - User-friendly label, determined by the platform. +* `maximumCursorSize` [Size](size.md) - Maximum cursor size in native pixels. +* `nativeOrigin` [Point](point.md) - Returns the display's origin in pixel coordinates. Only available on windowing systems like X11 that position displays in pixel coordinates. * `rotation` number - Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. * `scaleFactor` number - Output device's pixel scale factor. * `touchSupport` string - Can be `available`, `unavailable`, `unknown`. * `monochrome` boolean - Whether or not the display is a monochrome display. -* `accelerometerSupport` string - Can be `available`, `unavailable`, `unknown`. -* `colorSpace` string - represent a color space (three-dimensional object which contains all realizable color combinations) for the purpose of color conversions -* `colorDepth` number - The number of bits per pixel. -* `depthPerComponent` number - The number of bits per color component. -* `displayFrequency` number - The display refresh rate. -* `bounds` [Rectangle](rectangle.md) - the bounds of the display in DIP points. * `size` [Size](size.md) * `workArea` [Rectangle](rectangle.md) - the work area of the display in DIP points. -* `workAreaSize` [Size](size.md) -* `internal` boolean - `true` for an internal display and `false` for an external display +* `workAreaSize` [Size](size.md) - The size of the work area. The `Display` object represents a physical display connected to the system. A fake `Display` may exist on a headless system, or a `Display` may correspond to diff --git a/docs/api/structures/event.md b/docs/api/structures/event.md deleted file mode 100644 index 415d269feec98..0000000000000 --- a/docs/api/structures/event.md +++ /dev/null @@ -1,3 +0,0 @@ -# Event Object extends `GlobalEvent` - -* `preventDefault` VoidFunction diff --git a/docs/api/structures/file-path-with-headers.md b/docs/api/structures/file-path-with-headers.md index e07688eae1f38..cc55a18fae904 100644 --- a/docs/api/structures/file-path-with-headers.md +++ b/docs/api/structures/file-path-with-headers.md @@ -1,4 +1,4 @@ # FilePathWithHeaders Object * `path` string - The path to the file to send. -* `headers` Record<string, string> (optional) - Additional headers to be sent. +* `headers` Record\<string, string\> (optional) - Additional headers to be sent. diff --git a/docs/api/structures/filesystem-permission-request.md b/docs/api/structures/filesystem-permission-request.md new file mode 100644 index 0000000000000..8d813708cac7f --- /dev/null +++ b/docs/api/structures/filesystem-permission-request.md @@ -0,0 +1,5 @@ +# FilesystemPermissionRequest Object extends `PermissionRequest` + +* `filePath` string (optional) - The path of the `fileSystem` request. +* `isDirectory` boolean (optional) - Whether the `fileSystem` request is a directory. +* `fileAccessType` string (optional) - The access type of the `fileSystem` request. Can be `writable` or `readable`. diff --git a/docs/api/structures/input-event.md b/docs/api/structures/input-event.md index 21efec36d3e41..a68a9304dfca1 100644 --- a/docs/api/structures/input-event.md +++ b/docs/api/structures/input-event.md @@ -1,5 +1,16 @@ # InputEvent Object +* `type` string - Can be `undefined`, `mouseDown`, `mouseUp`, `mouseMove`, + `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, `rawKeyDown`, + `keyDown`, `keyUp`, `char`, `gestureScrollBegin`, `gestureScrollEnd`, + `gestureScrollUpdate`, `gestureFlingStart`, `gestureFlingCancel`, + `gesturePinchBegin`, `gesturePinchEnd`, `gesturePinchUpdate`, + `gestureTapDown`, `gestureShowPress`, `gestureTap`, `gestureTapCancel`, + `gestureShortPress`, `gestureLongPress`, `gestureLongTap`, + `gestureTwoFingerTap`, `gestureTapUnconfirmed`, `gestureDoubleTap`, + `touchStart`, `touchMove`, `touchEnd`, `touchCancel`, `touchScrollStarted`, + `pointerDown`, `pointerUp`, `pointerMove`, `pointerRawUpdate`, + `pointerCancel` or `pointerCausedUaAction`. * `modifiers` string[] (optional) - An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`, `meta`, `command`, `cmd`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, diff --git a/docs/api/structures/io-counters.md b/docs/api/structures/io-counters.md deleted file mode 100644 index 23a6883b07f52..0000000000000 --- a/docs/api/structures/io-counters.md +++ /dev/null @@ -1,8 +0,0 @@ -# IOCounters Object - -* `readOperationCount` number - The number of I/O read operations. -* `writeOperationCount` number - The number of I/O write operations. -* `otherOperationCount` number - Then number of I/O other operations. -* `readTransferCount` number - The number of I/O read transfers. -* `writeTransferCount` number - The number of I/O write transfers. -* `otherTransferCount` number - Then number of I/O other transfers. diff --git a/docs/api/structures/ipc-main-event.md b/docs/api/structures/ipc-main-event.md index 868fe4d0fb54e..2bf1e84affe84 100644 --- a/docs/api/structures/ipc-main-event.md +++ b/docs/api/structures/ipc-main-event.md @@ -3,9 +3,9 @@ * `processId` Integer - The internal ID of the renderer process that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message * `returnValue` any - Set this to the value to be returned in a synchronous message -* `sender` WebContents - Returns the `webContents` that sent the message -* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message -* `ports` MessagePortMain[] - A list of MessagePorts that were transferred with this message +* `sender` [WebContents](../web-contents.md) - Returns the `webContents` that sent the message +* `senderFrame` [WebFrameMain](../web-frame-main.md) | null _Readonly_ - The frame that sent this message. May be `null` if accessed after the frame has either navigated or been destroyed. +* `ports` [MessagePortMain](../message-port-main.md)[] - A list of MessagePorts that were transferred with this message * `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame. * `channel` string * `...args` any[] diff --git a/docs/api/structures/ipc-main-invoke-event.md b/docs/api/structures/ipc-main-invoke-event.md index d15f44df40685..b5c9e20438f0c 100644 --- a/docs/api/structures/ipc-main-invoke-event.md +++ b/docs/api/structures/ipc-main-invoke-event.md @@ -2,5 +2,5 @@ * `processId` Integer - The internal ID of the renderer process that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message -* `sender` WebContents - Returns the `webContents` that sent the message -* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message +* `sender` [WebContents](../web-contents.md) - Returns the `webContents` that sent the message +* `senderFrame` [WebFrameMain](../web-frame-main.md) | null _Readonly_ - The frame that sent this message. May be `null` if accessed after the frame has either navigated or been destroyed. diff --git a/docs/api/structures/ipc-renderer-event.md b/docs/api/structures/ipc-renderer-event.md index 1ac2def46d4aa..135834f2098d8 100644 --- a/docs/api/structures/ipc-renderer-event.md +++ b/docs/api/structures/ipc-renderer-event.md @@ -1,7 +1,6 @@ # IpcRendererEvent Object extends `Event` -* `sender` IpcRenderer - The `IpcRenderer` instance that emitted the event originally -* `senderId` Integer - The `webContents.id` that sent the message, you can call `event.sender.sendTo(event.senderId, ...)` to reply to the message, see [ipcRenderer.sendTo][ipc-renderer-sendto] for more information. This only applies to messages sent from a different renderer. Messages sent directly from the main process set `event.senderId` to `0`. -* `ports` MessagePort[] - A list of MessagePorts that were transferred with this message +* `sender` [IpcRenderer](../ipc-renderer.md) - The `IpcRenderer` instance that emitted the event originally +* `ports` [MessagePort][][] - A list of MessagePorts that were transferred with this message -[ipc-renderer-sendto]: ../ipc-renderer.md#ipcrenderersendtowebcontentsid-channel-args +[MessagePort]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort diff --git a/docs/api/structures/keyboard-input-event.md b/docs/api/structures/keyboard-input-event.md index de7bef2d770f6..3f8b4b5e8d3af 100644 --- a/docs/api/structures/keyboard-input-event.md +++ b/docs/api/structures/keyboard-input-event.md @@ -1,6 +1,6 @@ # KeyboardInputEvent Object extends `InputEvent` -* `type` string - The type of the event, can be `keyDown`, `keyUp` or `char`. +* `type` string - The type of the event, can be `rawKeyDown`, `keyDown`, `keyUp` or `char`. * `keyCode` string - The character that will be sent as the keyboard event. Should only use the valid key codes in [Accelerator](../accelerator.md). diff --git a/docs/api/structures/media-access-permission-request.md b/docs/api/structures/media-access-permission-request.md new file mode 100644 index 0000000000000..6a9cca661adbf --- /dev/null +++ b/docs/api/structures/media-access-permission-request.md @@ -0,0 +1,5 @@ +# MediaAccessPermissionRequest Object extends `PermissionRequest` + +* `securityOrigin` string (optional) - The security origin of the request. +* `mediaTypes` string[] (optional) - The types of media access being requested - elements can be `video` + or `audio`. diff --git a/docs/api/structures/navigation-entry.md b/docs/api/structures/navigation-entry.md new file mode 100644 index 0000000000000..6d1cd6734d13c --- /dev/null +++ b/docs/api/structures/navigation-entry.md @@ -0,0 +1,4 @@ +# NavigationEntry Object + +* `url` string +* `title` string diff --git a/docs/api/structures/notification-response.md b/docs/api/structures/notification-response.md index 32fff8625e1c5..eb5f1882a5d21 100644 --- a/docs/api/structures/notification-response.md +++ b/docs/api/structures/notification-response.md @@ -3,5 +3,5 @@ * `actionIdentifier` string - The identifier string of the action that the user selected. * `date` number - The delivery date of the notification. * `identifier` string - The unique identifier for this notification request. -* `userInfo` Record<string, any> - A dictionary of custom information associated with the notification. +* `userInfo` Record\<string, any\> - A dictionary of custom information associated with the notification. * `userText` string (optional) - The text entered or chosen by the user. diff --git a/docs/api/structures/offscreen-shared-texture.md b/docs/api/structures/offscreen-shared-texture.md new file mode 100644 index 0000000000000..0de21db13397d --- /dev/null +++ b/docs/api/structures/offscreen-shared-texture.md @@ -0,0 +1,24 @@ +# OffscreenSharedTexture Object + +* `textureInfo` Object - The shared texture info. + * `widgetType` string - The widget type of the texture. Can be `popup` or `frame`. + * `pixelFormat` string - The pixel format of the texture. Can be `rgba` or `bgra`. + * `codedSize` [Size](size.md) - The full dimensions of the video frame. + * `visibleRect` [Rectangle](rectangle.md) - A subsection of [0, 0, codedSize.width(), codedSize.height()]. In OSR case, it is expected to have the full section area. + * `contentRect` [Rectangle](rectangle.md) - The region of the video frame that capturer would like to populate. In OSR case, it is the same with `dirtyRect` that needs to be painted. + * `timestamp` number - The time in microseconds since the capture start. + * `metadata` Object - Extra metadata. See comments in src\media\base\video_frame_metadata.h for accurate details. + * `captureUpdateRect` [Rectangle](rectangle.md) (optional) - Updated area of frame, can be considered as the `dirty` area. + * `regionCaptureRect` [Rectangle](rectangle.md) (optional) - May reflect the frame's contents origin if region capture is used internally. + * `sourceSize` [Rectangle](rectangle.md) (optional) - Full size of the source frame. + * `frameCount` number (optional) - The increasing count of captured frame. May contain gaps if frames are dropped between two consecutively received frames. + * `sharedTextureHandle` Buffer _Windows_ _macOS_ - The handle to the shared texture. + * `planes` Object[] _Linux_ - Each plane's info of the shared texture. + * `stride` number - The strides and offsets in bytes to be used when accessing the buffers via a memory mapping. One per plane per entry. + * `offset` number - The strides and offsets in bytes to be used when accessing the buffers via a memory mapping. One per plane per entry. + * `size` number - Size in bytes of the plane. This is necessary to map the buffers. + * `fd` number - File descriptor for the underlying memory object (usually dmabuf). + * `modifier` string _Linux_ - The modifier is retrieved from GBM library and passed to EGL driver. +* `release` Function - Release the resources. The `texture` cannot be directly passed to another process, users need to maintain texture lifecycles in + main process, but it is safe to pass the `textureInfo` to another process. Only a limited number of textures can exist at the same time, so it's important + that you call `texture.release()` as soon as you're done with the texture. diff --git a/docs/api/structures/open-external-permission-request.md b/docs/api/structures/open-external-permission-request.md new file mode 100644 index 0000000000000..d7b7f68fc9cfc --- /dev/null +++ b/docs/api/structures/open-external-permission-request.md @@ -0,0 +1,3 @@ +# OpenExternalPermissionRequest Object extends `PermissionRequest` + +* `externalURL` string (optional) - The url of the `openExternal` request. diff --git a/docs/api/structures/permission-request.md b/docs/api/structures/permission-request.md new file mode 100644 index 0000000000000..4858f84a324ce --- /dev/null +++ b/docs/api/structures/permission-request.md @@ -0,0 +1,4 @@ +# PermissionRequest Object + +* `requestingUrl` string - The last URL the requesting frame loaded. +* `isMainFrame` boolean - Whether the frame making the request is the main frame. diff --git a/docs/api/structures/preload-script-registration.md b/docs/api/structures/preload-script-registration.md new file mode 100644 index 0000000000000..011d034f08847 --- /dev/null +++ b/docs/api/structures/preload-script-registration.md @@ -0,0 +1,6 @@ +# PreloadScriptRegistration Object + +* `type` string - Context type where the preload script will be executed. + Possible values include `frame`. +* `id` string (optional) - Unique ID of preload script. Defaults to a random UUID. +* `filePath` string - Path of the script file. Must be an absolute path. diff --git a/docs/api/structures/preload-script.md b/docs/api/structures/preload-script.md new file mode 100644 index 0000000000000..c75ead5217f98 --- /dev/null +++ b/docs/api/structures/preload-script.md @@ -0,0 +1,6 @@ +# PreloadScript Object + +* `type` string - Context type where the preload script will be executed. + Possible values include `frame`. +* `id` string - Unique ID of preload script. +* `filePath` string - Path of the script file. Must be an absolute path. diff --git a/docs/api/structures/printer-info.md b/docs/api/structures/printer-info.md index 716759a6dddd7..5910dca8fcfb9 100644 --- a/docs/api/structures/printer-info.md +++ b/docs/api/structures/printer-info.md @@ -7,14 +7,14 @@ * `isDefault` boolean - whether or not a given printer is set as the default printer on the OS. * `options` Object - an object containing a variable number of platform-specific printer information. -The number represented by `status` means different things on different platforms: on Windows its potential values can be found [here](https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-info-2), and on Linux and macOS they can be found [here](https://www.cups.org/doc/cupspm.html). +The number represented by `status` means different things on different platforms: on Windows its potential values can be found [here](https://learn.microsoft.com/en-us/windows/win32/printdocs/printer-info-2), and on Linux and macOS they can be found [here](https://www.cups.org/doc/cupspm.html). ## Example Below is an example of some of the additional options that may be set which may be different on each platform. -```javascript +```js { name: 'Austin_4th_Floor_Printer___C02XK13BJHD4', displayName: 'Austin 4th Floor Printer @ C02XK13BJHD4', diff --git a/docs/api/structures/product.md b/docs/api/structures/product.md index d37a57771fd56..5268e4f336fa8 100644 --- a/docs/api/structures/product.md +++ b/docs/api/structures/product.md @@ -3,8 +3,6 @@ * `productIdentifier` string - The string that identifies the product to the Apple App Store. * `localizedDescription` string - A description of the product. * `localizedTitle` string - The name of the product. -* `contentVersion` string - A string that identifies the version of the content. -* `contentLengths` number[] - The total size of the content, in bytes. * `price` number - The cost of the product in the local currency. * `formattedPrice` string - The locale formatted price of the product. * `currencyCode` string - 3 character code presenting a product's currency based on the ISO 4217 standard. diff --git a/docs/api/structures/protocol-request.md b/docs/api/structures/protocol-request.md index aacc062f9996f..586a64bba9dfe 100644 --- a/docs/api/structures/protocol-request.md +++ b/docs/api/structures/protocol-request.md @@ -4,4 +4,4 @@ * `referrer` string * `method` string * `uploadData` [UploadData[]](upload-data.md) (optional) -* `headers` Record<string, string> +* `headers` Record\<string, string\> diff --git a/docs/api/structures/protocol-response.md b/docs/api/structures/protocol-response.md index 21a863240fabb..6739ca77fbd5d 100644 --- a/docs/api/structures/protocol-response.md +++ b/docs/api/structures/protocol-response.md @@ -10,7 +10,7 @@ `"text/html"`. Setting `mimeType` would implicitly set the `content-type` header in response, but if `content-type` is already set in `headers`, the `mimeType` would be ignored. -* `headers` Record<string, string | string[]> (optional) - An object containing the response headers. The +* `headers` Record\<string, string | string[]\> (optional) - An object containing the response headers. The keys must be string, and values must be either string or Array of string. * `data` (Buffer | string | ReadableStream) (optional) - The response body. When returning stream as response, this is a Node.js readable stream representing diff --git a/docs/api/structures/proxy-config.md b/docs/api/structures/proxy-config.md new file mode 100644 index 0000000000000..eb68d37e651ac --- /dev/null +++ b/docs/api/structures/proxy-config.md @@ -0,0 +1,86 @@ +# ProxyConfig Object + +* `mode` string (optional) - The proxy mode. Should be one of `direct`, +`auto_detect`, `pac_script`, `fixed_servers` or `system`. +Defaults to `pac_script` proxy mode if `pacScript` option is specified +otherwise defaults to `fixed_servers`. + * `direct` - In direct mode all connections are created directly, without any proxy involved. + * `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can + be downloaded at http://wpad/wpad.dat. + * `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is + retrieved from the URL specified in the `pacScript`. This is the default mode if `pacScript` is specified. + * `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`. + This is the default mode if `proxyRules` is specified. + * `system` - In system mode the proxy configuration is taken from the operating system. + Note that the system mode is different from setting no proxy configuration. + In the latter case, Electron falls back to the system settings only if no + command-line options influence the proxy configuration. +* `pacScript` string (optional) - The URL associated with the PAC file. +* `proxyRules` string (optional) - Rules indicating which proxies to use. +* `proxyBypassRules` string (optional) - Rules indicating which URLs should +bypass the proxy settings. + +When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules` +option is ignored and `pacScript` configuration is applied. + +The `proxyRules` has to follow the rules below: + +```sh +proxyRules = schemeProxies[";"<schemeProxies>] +schemeProxies = [<urlScheme>"="]<proxyURIList> +urlScheme = "http" | "https" | "ftp" | "socks" +proxyURIList = <proxyURL>[","<proxyURIList>] +proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>] +``` + +For example: + +* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and + HTTP proxy `foopy2:80` for `ftp://` URLs. +* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. +* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing + over to `bar` if `foopy:80` is unavailable, and after that using no proxy. +* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. +* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail + over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. +* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no + proxy if `foopy` is unavailable. +* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use + `socks4://foopy2` for all other URLs. + +The `proxyBypassRules` is a comma separated list of rules described below: + +* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` + + Match all hostnames that match the pattern HOSTNAME_PATTERN. + + Examples: + "foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99", + "https://x.\*.y.com:99" + +* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` + + Match a particular domain suffix. + + Examples: + ".google.com", ".com", "http://.google.com" + +* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` + + Match URLs which are IP address literals. + + Examples: + "127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99" + +* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` + + Match any URL that is to an IP literal that falls between the + given range. IP range is specified using CIDR notation. + + Examples: + "192.168.1.1/16", "fefe:13::abc/33". + +* `<local>` + + Match local addresses. The meaning of `<local>` is whether the + host matches one of: "127.0.0.1", "::1", "localhost". diff --git a/docs/api/structures/render-process-gone-details.md b/docs/api/structures/render-process-gone-details.md new file mode 100644 index 0000000000000..e48800a5b87d7 --- /dev/null +++ b/docs/api/structures/render-process-gone-details.md @@ -0,0 +1,13 @@ +# RenderProcessGoneDetails Object + +* `reason` string - The reason the render process is gone. Possible values: + * `clean-exit` - Process exited with an exit code of zero + * `abnormal-exit` - Process exited with a non-zero exit code + * `killed` - Process was sent a SIGTERM or otherwise killed externally + * `crashed` - Process crashed + * `oom` - Process ran out of memory + * `launch-failed` - Process never successfully launched + * `integrity-failure` - Windows code integrity checks failed +* `exitCode` Integer - The exit code of the process, unless `reason` is + `launch-failed`, in which case `exitCode` will be a platform-specific + launch failure error code. diff --git a/docs/api/structures/resolved-endpoint.md b/docs/api/structures/resolved-endpoint.md new file mode 100644 index 0000000000000..0847429f04129 --- /dev/null +++ b/docs/api/structures/resolved-endpoint.md @@ -0,0 +1,7 @@ +# ResolvedEndpoint Object + +* `address` string +* `family` string - One of the following: + * `ipv4` - Corresponds to `AF_INET` + * `ipv6` - Corresponds to `AF_INET6` + * `unspec` - Corresponds to `AF_UNSPEC` diff --git a/docs/api/structures/resolved-host.md b/docs/api/structures/resolved-host.md new file mode 100644 index 0000000000000..43c577f1fb003 --- /dev/null +++ b/docs/api/structures/resolved-host.md @@ -0,0 +1,3 @@ +# ResolvedHost Object + +* `endpoints` [ResolvedEndpoint[]](resolved-endpoint.md) - resolved DNS entries for the hostname diff --git a/docs/api/structures/serial-port.md b/docs/api/structures/serial-port.md index 052b961141c29..21d607c8827b6 100644 --- a/docs/api/structures/serial-port.md +++ b/docs/api/structures/serial-port.md @@ -2,9 +2,9 @@ * `portId` string - Unique identifier for the port. * `portName` string - Name of the port. -* `displayName` string - A string suitable for display to the user for describing this device. -* `vendorId` string - Optional USB vendor ID. -* `productId` string - Optional USB product ID. -* `serialNumber` string - The USB device serial number. -* `usbDriverName` string (optional) - Represents a single serial port on macOS can be enumerated by multiple drivers. -* `deviceInstanceId` string (optional) - A stable identifier on Windows that can be used for device permissions. +* `displayName` string (optional) - A string suitable for display to the user for describing this device. +* `vendorId` string (optional) - The USB vendor ID. +* `productId` string (optional) - The USB product ID. +* `serialNumber` string (optional) - The USB device serial number. +* `usbDriverName` string (optional) _macOS_ - Represents a single serial port on macOS can be enumerated by multiple drivers. +* `deviceInstanceId` string (optional) _Windows_ - A stable identifier on Windows that can be used for device permissions. diff --git a/docs/api/structures/service-worker-info.md b/docs/api/structures/service-worker-info.md index 37dd691d96243..c1192a6ccdce3 100644 --- a/docs/api/structures/service-worker-info.md +++ b/docs/api/structures/service-worker-info.md @@ -3,3 +3,4 @@ * `scriptUrl` string - The full URL to the script that this service worker runs * `scope` string - The base URL that this service worker is active for. * `renderProcessId` number - The virtual ID of the process that this service worker is running in. This is not an OS level PID. This aligns with the ID set used for `webContents.getProcessId()`. +* `versionId` number - ID of the service worker version diff --git a/docs/api/structures/shared-dictionary-info.md b/docs/api/structures/shared-dictionary-info.md new file mode 100644 index 0000000000000..09710d5fd6fad --- /dev/null +++ b/docs/api/structures/shared-dictionary-info.md @@ -0,0 +1,12 @@ +# SharedDictionaryInfo Object + +* `match` string - The matching path pattern for the dictionary which was declared in 'use-as-dictionary' response header's `match` option. +* `matchDestinations` string[] - An array of matching destinations for the dictionary which was declared in 'use-as-dictionary' response header's `match-dest` option. +* `id` string - The Id for the dictionary which was declared in 'use-as-dictionary' response header's `id` option. +* `dictionaryUrl` string - URL of the dictionary. +* `lastFetchTime` Date - The time of when the dictionary was received from the network layer. +* `responseTime` Date - The time of when the dictionary was received from the server. For cached responses, this time could be "far" in the past. +* `expirationDuration` number - The expiration time for the dictionary which was declared in 'use-as-dictionary' response header's `expires` option in seconds. +* `lastUsedTime` Date - The time when the dictionary was last used. +* `size` number - The amount of bytes stored for this shared dictionary information object in Chromium's internal storage (usually Sqlite). +* `hash` string - The sha256 hash of the dictionary binary. diff --git a/docs/api/structures/shared-dictionary-usage-info.md b/docs/api/structures/shared-dictionary-usage-info.md new file mode 100644 index 0000000000000..c0b9217d1878c --- /dev/null +++ b/docs/api/structures/shared-dictionary-usage-info.md @@ -0,0 +1,5 @@ +# SharedDictionaryUsageInfo Object + +* `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. +* `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. +* `totalSizeBytes` number - The amount of bytes stored for this shared dictionary information object in Chromium's internal storage (usually Sqlite). diff --git a/docs/api/structures/trace-config.md b/docs/api/structures/trace-config.md index 4160b7121ca57..2f33aec0a00f8 100644 --- a/docs/api/structures/trace-config.md +++ b/docs/api/structures/trace-config.md @@ -7,8 +7,8 @@ recording buffer in events. * `enable_argument_filter` boolean (optional) - if true, filter event data according to a specific list of events that have been manually vetted to not - include any PII. See [the implementation in - Chromium][trace_event_args_allowlist.cc] for specifics. + include any PII. See [the implementation in Chromium][trace_event_args_allowlist.cc] + for specifics. * `included_categories` string[] (optional) - a list of tracing categories to include. Can include glob-like patterns using `*` at the end of the category name. See [tracing categories][] for the list of categories. @@ -19,10 +19,10 @@ include in the trace. If not specified, trace all processes. * `histogram_names` string[] (optional) - a list of [histogram][] names to report with the trace. -* `memory_dump_config` Record<string, any> (optional) - if the +* `memory_dump_config` Record\<string, any\> (optional) - if the `disabled-by-default-memory-infra` category is enabled, this contains - optional additional configuration for data collection. See the [Chromium - memory-infra docs][memory-infra docs] for more information. + optional additional configuration for data collection. See the + [Chromium memory-infra docs][memory-infra docs] for more information. An example TraceConfig that roughly matches what Chrome DevTools records: diff --git a/docs/api/structures/upload-file.md b/docs/api/structures/upload-file.md index 8361cd3e91dc4..a3f31b13c8d34 100644 --- a/docs/api/structures/upload-file.md +++ b/docs/api/structures/upload-file.md @@ -2,8 +2,8 @@ * `type` 'file' - `file`. * `filePath` string - Path of file to be uploaded. -* `offset` Integer - Defaults to `0`. -* `length` Integer - Number of bytes to read from `offset`. +* `offset` Integer (optional) - Defaults to `0`. +* `length` Integer (optional) - Number of bytes to read from `offset`. Defaults to `0`. -* `modificationTime` Double - Last Modification time in - number of seconds since the UNIX epoch. +* `modificationTime` Double (optional) - Last Modification time in + number of seconds since the UNIX epoch. Defaults to `0`. diff --git a/docs/api/structures/usb-device.md b/docs/api/structures/usb-device.md new file mode 100644 index 0000000000000..e1f427fb4edbf --- /dev/null +++ b/docs/api/structures/usb-device.md @@ -0,0 +1,17 @@ +# USBDevice Object + +* `deviceId` string - Unique identifier for the device. +* `vendorId` Integer - The USB vendor ID. +* `productId` Integer - The USB product ID. +* `productName` string (optional) - Name of the device. +* `serialNumber` string (optional) - The USB device serial number. +* `manufacturerName` string (optional) - The manufacturer name of the device. +* `usbVersionMajor` Integer - The USB protocol major version supported by the device +* `usbVersionMinor` Integer - The USB protocol minor version supported by the device +* `usbVersionSubminor` Integer - The USB protocol subminor version supported by the device +* `deviceClass` Integer - The device class for the communication interface supported by the device +* `deviceSubclass` Integer - The device subclass for the communication interface supported by the device +* `deviceProtocol` Integer - The device protocol for the communication interface supported by the device +* `deviceVersionMajor` Integer - The major version number of the device as defined by the device manufacturer. +* `deviceVersionMinor` Integer - The minor version number of the device as defined by the device manufacturer. +* `deviceVersionSubminor` Integer - The subminor version number of the device as defined by the device manufacturer. diff --git a/docs/api/structures/user-default-types.md b/docs/api/structures/user-default-types.md index cdca5cdc7257e..f11d43474bba1 100644 --- a/docs/api/structures/user-default-types.md +++ b/docs/api/structures/user-default-types.md @@ -9,4 +9,4 @@ * `array` Array\<unknown> * `dictionary` Record\<string, unknown> -This type is a helper alias, no object will never exist of this type. +This type is a helper alias, no object will ever exist of this type. diff --git a/docs/api/structures/web-preferences.md b/docs/api/structures/web-preferences.md new file mode 100644 index 0000000000000..414d9c6c3b027 --- /dev/null +++ b/docs/api/structures/web-preferences.md @@ -0,0 +1,153 @@ +# WebPreferences Object + +* `devTools` boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. +* `nodeIntegration` boolean (optional) - Whether node integration is enabled. + Default is `false`. +* `nodeIntegrationInWorker` boolean (optional) - Whether node integration is + enabled in web workers. Default is `false`. More about this can be found + in [Multithreading](../../tutorial/multithreading.md). +* `nodeIntegrationInSubFrames` boolean (optional) - Experimental option for + enabling Node.js support in sub-frames such as iframes and child windows. All your preloads will load for + every iframe, you can use `process.isMainFrame` to determine if you are + in the main frame or not. +* `preload` string (optional) - Specifies a script that will be loaded before other + scripts run in the page. This script will always have access to node APIs + no matter whether node integration is turned on or off. The value should + be the absolute file path to the script. + When node integration is turned off, the preload script can reintroduce + Node global symbols back to the global scope. See example + [here](../context-bridge.md#exposing-node-global-symbols). +* `sandbox` boolean (optional) - If set, this will sandbox the renderer + associated with the window, making it compatible with the Chromium + OS-level sandbox and disabling the Node.js engine. This is not the same as + the `nodeIntegration` option and the APIs available to the preload script + are more limited. Read more about the option [here](../../tutorial/sandbox.md). +* `session` [Session](../session.md#class-session) (optional) - Sets the session used by the + page. Instead of passing the Session object directly, you can also choose to + use the `partition` option instead, which accepts a partition string. When + both `session` and `partition` are provided, `session` will be preferred. + Default is the default session. +* `partition` string (optional) - Sets the session used by the page according to the + session's partition string. If `partition` starts with `persist:`, the page + will use a persistent session available to all pages in the app with the + same `partition`. If there is no `persist:` prefix, the page will use an + in-memory session. By assigning the same `partition`, multiple pages can share + the same session. Default is the default session. +* `zoomFactor` number (optional) - The default zoom factor of the page, `3.0` represents + `300%`. Default is `1.0`. +* `javascript` boolean (optional) - Enables JavaScript support. Default is `true`. +* `webSecurity` boolean (optional) - When `false`, it will disable the + same-origin policy (usually using testing websites by people), and set + `allowRunningInsecureContent` to `true` if this options has not been set + by user. Default is `true`. +* `allowRunningInsecureContent` boolean (optional) - Allow an https page to run + JavaScript, CSS or plugins from http URLs. Default is `false`. +* `images` boolean (optional) - Enables image support. Default is `true`. +* `imageAnimationPolicy` string (optional) - Specifies how to run image animations (E.g. GIFs). Can be `animate`, `animateOnce` or `noAnimation`. Default is `animate`. +* `textAreasAreResizable` boolean (optional) - Make TextArea elements resizable. Default + is `true`. +* `webgl` boolean (optional) - Enables WebGL support. Default is `true`. +* `plugins` boolean (optional) - Whether plugins should be enabled. Default is `false`. +* `experimentalFeatures` boolean (optional) - Enables Chromium's experimental features. + Default is `false`. +* `scrollBounce` boolean (optional) _macOS_ - Enables scroll bounce + (rubber banding) effect on macOS. Default is `false`. +* `enableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, like + `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature + strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] + file. +* `disableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, + like `CSSVariables,KeyboardEventKey` to disable. The full list of supported + feature strings can be found in the + [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. +* `defaultFontFamily` Object (optional) - Sets the default font for the font-family. + * `standard` string (optional) - Defaults to `Times New Roman`. + * `serif` string (optional) - Defaults to `Times New Roman`. + * `sansSerif` string (optional) - Defaults to `Arial`. + * `monospace` string (optional) - Defaults to `Courier New`. + * `cursive` string (optional) - Defaults to `Script`. + * `fantasy` string (optional) - Defaults to `Impact`. + * `math` string (optional) - Defaults to `Latin Modern Math`. +* `defaultFontSize` Integer (optional) - Defaults to `16`. +* `defaultMonospaceFontSize` Integer (optional) - Defaults to `13`. +* `minimumFontSize` Integer (optional) - Defaults to `0`. +* `defaultEncoding` string (optional) - Defaults to `ISO-8859-1`. +* `backgroundThrottling` boolean (optional) - Whether to throttle animations and timers + when the page becomes background. This also affects the + [Page Visibility API](../browser-window.md#page-visibility). When at least one + [webContents](../web-contents.md) displayed in a single + [browserWindow](../browser-window.md) has disabled `backgroundThrottling` then + frames will be drawn and swapped for the whole window and other + [webContents](../web-contents.md) displayed by it. Defaults to `true`. +* `offscreen` Object | boolean (optional) - Whether to enable offscreen rendering for the browser + window. Defaults to `false`. See the + [offscreen rendering tutorial](../../tutorial/offscreen-rendering.md) for + more details. + * `useSharedTexture` boolean (optional) _Experimental_ - Whether to use GPU shared texture for accelerated + paint event. Defaults to `false`. See the + [offscreen rendering tutorial](../../tutorial/offscreen-rendering.md) for + more details. +* `contextIsolation` boolean (optional) - Whether to run Electron APIs and + the specified `preload` script in a separate JavaScript context. Defaults + to `true`. The context that the `preload` script runs in will only have + access to its own dedicated `document` and `window` globals, as well as + its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.), + which are all invisible to the loaded content. The Electron API will only + be available in the `preload` script and not the loaded page. This option + should be used when loading potentially untrusted remote content to ensure + the loaded content cannot tamper with the `preload` script and any + Electron APIs being used. This option uses the same technique used by + [Chrome Content Scripts][chrome-content-scripts]. You can access this + context in the dev tools by selecting the 'Electron Isolated Context' + entry in the combo box at the top of the Console tab. +* `webviewTag` boolean (optional) - Whether to enable the [`<webview>` tag](../webview-tag.md). + Defaults to `false`. **Note:** The + `preload` script configured for the `<webview>` will have node integration + enabled when it is executed so you should ensure remote/untrusted content + is not able to create a `<webview>` tag with a possibly malicious `preload` + script. You can use the `will-attach-webview` event on [webContents](../web-contents.md) + to strip away the `preload` script and to validate or alter the + `<webview>`'s initial settings. +* `additionalArguments` string[] (optional) - A list of strings that will be appended + to `process.argv` in the renderer process of this app. Useful for passing small + bits of data down to renderer process preload scripts. +* `safeDialogs` boolean (optional) - Whether to enable browser style + consecutive dialog protection. Default is `false`. +* `safeDialogsMessage` string (optional) - The message to display when + consecutive dialog protection is triggered. If not defined the default + message would be used, note that currently the default message is in + English and not localized. +* `disableDialogs` boolean (optional) - Whether to disable dialogs + completely. Overrides `safeDialogs`. Default is `false`. +* `navigateOnDragDrop` boolean (optional) - Whether dragging and dropping a + file or link onto the page causes a navigation. Default is `false`. +* `autoplayPolicy` string (optional) - Autoplay policy to apply to + content in the window, can be `no-user-gesture-required`, + `user-gesture-required`, `document-user-activation-required`. Defaults to + `no-user-gesture-required`. +* `disableHtmlFullscreenWindowResize` boolean (optional) - Whether to + prevent the window from resizing when entering HTML Fullscreen. Default + is `false`. +* `accessibleTitle` string (optional) - An alternative title string provided only + to accessibility tools such as screen readers. This string is not directly + visible to users. +* `spellcheck` boolean (optional) - Whether to enable the builtin spellchecker. + Default is `true`. +* `enableWebSQL` boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/). + Default is `true`. +* `v8CacheOptions` string (optional) - Enforces the v8 code caching policy + used by blink. Accepted values are + * `none` - Disables code caching + * `code` - Heuristic based code caching + * `bypassHeatCheck` - Bypass code caching heuristics but with lazy compilation + * `bypassHeatCheckAndEagerCompile` - Same as above except compilation is eager. + Default policy is `code`. +* `enablePreferredSizeMode` boolean (optional) - Whether to enable + preferred size mode. The preferred size is the minimum size needed to + contain the layout of the document—without requiring scrolling. Enabling + this will cause the `preferred-size-changed` event to be emitted on the + `WebContents` when the preferred size changes. Default is `false`. +* `transparent` boolean (optional) - Whether to enable background transparency for the guest page. Default is `true`. **Note:** The guest page's text and background colors are derived from the [color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) of its root element. When transparency is enabled, the text color will still change accordingly but the background will remain transparent. + +[chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment +[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5 diff --git a/docs/api/structures/web-request-filter.md b/docs/api/structures/web-request-filter.md index ae54cea7bfc08..13a70663dd4b8 100644 --- a/docs/api/structures/web-request-filter.md +++ b/docs/api/structures/web-request-filter.md @@ -1,3 +1,4 @@ # WebRequestFilter Object -* `urls` string[] - Array of URL patterns that will be used to filter out the requests that do not match the URL patterns. +* `urls` string[] - Array of [URL patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) that will be used to filter out the requests that do not match the URL patterns. +* `types` String[] (optional) - Array of types that will be used to filter out the requests that do not match the types. When not specified, all types will be matched. Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media` or `webSocket`. diff --git a/docs/api/structures/window-open-handler-response.md b/docs/api/structures/window-open-handler-response.md new file mode 100644 index 0000000000000..6ea1c99628156 --- /dev/null +++ b/docs/api/structures/window-open-handler-response.md @@ -0,0 +1,7 @@ +# WindowOpenHandlerResponse Object + +* `action` string - Can be `allow` or `deny`. Controls whether new window should be created. +* `overrideBrowserWindowOptions` BrowserWindowConstructorOptions (optional) - Allows customization of the created window. +* `outlivesOpener` boolean (optional) - By default, child windows are closed when their opener is closed. This can be + changed by specifying `outlivesOpener: true`, in which case the opened window will not be closed when its opener is closed. +* `createWindow` (options: BrowserWindowConstructorOptions) => WebContents (optional) - If specified, will be called instead of `new BrowserWindow` to create the new child window and event [`did-create-window`](../web-contents.md#event-did-create-window) will not be emitted. Constructed child window should use passed `options` object. This can be used for example to have the new window open as a BrowserView instead of in a separate window. diff --git a/docs/api/structures/window-session-end-event.md b/docs/api/structures/window-session-end-event.md new file mode 100644 index 0000000000000..a5a062b6b4495 --- /dev/null +++ b/docs/api/structures/window-session-end-event.md @@ -0,0 +1,7 @@ +# WindowSessionEndEvent Object extends `Event` + +* `reasons` string[] - List of reasons for shutdown. Can be 'shutdown', 'close-app', 'critical', or 'logoff'. + +Unfortunately, Windows does not offer a way to differentiate between a shutdown and a reboot, meaning the 'shutdown' +reason is triggered in both scenarios. For more details on the `WM_ENDSESSION` message and its associated reasons, +refer to the [MSDN documentation](https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-endsession). diff --git a/docs/api/synopsis.md b/docs/api/synopsis.md deleted file mode 100644 index 667c1dcd35a4d..0000000000000 --- a/docs/api/synopsis.md +++ /dev/null @@ -1,93 +0,0 @@ -# Synopsis - -> How to use Node.js and Electron APIs. - -All of [Node.js's built-in modules](https://nodejs.org/api/) are available in -Electron and third-party node modules also fully supported as well (including -the [native modules](../tutorial/using-native-node-modules.md)). - -Electron also provides some extra built-in modules for developing native -desktop applications. Some modules are only available in the main process, some -are only available in the renderer process (web page), and some can be used in -either process type. - -The basic rule is: if a module is [GUI][gui] or low-level system related, then -it should be only available in the main process. You need to be familiar with -the concept of main process vs. renderer process -scripts to be able to use those modules. - -The main process script is like a normal Node.js script: - -```javascript -const { app, BrowserWindow } = require('electron') -let win = null - -app.whenReady().then(() => { - win = new BrowserWindow({ width: 800, height: 600 }) - win.loadURL('https://github.com') -}) -``` - -The renderer process is no different than a normal web page, except for the -extra ability to use node modules if `nodeIntegration` is enabled: - -```html -<!DOCTYPE html> -<html> -<body> -<script> - const fs = require('fs') - console.log(fs.readFileSync(__filename, 'utf8')) -</script> -</body> -</html> -``` - -## Destructuring assignment - -As of 0.37, you can use -[destructuring assignment][destructuring-assignment] to make it easier to use -built-in modules. - -```javascript -const { app, BrowserWindow } = require('electron') - -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -If you need the entire `electron` module, you can require it and then using -destructuring to access the individual modules from `electron`. - -```javascript -const electron = require('electron') -const { app, BrowserWindow } = electron - -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -This is equivalent to the following code: - -```javascript -const electron = require('electron') -const app = electron.app -const BrowserWindow = electron.BrowserWindow -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface -[destructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 6c0a6a388fb46..ad6f72007aa59 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -2,11 +2,11 @@ > Get system preferences. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process) -```javascript +```js const { systemPreferences } = require('electron') -console.log(systemPreferences.isDarkMode()) +console.log(systemPreferences.isAeroGlassEnabled()) ``` ## Events @@ -27,32 +27,8 @@ Returns: * `event` Event -### Event: 'inverted-color-scheme-changed' _Windows_ _Deprecated_ - -Returns: - -* `event` Event -* `invertedColorScheme` boolean - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is being used, `false` otherwise. - -**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module. - -### Event: 'high-contrast-color-scheme-changed' _Windows_ _Deprecated_ - -Returns: - -* `event` Event -* `highContrastColorScheme` boolean - `true` if a high contrast theme is being used, `false` otherwise. - -**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module. - ## Methods -### `systemPreferences.isDarkMode()` _macOS_ _Windows_ _Deprecated_ - -Returns `boolean` - Whether the system is in Dark Mode. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseDarkColors`](native-theme.md#nativethemeshouldusedarkcolors-readonly) API. - ### `systemPreferences.isSwipeTrackingFromScrollEventsEnabled()` _macOS_ Returns `boolean` - Whether the Swipe between pages setting is on. @@ -60,7 +36,7 @@ Returns `boolean` - Whether the Swipe between pages setting is on. ### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_ * `event` string -* `userInfo` Record<string, any> +* `userInfo` Record\<string, any\> * `deliverImmediately` boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive. Posts `event` as native notifications of macOS. The `userInfo` is an Object @@ -69,7 +45,7 @@ that contains the user information dictionary sent along with the notification. ### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_ * `event` string -* `userInfo` Record<string, any> +* `userInfo` Record\<string, any\> Posts `event` as native notifications of macOS. The `userInfo` is an Object that contains the user information dictionary sent along with the notification. @@ -77,7 +53,7 @@ that contains the user information dictionary sent along with the notification. ### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_ * `event` string -* `userInfo` Record<string, any> +* `userInfo` Record\<string, any\> Posts `event` as native notifications of macOS. The `userInfo` is an Object that contains the user information dictionary sent along with the notification. @@ -87,7 +63,7 @@ that contains the user information dictionary sent along with the notification. * `event` string | null * `callback` Function * `event` string - * `userInfo` Record<string, unknown> + * `userInfo` Record\<string, unknown\> * `object` string Returns `number` - The ID of this subscription @@ -116,7 +92,7 @@ If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as cr * `event` string | null * `callback` Function * `event` string - * `userInfo` Record<string, unknown> + * `userInfo` Record\<string, unknown\> * `object` string Returns `number` - The ID of this subscription @@ -131,7 +107,7 @@ If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for * `event` string | null * `callback` Function * `event` string - * `userInfo` Record<string, unknown> + * `userInfo` Record\<string, unknown\> * `object` string Returns `number` - The ID of this subscription @@ -161,7 +137,7 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace. ### `systemPreferences.registerDefaults(defaults)` _macOS_ -* `defaults` Record<string, string | boolean | number> - a dictionary of (`key: value`) user defaults +* `defaults` Record\<string, string | boolean | number\> - a dictionary of (`key: value`) user defaults Add the specified defaults to your application's `NSUserDefaults`. @@ -187,7 +163,7 @@ Some popular `key` and `type`s are: * `key` string * `type` Type - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. -* `value` UserDefaultTypes[Type] +* `value` UserDefaultTypes\[Type] Set the value of `key` in `NSUserDefaults`. @@ -213,7 +189,7 @@ enabled, and `false` otherwise. An example of using it to determine if you should create a transparent window or not (transparent windows won't work correctly when DWM composition is disabled): -```javascript +```js const { BrowserWindow, systemPreferences } = require('electron') const browserOptions = { width: 1000, height: 800 } @@ -228,14 +204,14 @@ const win = new BrowserWindow(browserOptions) // Navigate. if (browserOptions.transparent) { - win.loadURL(`file://${__dirname}/index.html`) + win.loadFile('index.html') } else { // No transparency, so we load a fallback that uses basic styles. - win.loadURL(`file://${__dirname}/fallback.html`) + win.loadFile('fallback.html') } ``` -[dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx +[dwm-composition]: https://learn.microsoft.com/en-us/windows/win32/dwm/composition-ovw ### `systemPreferences.getAccentColor()` _Windows_ _macOS_ @@ -297,7 +273,6 @@ This API is only available on macOS 10.14 Mojave or newer. * `window-frame` - Window frame. * `window-text` - Text in windows. * On **macOS** - * `alternate-selected-control-text` - The text on a selected surface in a list or table. _deprecated_ * `control-background` - The background of a large interface element, such as a browser or table. * `control` - The surface of a control. * `control-text` -The text of a control that isn’t disabled. @@ -331,13 +306,13 @@ This API is only available on macOS 10.14 Mojave or newer. * `window-background` - The background of a window. * `window-frame-text` - The text in the window's titlebar area. -Returns `string` - The system color setting in RGB hexadecimal form (`#ABCDEF`). +Returns `string` - The system color setting in RGBA hexadecimal form (`#RRGGBBAA`). See the [Windows docs][windows-colors] and the [macOS docs][macos-colors] for more details. The following colors are only available on macOS 10.14: `find-highlight`, `selected-content-background`, `separator`, `unemphasized-selected-content-background`, `unemphasized-selected-text-background`, and `unemphasized-selected-text`. -[windows-colors]:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724371(v=vs.85).aspx -[macos-colors]:https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#dynamic-system-colors +[windows-colors]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsyscolor +[macos-colors]: https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#dynamic-system-colors ### `systemPreferences.getSystemColor(color)` _macOS_ @@ -356,18 +331,6 @@ Returns `string` - The standard system color formatted as `#RRGGBBAA`. Returns one of several standard system colors that automatically adapt to vibrancy and changes in accessibility settings like 'Increase contrast' and 'Reduce transparency'. See [Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#system-colors) for more details. -### `systemPreferences.isInvertedColorScheme()` _Windows_ _Deprecated_ - -Returns `boolean` - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is active, `false` otherwise. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseInvertedColorScheme`](native-theme.md#nativethemeshoulduseinvertedcolorscheme-macos-windows-readonly) API. - -### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_ _Deprecated_ - -Returns `boolean` - `true` if a high contrast theme is active, `false` otherwise. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseHighContrastColors`](native-theme.md#nativethemeshouldusehighcontrastcolors-macos-windows-readonly) API. - ### `systemPreferences.getEffectiveAppearance()` _macOS_ Returns `string` - Can be `dark`, `light` or `unknown`. @@ -375,34 +338,17 @@ Returns `string` - Can be `dark`, `light` or `unknown`. Gets the macOS appearance setting that is currently applied to your application, maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc) -### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_ - -Returns `string` | `null` - Can be `dark`, `light` or `unknown`. - -Gets the macOS appearance setting that you have declared you want for -your application, maps to [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). -You can use the `setAppLevelAppearance` API to set this value. - -### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_ _Deprecated_ - -* `appearance` string | null - Can be `dark` or `light` - -Sets the appearance setting for your application, this should override the -system default and override the value of `getEffectiveAppearance`. - ### `systemPreferences.canPromptTouchID()` _macOS_ Returns `boolean` - whether or not this device has the ability to use Touch ID. -**NOTE:** This API will return `false` on macOS systems older than Sierra 10.12.2. - ### `systemPreferences.promptTouchID(reason)` _macOS_ * `reason` string - The reason you are asking for Touch ID authentication Returns `Promise<void>` - resolves if the user has successfully authenticated with Touch ID. -```javascript +```js const { systemPreferences } = require('electron') systemPreferences.promptTouchID('To get consent for a Security-Gated Thing').then(success => { @@ -414,8 +360,6 @@ systemPreferences.promptTouchID('To get consent for a Security-Gated Thing').the This API itself will not protect your user data; rather, it is a mechanism to allow you to do so. Native apps will need to set [Access Control Constants](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc) like [`kSecAccessControlUserPresence`](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags/ksecaccesscontroluserpresence?language=objc) on their keychain entry so that reading it would auto-prompt for Touch ID biometric consent. This could be done with [`node-keytar`](https://github.com/atom/node-keytar), such that one would store an encryption key with `node-keytar` and only fetch it if `promptTouchID()` resolves. -**NOTE:** This API will return a rejected Promise on macOS systems older than Sierra 10.12.2. - ### `systemPreferences.isTrustedAccessibilityClient(prompt)` _macOS_ * `prompt` boolean - whether or not the user will be informed via prompt if the current process is untrusted. @@ -428,7 +372,7 @@ Returns `boolean` - `true` if the current process is a trusted accessibility cli Returns `string` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`. -This user consent was not required on macOS 10.13 High Sierra or lower so this method will always return `granted`. +This user consent was not required on macOS 10.13 High Sierra so this method will always return `granted`. macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access. macOS 10.15 Catalina or higher requires consent for `screen` access. @@ -441,9 +385,9 @@ It will always return `granted` for `screen` and for all media types on older ve Returns `Promise<boolean>` - A promise that resolves with `true` if consent was granted and `false` if it was denied. If an invalid `mediaType` is passed, the promise will be rejected. If an access request was denied and later is changed through the System Preferences pane, a restart of the app will be required for the new permissions to take effect. If access has already been requested and denied, it _must_ be changed through the preference pane; an alert will not pop up and the promise will resolve with the existing access status. -**Important:** In order to properly leverage this API, you [must set](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos?language=objc) the `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your app's `Info.plist` file. The values for these keys will be used to populate the permission dialogs so that the user will be properly informed as to the purpose of the permission request. See [Electron Application Distribution](../tutorial/application-distribution.md#macos) for more information about how to set these in the context of Electron. +**Important:** In order to properly leverage this API, you [must set](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos?language=objc) the `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your app's `Info.plist` file. The values for these keys will be used to populate the permission dialogs so that the user will be properly informed as to the purpose of the permission request. See [Electron Application Distribution](../tutorial/application-distribution.md#rebranding-with-downloaded-binaries) for more information about how to set these in the context of Electron. -This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra or lower. +This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra. ### `systemPreferences.getAnimationSettings()` @@ -457,15 +401,11 @@ Returns an object with system animation settings. ## Properties -### `systemPreferences.appLevelAppearance` _macOS_ - -A `string` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for -your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the -system default as well as the value of `getEffectiveAppearance`. +### `systemPreferences.accessibilityDisplayShouldReduceTransparency` _macOS_ _Deprecated_ -Possible values that can be set are `dark` and `light`, and possible return values are `dark`, `light`, and `unknown`. +A `boolean` property which determines whether the app avoids using semitransparent backgrounds. This maps to [NSWorkspace.accessibilityDisplayShouldReduceTransparency](https://developer.apple.com/documentation/appkit/nsworkspace/1533006-accessibilitydisplayshouldreduce) -This property is only available on macOS 10.14 Mojave or newer. +**Deprecated:** Use the new [`nativeTheme.prefersReducedTransparency`](native-theme.md#nativethemeprefersreducedtransparency-readonly) API. ### `systemPreferences.effectiveAppearance` _macOS_ _Readonly_ diff --git a/docs/api/touch-bar-scrubber.md b/docs/api/touch-bar-scrubber.md index 59aa373f15041..a64f309c388f7 100644 --- a/docs/api/touch-bar-scrubber.md +++ b/docs/api/touch-bar-scrubber.md @@ -39,7 +39,7 @@ updates the control in the touch bar. Possible values: #### `touchBarScrubber.overlayStyle` -A `string` representing the style that selected items in the scrubber should have. This style is overlayed on top +A `string` representing the style that selected items in the scrubber should have. This style is overlaid on top of the scrubber item instead of being placed behind it. Updating this value immediately updates the control in the touch bar. Possible values: diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 10bf400ab47b0..c229430326437 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -79,7 +79,7 @@ immediately updates the escape item in the touch bar. Below is an example of a simple slot machine touch bar game with a button and some labels. -```javascript +```js const { app, BrowserWindow, TouchBar } = require('electron') const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar @@ -87,12 +87,12 @@ const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar let spinning = false // Reel labels -const reel1 = new TouchBarLabel() -const reel2 = new TouchBarLabel() -const reel3 = new TouchBarLabel() +const reel1 = new TouchBarLabel({ label: '' }) +const reel2 = new TouchBarLabel({ label: '' }) +const reel3 = new TouchBarLabel({ label: '' }) // Spin result label -const result = new TouchBarLabel() +const result = new TouchBarLabel({ label: '' }) // Spin button const spin = new TouchBarButton({ diff --git a/docs/api/tray.md b/docs/api/tray.md index 0cb995ce2fb3d..6d11505ac5602 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -8,7 +8,7 @@ Process: [Main](../glossary.md#main-process) `Tray` is an [EventEmitter][event-emitter]. -```javascript +```js const { app, Menu, Tray } = require('electron') let tray = null @@ -25,23 +25,21 @@ app.whenReady().then(() => { }) ``` -__Platform Considerations__ +**Platform Considerations** -If you want to keep exact same behaviors on all platforms, you should not -rely on the `click` event; instead, always attach a context menu to the tray icon. +**Linux** -__Linux__ - -* On Linux distributions that only have app indicator support, you have to - install `libappindicator1` to make the tray icon work. -* The app indicator will be used if it is supported, otherwise +* Tray icon uses [StatusNotifierItem](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/) + by default, when it is not available in user's desktop environment the `GtkStatusIcon` will be used instead. -* App indicator will only be shown when it has a context menu. -* The `click` event is ignored when using the app indicator. +* The `click` event is emitted when the tray icon receives activation from + user, however the StatusNotifierItem spec does not specify which action would + cause an activation, for some environments it is left mouse click, but for + some it might be double left mouse click. * In order for changes made to individual `MenuItem`s to take effect, you have to call `setContextMenu` again. For example: -```javascript +```js const { app, Menu, Tray } = require('electron') let appIcon = null @@ -60,14 +58,14 @@ app.whenReady().then(() => { }) ``` -__MacOS__ +**MacOS** -* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image). +* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos). * To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi. * If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image. * 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons. -__Windows__ +**Windows** * It is recommended to use `ICO` icons to get best visual effects. @@ -92,6 +90,9 @@ Returns: Emitted when the tray icon is clicked. +Note that on Linux this event is emitted when the tray icon receives an +activation, which might not necessarily be left mouse click. + #### Event: 'right-click' _macOS_ _Windows_ Returns: @@ -110,6 +111,15 @@ Returns: Emitted when the tray icon is double clicked. +#### Event: 'middle-click' _Windows_ + +Returns: + +* `event` [KeyboardEvent](structures/keyboard-event.md) +* `bounds` [Rectangle](structures/rectangle.md) - The bounds of tray icon. + +Emitted when the tray icon is middle clicked. + #### Event: 'balloon-show' _Windows_ Emitted when the tray balloon shows. @@ -177,7 +187,7 @@ Returns: Emitted when the mouse clicks the tray icon. -#### Event: 'mouse-enter' _macOS_ +#### Event: 'mouse-enter' _macOS_ _Windows_ Returns: @@ -186,7 +196,7 @@ Returns: Emitted when the mouse enters the tray icon. -#### Event: 'mouse-leave' _macOS_ +#### Event: 'mouse-leave' _macOS_ _Windows_ Returns: @@ -234,7 +244,7 @@ Sets the hover text for this tray icon. * `title` string * `options` Object (optional) - * `fontType` string (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in macOS 10.11+. When left blank, the title uses the default system font. + * `fontType` string (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ When left blank, the title uses the default system font. Sets the title displayed next to the tray icon in the status bar (Support ANSI colors). @@ -268,9 +278,9 @@ Returns `boolean` - Whether double click events will be ignored. Displays a tray balloon. -[NIIF_NOSOUND]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_nosound-0x00000010 -[NIIF_LARGE_ICON]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_large_icon-0x00000020 -[NIIF_RESPECT_QUIET_TIME]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_respect_quiet_time-0x00000080 +[NIIF_NOSOUND]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_nosound-0x00000010 +[NIIF_LARGE_ICON]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_large_icon-0x00000020 +[NIIF_RESPECT_QUIET_TIME]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_respect_quiet_time-0x00000080 #### `tray.removeBalloon()` _Windows_ diff --git a/docs/api/utility-process.md b/docs/api/utility-process.md new file mode 100644 index 0000000000000..0b500b58fa9fc --- /dev/null +++ b/docs/api/utility-process.md @@ -0,0 +1,174 @@ +# utilityProcess + +`utilityProcess` creates a child process with +Node.js and Message ports enabled. It provides the equivalent of [`child_process.fork`][] API from Node.js +but instead uses [Services API][] from Chromium to launch the child process. + +Process: [Main](../glossary.md#main-process)<br /> + +## Methods + +### `utilityProcess.fork(modulePath[, args][, options])` + +* `modulePath` string - Path to the script that should run as entrypoint in the child process. +* `args` string[] (optional) - List of string arguments that will be available as `process.argv` + in the child process. +* `options` Object (optional) + * `env` Object (optional) - Environment key-value pairs. Default is `process.env`. + * `execArgv` string[] (optional) - List of string arguments passed to the executable. + * `cwd` string (optional) - Current working directory of the child process. + * `stdio` (string[] | string) (optional) - Allows configuring the mode for `stdout` and `stderr` + of the child process. Default is `inherit`. + String value can be one of `pipe`, `ignore`, `inherit`, for more details on these values you can refer to + [stdio][] documentation from Node.js. Currently this option only supports configuring `stdout` and + `stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` to any property other than `ignore` is not supported and will result in an error. + For example, the supported values will be processed as following: + * `pipe`: equivalent to \['ignore', 'pipe', 'pipe'] + * `ignore`: equivalent to \['ignore', 'ignore', 'ignore'] + * `inherit`: equivalent to \['ignore', 'inherit', 'inherit'] (the default) + * `serviceName` string (optional) - Name of the process that will appear in `name` property of + [`ProcessMetric`](structures/process-metric.md) returned by [`app.getAppMetrics`](app.md#appgetappmetrics) + and [`child-process-gone` event of `app`](app.md#event-child-process-gone). + Default is `Node Utility Process`. + * `allowLoadingUnsignedLibraries` boolean (optional) _macOS_ - With this flag, the utility process will be + launched via the `Electron Helper (Plugin).app` helper executable on macOS, which can be + codesigned with `com.apple.security.cs.disable-library-validation` and + `com.apple.security.cs.allow-unsigned-executable-memory` entitlements. This will allow the utility process + to load unsigned libraries. Unless you specifically need this capability, it is best to leave this disabled. + Default is `false`. + * `respondToAuthRequestsFromMainProcess` boolean (optional) - With this flag, all HTTP 401 and 407 network + requests created via the [net module](net.md) will allow responding to them via the + [`app#login`](app.md#event-login) event in the main process instead of the default + [`login`](client-request.md#event-login) event on the [`ClientRequest`](client-request.md) object. Default is + `false`. + +Returns [`UtilityProcess`](utility-process.md#class-utilityprocess) + +## Class: UtilityProcess + +> Instances of the `UtilityProcess` represent the Chromium spawned child process +> with Node.js integration. + +`UtilityProcess` is an [EventEmitter][event-emitter]. + +### Instance Methods + +#### `child.postMessage(message, [transfer])` + +* `message` any +* `transfer` MessagePortMain[] (optional) + +Send a message to the child process, optionally transferring ownership of +zero or more [`MessagePortMain`][] objects. + +For example: + +```js +// Main process +const { port1, port2 } = new MessageChannelMain() +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.postMessage({ message: 'hello' }, [port1]) + +// Child process +process.parentPort.once('message', (e) => { + const [port] = e.ports + // ... +}) +``` + +#### `child.kill()` + +Returns `boolean` + +Terminates the process gracefully. On POSIX, it uses SIGTERM +but will ensure the process is reaped on exit. This function returns +true if the kill is successful, and false otherwise. + +### Instance Properties + +#### `child.pid` + +A `Integer | undefined` representing the process identifier (PID) of the child process. +Until the child process has spawned successfully, the value is `undefined`. When +the child process exits, then the value is `undefined` after the `exit` event is emitted. + +```js +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) + +console.log(child.pid) // undefined + +child.on('spawn', () => { + console.log(child.pid) // Integer +}) + +child.on('exit', () => { + console.log(child.pid) // undefined +}) +``` + +**Note:** You can use the `pid` to determine if the process is currently running. + +#### `child.stdout` + +A `NodeJS.ReadableStream | null` that represents the child process's stdout. +If the child was spawned with options.stdio\[1] set to anything other than 'pipe', then this will be `null`. +When the child process exits, then the value is `null` after the `exit` event is emitted. + +```js +// Main process +const { port1, port2 } = new MessageChannelMain() +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.stdout.on('data', (data) => { + console.log(`Received chunk ${data}`) +}) +``` + +#### `child.stderr` + +A `NodeJS.ReadableStream | null` that represents the child process's stderr. +If the child was spawned with options.stdio\[2] set to anything other than 'pipe', then this will be `null`. +When the child process exits, then the value is `null` after the `exit` event is emitted. + +### Instance Events + +#### Event: 'spawn' + +Emitted once the child process has spawned successfully. + +#### Event: 'error' _Experimental_ + +Returns: + +* `type` string - Type of error. One of the following values: + * `FatalError` +* `location` string - Source location from where the error originated. +* `report` string - [`Node.js diagnostic report`][]. + +Emitted when the child process needs to terminate due to non continuable error from V8. + +No matter if you listen to the `error` event, the `exit` event will be emitted after the +child process terminates. + +#### Event: 'exit' + +Returns: + +* `code` number - Contains the exit code for +the process obtained from waitpid on POSIX, or GetExitCodeProcess on Windows. + +Emitted after the child process ends. + +#### Event: 'message' + +Returns: + +* `message` any + +Emitted when the child process sends a message using [`process.parentPort.postMessage()`](process.md#processparentport). + +[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options +[Services API]: https://chromium.googlesource.com/chromium/src/+/main/docs/mojo_and_services.md +[stdio]: https://nodejs.org/dist/latest/docs/api/child_process.html#optionsstdio +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[`MessagePortMain`]: message-port-main.md +[`Node.js diagnostic report`]: https://nodejs.org/docs/latest/api/report.html#diagnostic-report diff --git a/docs/api/view.md b/docs/api/view.md new file mode 100644 index 0000000000000..435367d2787e6 --- /dev/null +++ b/docs/api/view.md @@ -0,0 +1,117 @@ +# View + +> Create and layout native views. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +const { BaseWindow, View } = require('electron') +const win = new BaseWindow() +const view = new View() + +view.setBackgroundColor('red') +view.setBounds({ x: 0, y: 0, width: 100, height: 100 }) +win.contentView.addChildView(view) +``` + +## Class: View + +> A basic native view. + +Process: [Main](../glossary.md#main-process) + +`View` is an [EventEmitter][event-emitter]. + +### `new View()` + +Creates a new `View`. + +### Instance Events + +Objects created with `new View` emit the following events: + +#### Event: 'bounds-changed' + +Emitted when the view's bounds have changed in response to being laid out. The +new bounds can be retrieved with [`view.getBounds()`](#viewgetbounds). + +### Instance Methods + +Objects created with `new View` have the following instance methods: + +#### `view.addChildView(view[, index])` + +* `view` View - Child view to add. +* `index` Integer (optional) - Index at which to insert the child view. + Defaults to adding the child at the end of the child list. + +If the same View is added to a parent which already contains it, it will be reordered such that +it becomes the topmost view. + +#### `view.removeChildView(view)` + +* `view` View - Child view to remove. + +If the view passed as a parameter is not a child of this view, this method is a no-op. + +#### `view.setBounds(bounds)` + +* `bounds` [Rectangle](structures/rectangle.md) - New bounds of the View. + +#### `view.getBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The bounds of this View, relative to its parent. + +#### `view.setBackgroundColor(color)` + +* `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is + optional for the hex type. + +Examples of valid `color` values: + +* Hex + * `#fff` (RGB) + * `#ffff` (ARGB) + * `#ffffff` (RRGGBB) + * `#ffffffff` (AARRGGBB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. `rgb(255, 255, 255)` +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. `rgba(255, 255, 255, 1.0)` +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. `hsl(200, 20%, 50%)` +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. `hsla(200, 20%, 50%, 0.5)` +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`. + +#### `view.setBorderRadius(radius)` + +* `radius` Integer - Border radius size in pixels. + +**Note:** The area cutout of the view's border still captures clicks. + +#### `view.setVisible(visible)` + +* `visible` boolean - If false, the view will be hidden from display. + +### Instance Properties + +Objects created with `new View` have the following properties: + +#### `view.children` _Readonly_ + +A `View[]` property representing the child views of this view. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/web-contents-view.md b/docs/api/web-contents-view.md new file mode 100644 index 0000000000000..66bb257cf0edb --- /dev/null +++ b/docs/api/web-contents-view.md @@ -0,0 +1,59 @@ +# WebContentsView + +> A View that displays a WebContents. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +const { BaseWindow, WebContentsView } = require('electron') +const win = new BaseWindow({ width: 800, height: 400 }) + +const view1 = new WebContentsView() +win.contentView.addChildView(view1) +view1.webContents.loadURL('https://electronjs.org') +view1.setBounds({ x: 0, y: 0, width: 400, height: 400 }) + +const view2 = new WebContentsView() +win.contentView.addChildView(view2) +view2.webContents.loadURL('https://github.com/electron/electron') +view2.setBounds({ x: 400, y: 0, width: 400, height: 400 }) +``` + +## Class: WebContentsView extends `View` + +> A View that displays a WebContents. + +Process: [Main](../glossary.md#main-process) + +`WebContentsView` inherits from [`View`](view.md). + +`WebContentsView` is an [EventEmitter][event-emitter]. + +### `new WebContentsView([options])` + +* `options` Object (optional) + * `webPreferences` [WebPreferences](structures/web-preferences.md) (optional) - Settings of web page's features. + * `webContents` [WebContents](web-contents.md) (optional) - If present, the given WebContents will be adopted by the WebContentsView. A WebContents may only be presented in one WebContentsView at a time. + +Creates a WebContentsView. + +### Instance Properties + +Objects created with `new WebContentsView` have the following properties, in +addition to those inherited from [View](view.md): + +#### `view.webContents` _Readonly_ + +A `WebContents` property containing a reference to the displayed `WebContents`. +Use this to interact with the `WebContents`, for instance to load a URL. + +```js +const { WebContentsView } = require('electron') +const view = new WebContentsView() +view.webContents.loadURL('https://electronjs.org/') +``` + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 2cf6e17263088..000c6b9a766bb 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -9,21 +9,51 @@ It is responsible for rendering and controlling a web page and is a property of the [`BrowserWindow`](browser-window.md) object. An example of accessing the `webContents` object: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 1500 }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') const contents = win.webContents console.log(contents) ``` +## Navigation Events + +Several events can be used to monitor navigations as they occur within a `webContents`. + +### Document Navigations + +When a `webContents` navigates to another page (as opposed to an [in-page navigation](web-contents.md#in-page-navigation)), the following events will be fired. + +* [`did-start-navigation`](web-contents.md#event-did-start-navigation) +* [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) +* [`will-navigate`](web-contents.md#event-will-navigate) (only fired when main frame navigates) +* [`will-redirect`](web-contents.md#event-will-redirect) (only fired when a redirect happens during navigation) +* [`did-redirect-navigation`](web-contents.md#event-did-redirect-navigation) (only fired when a redirect happens during navigation) +* [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) +* [`did-navigate`](web-contents.md#event-did-navigate) (only fired when main frame navigates) + +Subsequent events will not fire if `event.preventDefault()` is called on any of the cancellable events. + +### In-page Navigation + +In-page navigations don't cause the page to reload, but instead navigate to a location within the current page. These events are not cancellable. For an in-page navigations, the following events will fire in this order: + +* [`did-start-navigation`](web-contents.md#event-did-start-navigation) +* [`did-navigate-in-page`](web-contents.md#event-did-navigate-in-page) + +### Frame Navigation + +The [`will-navigate`](web-contents.md#event-will-navigate) and [`did-navigate`](web-contents.md#event-did-navigate) events only fire when the [mainFrame](web-contents.md#contentsmainframe-readonly) navigates. +If you want to also observe navigations in `<iframe>`s, use [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) and [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) events. + ## Methods These methods can be accessed from the `webContents` module: -```javascript +```js const { webContents } = require('electron') console.log(webContents) ``` @@ -35,21 +65,28 @@ for all windows, webviews, opened devtools, and devtools extension background pa ### `webContents.getFocusedWebContents()` -Returns `WebContents` | null - The web contents that is focused in this application, otherwise +Returns `WebContents | null` - The web contents that is focused in this application, otherwise returns `null`. ### `webContents.fromId(id)` * `id` Integer -Returns `WebContents` | undefined - A WebContents instance with the given ID, or +Returns `WebContents | undefined` - A WebContents instance with the given ID, or `undefined` if there is no WebContents associated with the given ID. +### `webContents.fromFrame(frame)` + +* `frame` WebFrameMain + +Returns `WebContents | undefined` - A WebContents instance with the given WebFrameMain, or +`undefined` if there is no WebContents associated with the given WebFrameMain. + ### `webContents.fromDevToolsTargetId(targetId)` * `targetId` string - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance. -Returns `WebContents` | undefined - A WebContents instance with the given TargetID, or +Returns `WebContents | undefined` - A WebContents instance with the given TargetID, or `undefined` if there is no WebContents associated with the given TargetID. When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), @@ -61,7 +98,7 @@ async function lookupTargetId (browserWindow) { await wc.debugger.attach('1.3') const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo') const { targetId } = targetInfo - const targetWebContents = await webContents.fromDevToolsTargetId(targetId) + const targetWebContents = await wc.fromDevToolsTargetId(targetId) } ``` @@ -130,10 +167,6 @@ Corresponds to the points in time when the spinner of the tab stopped spinning. #### Event: 'dom-ready' -Returns: - -* `event` Event - Emitted when the document in the top-level frame is loaded. #### Event: 'page-title-updated' @@ -156,6 +189,18 @@ Returns: Emitted when page receives favicon urls. +#### Event: 'content-bounds-updated' + +Returns: + +* `event` Event +* `bounds` [Rectangle](structures/rectangle.md) - requested new content bounds + +Emitted when the page calls `window.moveTo`, `window.resizeTo` or related APIs. + +By default, this will move the window. To prevent that behavior, call +`event.preventDefault()`. + #### Event: 'did-create-window' Returns: @@ -165,7 +210,7 @@ Returns: * `url` string - URL for the created window. * `frameName` string - Name given to the created window in the `window.open()` call. - * `options` BrowserWindowConstructorOptions - The options used to create the + * `options` [BrowserWindowConstructorOptions](structures/browser-window-options.md) - The options used to create the BrowserWindow. They are merged in increasing precedence: parsed options from the `features` string from `window.open()`, security-related webPreferences inherited from the parent, and options given by @@ -180,7 +225,7 @@ Returns: Only defined when the window is being created by a form that set `target=_blank`. * `disposition` string - Can be `default`, `foreground-tab`, - `background-tab`, `new-window`, `save-to-disk` and `other`. + `background-tab`, `new-window` or `other`. Emitted _after_ successful creation of a window via `window.open` in the renderer. Not emitted if the creation of the window is canceled from @@ -192,12 +237,58 @@ See [`window.open()`](window-open.md) for more details and how to use this in co Returns: -* `event` Event -* `url` string +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations. + This property is always set to `false` for this event. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ + +Emitted when a user or the page wants to start navigation on the main frame. It can happen when +the `window.location` object is changed or a user clicks a link in the page. + +This event will not emit when the navigation is started programmatically with +APIs like `webContents.loadURL` and `webContents.back`. + +It is also not emitted for in-page navigations, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. + +Calling `event.preventDefault()` will prevent the navigation. -Emitted when a user or the page wants to start navigation. It can happen when +#### Event: 'will-frame-navigate' + +Returns: + +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations. + This property is always set to `false` for this event. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. + +Emitted when a user or the page wants to start navigation in any frame. It can happen when the `window.location` object is changed or a user clicks a link in the page. +Unlike `will-navigate`, `will-frame-navigate` is fired when the main frame or any of its subframes attempts to navigate. When the navigation event comes from the main frame, `isMainFrame` will be `true`. + This event will not emit when the navigation is started programmatically with APIs like `webContents.loadURL` and `webContents.back`. @@ -211,26 +302,49 @@ Calling `event.preventDefault()` will prevent the navigation. Returns: -* `event` Event -* `url` string -* `isInPlace` boolean -* `isMainFrame` boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer - -Emitted when any frame (including main) starts navigating. `isInPlace` will be -`true` for in-page navigations. +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ + +Emitted when any frame (including main) starts navigating. #### Event: 'will-redirect' Returns: -* `event` Event -* `url` string -* `isInPlace` boolean -* `isMainFrame` boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ Emitted when a server side redirect occurs during navigation. For example a 302 redirect. @@ -245,12 +359,24 @@ redirect). Returns: -* `event` Event -* `url` string -* `isInPlace` boolean -* `isMainFrame` boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ Emitted after a server side redirect occurs during navigation. For example a 302 redirect. @@ -318,7 +444,7 @@ Emitted when a `beforeunload` event handler is attempting to cancel a page unloa Calling `event.preventDefault()` will ignore the `beforeunload` event handler and allow the page to be unloaded. -```javascript +```js const { BrowserWindow, dialog } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) win.webContents.on('will-prevent-unload', (event) => { @@ -339,37 +465,12 @@ win.webContents.on('will-prevent-unload', (event) => { **Note:** This will be emitted for `BrowserViews` but will _not_ be respected - this is because we have chosen not to tie the `BrowserView` lifecycle to its owning BrowserWindow should one exist per the [specification](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event). -#### Event: 'crashed' _Deprecated_ - -Returns: - -* `event` Event -* `killed` boolean - -Emitted when the renderer process crashes or is killed. - -**Deprecated:** This event is superceded by the `render-process-gone` event -which contains more information about why the render process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. - #### Event: 'render-process-gone' Returns: * `event` Event -* `details` Object - * `reason` string - The reason the render process is gone. Possible values: - * `clean-exit` - Process exited with an exit code of zero - * `abnormal-exit` - Process exited with a non-zero exit code - * `killed` - Process was sent a SIGTERM or otherwise killed externally - * `crashed` - Process crashed - * `oom` - Process ran out of memory - * `launch-failed` - Process never successfully launched - * `integrity-failure` - Windows code integrity checks failed - * `exitCode` Integer - The exit code of the process, unless `reason` is - `launch-failed`, in which case `exitCode` will be a platform-specific - launch failure error code. +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) Emitted when the renderer process unexpectedly disappears. This is normally because it was crashed or killed. @@ -396,6 +497,16 @@ Emitted when a plugin process has crashed. Emitted when `webContents` is destroyed. +#### Event: 'input-event' + +Returns: + +* `event` Event +* `inputEvent` [InputEvent](structures/input-event.md) + +Emitted when an input event is sent to the WebContents. See +[InputEvent](structures/input-event.md) for details. + #### Event: 'before-input-event' Returns: @@ -421,7 +532,7 @@ and the menu shortcuts. To only prevent the menu shortcuts, use [`setIgnoreMenuShortcuts`](#contentssetignoremenushortcutsignore): -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) @@ -467,6 +578,24 @@ The `focus` and `blur` events of `WebContents` should only be used to detect focus change between different `WebContents` and `BrowserView` in the same window. +#### Event: 'devtools-open-url' + +Returns: + +* `event` Event +* `url` string - URL of the link that was clicked or selected. + +Emitted when a link is clicked in DevTools or 'Open in new tab' is selected for a link in its context menu. + +#### Event: 'devtools-search-query' + +Returns: + +* `event` Event +* `query` string - text to query for. + +Emitted when 'Search' is selected for text in its context menu. + #### Event: 'devtools-opened' Emitted when DevTools is opened. @@ -493,8 +622,7 @@ Returns: Emitted when failed to verify the `certificate` for `url`. -The usage is the same with [the `certificate-error` event of -`app`](app.md#event-certificate-error). +The usage is the same with [the `certificate-error` event of `app`](app.md#event-certificate-error). #### Event: 'select-client-certificate' @@ -508,8 +636,7 @@ Returns: Emitted when a client certificate is requested. -The usage is the same with [the `select-client-certificate` event of -`app`](app.md#event-select-client-certificate). +The usage is the same with [the `select-client-certificate` event of `app`](app.md#event-select-client-certificate). #### Event: 'login' @@ -545,7 +672,7 @@ Returns: * `finalUpdate` boolean Emitted when a result is available for -[`webContents.findInPage`] request. +[`webContents.findInPage`](#contentsfindinpagetext-options) request. #### Event: 'media-started-playing' @@ -555,6 +682,15 @@ Emitted when media starts playing. Emitted when media is paused or done playing. +#### Event: 'audio-state-changed' + +Returns: + +* `event` Event\<\> + * `audible` boolean - True if one or more frames or child `webContents` are emitting audio. + +Emitted when media becomes audible or inaudible. + #### Event: 'did-change-theme-color' Returns: @@ -589,14 +725,16 @@ Returns: * `size` [Size](structures/size.md) (optional) - the size of the `image`. * `hotspot` [Point](structures/point.md) (optional) - coordinates of the custom cursor's hotspot. -Emitted when the cursor's type changes. The `type` parameter can be `default`, -`crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, -`ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, -`ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`, -`row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, -`s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, -`cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, -`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing` or `custom`. +Emitted when the cursor's type changes. The `type` parameter can be `pointer`, +`crosshair`, `hand`, `text`, `wait`, `help`, `e-resize`, `n-resize`, `ne-resize`, +`nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, `ns-resize`, `ew-resize`, +`nesw-resize`, `nwse-resize`, `col-resize`, `row-resize`, `m-panning`, `m-panning-vertical`, +`m-panning-horizontal`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, `s-panning`, +`se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, `cell`, `context-menu`, +`alias`, `progress`, `nodrop`, `copy`, `none`, `not-allowed`, `zoom-in`, `zoom-out`, `grab`, +`grabbing`, `custom`, `null`, `drag-drop-none`, `drag-drop-move`, `drag-drop-copy`, +`drag-drop-link`, `ns-no-resize`, `ew-no-resize`, `nesw-no-resize`, `nwse-no-resize`, +or `default`. If the `type` parameter is `custom`, the `image` parameter will hold the custom cursor image in a [`NativeImage`](native-image.md), and `scale`, `size` and `hotspot` will hold @@ -610,7 +748,8 @@ Returns: * `params` Object * `x` Integer - x coordinate. * `y` Integer - y coordinate. - * `frame` WebFrameMain - Frame from which the context menu was invoked. + * `frame` WebFrameMain | null - Frame from which the context menu was invoked. + May be `null` if accessed after the frame has either navigated or been destroyed. * `linkURL` string - URL of the link that encloses the node the context menu was invoked on. * `linkText` string - Text associated with the link. May be an empty @@ -643,9 +782,15 @@ Returns: word and spellchecker is enabled. * `frameCharset` string - The character encoding of the frame on which the menu was invoked. - * `inputFieldType` string - If the context menu was invoked on an input - field, the type of that field. Possible values are `none`, `plainText`, - `password`, `other`. + * `formControlType` string - The source that the context menu was invoked on. + Possible values include `none`, `button-button`, `field-set`, + `input-button`, `input-checkbox`, `input-color`, `input-date`, + `input-datetime-local`, `input-email`, `input-file`, `input-hidden`, + `input-image`, `input-month`, `input-number`, `input-password`, `input-radio`, + `input-range`, `input-reset`, `input-search`, `input-submit`, `input-telephone`, + `input-text`, `input-time`, `input-url`, `input-week`, `output`, `reset-button`, + `select-list`, `select-list`, `select-multiple`, `select-one`, `submit-button`, + and `text-area`, * `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled. * `menuSourceType` string - Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. @@ -688,20 +833,24 @@ Returns: * `callback` Function * `deviceId` string -Emitted when bluetooth device needs to be selected on call to -`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api -`webBluetooth` should be enabled. If `event.preventDefault` is not called, -first available device will be selected. `callback` should be called with -`deviceId` to be selected, passing empty string to `callback` will -cancel the request. +Emitted when a bluetooth device needs to be selected when a call to +`navigator.bluetooth.requestDevice` is made. `callback` should be called with +the `deviceId` of the device to be selected. Passing an empty string to +`callback` will cancel the request. + +If an event listener is not added for this event, or if `event.preventDefault` +is not called when handling this event, the first available device will be +automatically selected. -If no event listener is added for this event, all bluetooth requests will be cancelled. +Due to the nature of bluetooth, scanning for devices when +`navigator.bluetooth.requestDevice` is called may take time and will cause +`select-bluetooth-device` to fire multiple times until `callback` is called +with either a device id or an empty string to cancel the request. -```javascript +```js title='main.js' const { app, BrowserWindow } = require('electron') let win = null -app.commandLine.appendSwitch('enable-experimental-web-platform-features') app.whenReady().then(() => { win = new BrowserWindow({ width: 800, height: 600 }) @@ -711,6 +860,9 @@ app.whenReady().then(() => { return device.deviceName === 'test' }) if (!result) { + // The device wasn't found so we need to either wait longer (eg until the + // device is turned on) or cancel the request by calling the callback + // with an empty string. callback('') } else { callback(result.deviceId) @@ -723,21 +875,48 @@ app.whenReady().then(() => { Returns: -* `event` Event +* `details` Event\<\> + * `texture` [OffscreenSharedTexture](structures/offscreen-shared-texture.md) (optional) _Experimental_ - The GPU shared texture of the frame, when `webPreferences.offscreen.useSharedTexture` is `true`. * `dirtyRect` [Rectangle](structures/rectangle.md) * `image` [NativeImage](native-image.md) - The image data of the whole frame. -Emitted when a new frame is generated. Only the dirty area is passed in the -buffer. +Emitted when a new frame is generated. Only the dirty area is passed in the buffer. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ webPreferences: { offscreen: true } }) win.webContents.on('paint', (event, dirty, image) => { // updateBitmap(dirty, image.getBitmap()) }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') +``` + +When using shared texture (set `webPreferences.offscreen.useSharedTexture` to `true`) feature, you can pass the texture handle to external rendering pipeline without the overhead of +copying data between CPU and GPU memory, with Chromium's hardware acceleration support. This feature is helpful for high-performance rendering scenarios. + +Only a limited number of textures can exist at the same time, so it's important that you call `texture.release()` as soon as you're done with the texture. +By managing the texture lifecycle by yourself, you can safely pass the `texture.textureInfo` to other processes through IPC. + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow({ webPreferences: { offscreen: { useSharedTexture: true } } }) +win.webContents.on('paint', async (e, dirty, image) => { + if (e.texture) { + // By managing lifecycle yourself, you can handle the event in async handler or pass the `e.texture.textureInfo` + // to other processes (not `e.texture`, the `e.texture.release` function is not passable through IPC). + await new Promise(resolve => setTimeout(resolve, 50)) + + // You can send the native texture handle to native code for importing into your rendering pipeline. + // For example: https://github.com/electron/electron/tree/main/spec/fixtures/native-addon/osr-gpu + // importTextureHandle(dirty, e.texture.textureInfo) + + // You must call `e.texture.release()` as soon as possible, before the underlying frame pool is drained. + e.texture.release() + } +}) +win.loadURL('https://github.com') ``` #### Event: 'devtools-reload-page' @@ -749,10 +928,10 @@ Emitted when the devtools window instructs the webContents to reload Returns: * `event` Event -* `webPreferences` WebPreferences - The web preferences that will be used by the guest +* `webPreferences` [WebPreferences](structures/web-preferences.md) - The web preferences that will be used by the guest page. This object can be modified to adjust the preferences for the guest page. -* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL. +* `params` Record\<string, string\> - The other `<webview>` parameters such as the `src` URL. This object can be modified to adjust the parameters of the guest page. Emitted when a `<webview>`'s web contents is being attached to this web @@ -776,11 +955,17 @@ Emitted when a `<webview>` has been attached to this web contents. Returns: -* `event` Event -* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. -* `message` string - The actual console message -* `line` Integer - The line number of the source that triggered this console message -* `sourceId` string +* `details` Event\<\> + * `message` string - Message text + * `level` string - Message severity + Possible values include `info`, `warning`, `error`, and `debug`. + * `lineNumber` Integer - Line number in the log source + * `sourceId` string - URL of the log source + * `frame` WebFrameMain - Frame that logged the message +* `level` Integer _Deprecated_ - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. +* `message` string _Deprecated_ - The actual console message +* `line` Integer _Deprecated_ - The line number of the source that triggered this console message +* `sourceId` string _Deprecated_ Emitted when the associated window logs a console message. @@ -798,7 +983,7 @@ Emitted when the preload script `preloadPath` throws an unhandled exception `err Returns: -* `event` Event +* `event` [IpcMainEvent](structures/ipc-main-event.md) * `channel` string * `...args` any[] @@ -810,7 +995,7 @@ See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain Returns: -* `event` Event +* `event` [IpcMainEvent](structures/ipc-main-event.md) * `channel` string * `...args` any[] @@ -837,7 +1022,8 @@ Returns: * `event` Event * `details` Object - * `frame` WebFrameMain + * `frame` WebFrameMain | null - The created frame. + May be `null` if accessed after the frame has either navigated or been destroyed. Emitted when the [mainFrame](web-contents.md#contentsmainframe-readonly), an `<iframe>`, or a nested `<iframe>` is loaded within the page. @@ -862,17 +1048,17 @@ Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. the `http://` or `file://`. If the load should bypass http cache then use the `pragma` header to achieve it. -```javascript -const { webContents } = require('electron') +```js +const win = new BrowserWindow() const options = { extraHeaders: 'pragma: no-cache\n' } -webContents.loadURL('https://github.com', options) +win.webContents.loadURL('https://github.com', options) ``` #### `contents.loadFile(filePath[, options])` * `filePath` string * `options` Object (optional) - * `query` Record<string, string> (optional) - Passed to `url.format()`. + * `query` Record\<string, string\> (optional) - Passed to `url.format()`. * `search` string (optional) - Passed to `url.format()`. * `hash` string (optional) - Passed to `url.format()`. @@ -895,12 +1081,15 @@ an app structure like this: Would require code like this ```js +const win = new BrowserWindow() win.loadFile('src/index.html') ``` -#### `contents.downloadURL(url)` +#### `contents.downloadURL(url[, options])` * `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url` without navigating. The `will-download` event of `session` will be triggered. @@ -909,10 +1098,10 @@ Initiates a download of the resource at `url` without navigating. The Returns `string` - The URL of the current web page. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('http://github.com').then(() => { +win.loadURL('https://github.com').then(() => { const currentURL = win.webContents.getURL() console.log(currentURL) }) @@ -926,6 +1115,21 @@ Returns `string` - The title of the current web page. Returns `boolean` - Whether the web page is destroyed. +#### `contents.close([opts])` + +* `opts` Object (optional) + * `waitForBeforeUnload` boolean - if true, fire the `beforeunload` event + before closing the page. If the page prevents the unload, the WebContents + will not be closed. The [`will-prevent-unload`](#event-will-prevent-unload) + will be fired if the page requests prevention of unload. + +Closes the page, as if the web content had called `window.close()`. + +If the page is successfully closed (i.e. the unload is not prevented by the +page, or `waitForBeforeUnload` is false or unspecified), the WebContents will +be destroyed and no longer usable. The [`destroyed`](#event-destroyed) event +will be emitted. + #### `contents.focus()` Focuses the web page. @@ -960,44 +1164,124 @@ Reloads the current web page. Reloads current page and ignores cache. -#### `contents.canGoBack()` +#### `contents.canGoBack()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Returns `boolean` - Whether the browser can go back to previous web page. -#### `contents.canGoForward()` +**Deprecated:** Should use the new [`contents.navigationHistory.canGoBack`](navigation-history.md#navigationhistorycangoback) API. + +#### `contents.canGoForward()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Returns `boolean` - Whether the browser can go forward to next web page. -#### `contents.canGoToOffset(offset)` +**Deprecated:** Should use the new [`contents.navigationHistory.canGoForward`](navigation-history.md#navigationhistorycangoforward) API. + +#### `contents.canGoToOffset(offset)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `offset` Integer Returns `boolean` - Whether the web page can go to `offset`. -#### `contents.clearHistory()` +**Deprecated:** Should use the new [`contents.navigationHistory.canGoToOffset`](navigation-history.md#navigationhistorycangotooffsetoffset) API. + +#### `contents.clearHistory()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Clears the navigation history. -#### `contents.goBack()` +**Deprecated:** Should use the new [`contents.navigationHistory.clear`](navigation-history.md#navigationhistoryclear) API. + +#### `contents.goBack()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Makes the browser go back a web page. -#### `contents.goForward()` +**Deprecated:** Should use the new [`contents.navigationHistory.goBack`](navigation-history.md#navigationhistorygoback) API. + +#### `contents.goForward()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Makes the browser go forward a web page. -#### `contents.goToIndex(index)` +**Deprecated:** Should use the new [`contents.navigationHistory.goForward`](navigation-history.md#navigationhistorygoforward) API. + +#### `contents.goToIndex(index)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `index` Integer Navigates browser to the specified absolute web page index. -#### `contents.goToOffset(offset)` +**Deprecated:** Should use the new [`contents.navigationHistory.goToIndex`](navigation-history.md#navigationhistorygotoindexindex) API. + +#### `contents.goToOffset(offset)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `offset` Integer Navigates to the specified offset from the "current entry". +**Deprecated:** Should use the new [`contents.navigationHistory.goToOffset`](navigation-history.md#navigationhistorygotooffsetoffset) API. + #### `contents.isCrashed()` Returns `boolean` - Whether the renderer process has crashed. @@ -1016,7 +1300,9 @@ when this process is unstable or unusable, for instance in order to recover from the `unresponsive` event. ```js -contents.on('unresponsive', async () => { +const win = new BrowserWindow() + +win.webContents.on('unresponsive', async () => { const { response } = await dialog.showMessageBox({ message: 'App X has become unresponsive', title: 'Do you want to try forcefully reloading the app?', @@ -1024,8 +1310,8 @@ contents.on('unresponsive', async () => { cancelId: 1 }) if (response === 0) { - contents.forcefullyCrashRenderer() - contents.reload() + win.webContents.forcefullyCrashRenderer() + win.webContents.reload() } }) ``` @@ -1044,7 +1330,7 @@ Returns `string` - The user agent for this web page. * `css` string * `options` Object (optional) - * `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. + * `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`. @@ -1052,8 +1338,9 @@ Injects CSS into the current web page and returns a unique key for the inserted stylesheet. ```js -contents.on('did-finish-load', () => { - contents.insertCSS('html, body { background-color: #f00; }') +const win = new BrowserWindow() +win.webContents.on('did-finish-load', () => { + win.webContents.insertCSS('html, body { background-color: #f00; }') }) ``` @@ -1067,9 +1354,11 @@ Removes the inserted CSS from the current web page. The stylesheet is identified by its key, which is returned from `contents.insertCSS(css)`. ```js -contents.on('did-finish-load', async () => { - const key = await contents.insertCSS('html, body { background-color: #f00; }') - contents.removeInsertedCSS(key) +const win = new BrowserWindow() + +win.webContents.on('did-finish-load', async () => { + const key = await win.webContents.insertCSS('html, body { background-color: #f00; }') + win.webContents.removeInsertedCSS(key) }) ``` @@ -1090,7 +1379,9 @@ this limitation. Code execution will be suspended until web page stop loading. ```js -contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) +const win = new BrowserWindow() + +win.webContents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) .then((result) => { console.log(result) // Will be the JSON object from the fetch call }) @@ -1115,13 +1406,13 @@ Ignore application menu shortcuts while this web contents is focused. #### `contents.setWindowOpenHandler(handler)` -* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}> +* `handler` Function\<[WindowOpenHandlerResponse](structures/window-open-handler-response.md)\> * `details` Object * `url` string - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`. * `frameName` string - Name of the window provided in `window.open()` * `features` string - Comma separated list of window features provided to `window.open()`. * `disposition` string - Can be `default`, `foreground-tab`, `background-tab`, - `new-window`, `save-to-disk` or `other`. + `new-window` or `other`. * `referrer` [Referrer](structures/referrer.md) - The referrer that will be passed to the new window. May or may not result in the `Referer` header being sent, depending on the referrer policy. @@ -1130,8 +1421,8 @@ Ignore application menu shortcuts while this web contents is focused. be set. If no post data is to be sent, the value will be `null`. Only defined when the window is being created by a form that set `target=_blank`. - Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new - window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window. + Returns `WindowOpenHandlerResponse` - When set to `{ action: 'deny' }` cancels the creation of the new + window. `{ action: 'allow' }` will allow the new window to be created. Returning an unrecognized value such as a null, undefined, or an object without a recognized 'action' value will result in a console error and have the same effect as returning `{action: 'deny'}`. @@ -1142,6 +1433,26 @@ submitting a form with `<form target="_blank">`. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`. +An example showing how to customize the process of new `BrowserWindow` creation to be `BrowserView` attached to main window instead: + +```js +const { BrowserView, BrowserWindow } = require('electron') + +const mainWindow = new BrowserWindow() + +mainWindow.webContents.setWindowOpenHandler((details) => { + return { + action: 'allow', + createWindow: (options) => { + const browserView = new BrowserView(options) + mainWindow.addBrowserView(browserView) + browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 }) + return browserView.webContents + } + } +}) +``` + #### `contents.setAudioMuted(muted)` * `muted` boolean @@ -1198,7 +1509,8 @@ Sets the maximum and minimum pinch-to-zoom level. > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, call: > > ```js -> contents.setVisualZoomLevelLimits(1, 3) +> const win = new BrowserWindow() +> win.webContents.setVisualZoomLevelLimits(1, 3) > ``` #### `contents.undo()` @@ -1217,6 +1529,10 @@ Executes the editing command `cut` in web page. Executes the editing command `copy` in web page. +#### `contents.centerSelection()` + +Centers the current text selection in web page. + #### `contents.copyImageAt(x, y)` * `x` Integer @@ -1244,6 +1560,46 @@ Executes the editing command `selectAll` in web page. Executes the editing command `unselect` in web page. +#### `contents.scrollToTop()` + +Scrolls to the top of the current `webContents`. + +#### `contents.scrollToBottom()` + +Scrolls to the bottom of the current `webContents`. + +#### `contents.adjustSelection(options)` + +* `options` Object + * `start` Number (optional) - Amount to shift the start index of the current selection. + * `end` Number (optional) - Amount to shift the end index of the current selection. + +Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document. + +Example: + +```js +const win = new BrowserWindow() + +// Adjusts the beginning of the selection 1 letter forward, +// and the end of the selection 5 letters forward. +win.webContents.adjustSelection({ start: 1, end: 5 }) + +// Adjusts the beginning of the selection 2 letters forward, +// and the end of the selection 3 letters backward. +win.webContents.adjustSelection({ start: 2, end: -3 }) +``` + +For a call of `win.webContents.adjustSelection({ start: 1, end: 5 })` + +Before: + +<img width="487" alt="Image Before Text Selection Adjustment" src="../images/web-contents-text-selection-before.png"/> + +After: + +<img width="487" alt="Image After Text Selection Adjustment" src="../images/web-contents-text-selection-after.png"/> + #### `contents.replace(text)` * `text` string @@ -1281,63 +1637,40 @@ can be obtained by subscribing to [`found-in-page`](web-contents.md#event-found- #### `contents.stopFindInPage(action)` * `action` string - Specifies the action to take place when ending - [`webContents.findInPage`] request. + [`webContents.findInPage`](#contentsfindinpagetext-options) request. * `clearSelection` - Clear the selection. * `keepSelection` - Translate the selection into a normal selection. * `activateSelection` - Focus and click the selection node. Stops any `findInPage` request for the `webContents` with the provided `action`. -```javascript -const { webContents } = require('electron') -webContents.on('found-in-page', (event, result) => { - if (result.finalUpdate) webContents.stopFindInPage('clearSelection') +```js +const win = new BrowserWindow() +win.webContents.on('found-in-page', (event, result) => { + if (result.finalUpdate) win.webContents.stopFindInPage('clearSelection') }) -const requestId = webContents.findInPage('api') +const requestId = win.webContents.findInPage('api') console.log(requestId) ``` -#### `contents.capturePage([rect])` +#### `contents.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured. +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md) Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. +The page is considered visible when its browser window is hidden and the capturer count is non-zero. +If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `contents.isBeingCaptured()` Returns `boolean` - Whether this page is being captured. It returns true when the capturer count -is large then 0. - -#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])` - -* `size` [Size](structures/size.md) (optional) - The preferred size for the capturer. -* `stayHidden` boolean (optional) - Keep the page hidden instead of visible. -* `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. - -Increase the capturer count by one. The page is considered visible when its browser window is -hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. - -This also affects the Page Visibility API. - -#### `contents.decrementCapturerCount([stayHidden, stayAwake])` - -* `stayHidden` boolean (optional) - Keep the page in hidden state instead of visible. -* `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. - -Decrease the capturer count by one. The page will be set to hidden or occluded state when its -browser window is hidden or occluded and the capturer count reaches zero. If you want to -decrease the hidden capturer count instead you should set `stayHidden` to true. - -#### `contents.getPrinters()` _Deprecated_ - -Get the system printer list. - -Returns [`PrinterInfo[]`](structures/printer-info.md) - -**Deprecated:** Should use the new [`contents.getPrintersAsync`](web-contents.md#contentsgetprintersasync) API. +is greater than 0. #### `contents.getPrintersAsync()` @@ -1368,13 +1701,13 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/ * `from` number - Index of the first page to print (0-based). * `to` number - Index of the last page to print (inclusive) (0-based). * `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. - * `dpi` Record<string, number> (optional) + * `dpi` Record\<string, number\> (optional) * `horizontal` number (optional) - The horizontal dpi. * `vertical` number (optional) - The vertical dpi. * `header` string (optional) - string to be printed as page header. * `footer` string (optional) - string to be printed as page footer. - * `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`. + * `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A0`, `A1`, `A2`, `A3`, + `A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`. * `callback` Function (optional) * `success` boolean - Indicates success of the print call. * `failureReason` string - Error description called back if the print fails. @@ -1389,6 +1722,7 @@ Use `page-break-before: always;` CSS style to force to print to a new page. Example usage: ```js +const win = new BrowserWindow() const options = { silent: true, deviceName: 'My-Printer', @@ -1416,10 +1750,12 @@ win.webContents.print(options, (success, errorType) => { * `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches). * `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches). * `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches). - * `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. + * `pageRanges` string (optional) - Page ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. * `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title. * `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`. * `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. + * `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards. + * `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false. Returns `Promise<Buffer>` - Resolves with the generated PDF data. @@ -1429,25 +1765,27 @@ The `landscape` will be ignored if `@page` CSS at-rule is used in the web page. An example of `webContents.printToPDF`: -```javascript -const { BrowserWindow } = require('electron') -const fs = require('fs') -const path = require('path') -const os = require('os') +```js +const { app, BrowserWindow } = require('electron') +const fs = require('node:fs') +const path = require('node:path') +const os = require('node:os') -const win = new BrowserWindow() -win.loadURL('http://github.com') +app.whenReady().then(() => { + const win = new BrowserWindow() + win.loadURL('https://github.com') -win.webContents.on('did-finish-load', () => { - // Use default printing options - const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf') - win.webContents.printToPDF({}).then(data => { - fs.writeFile(pdfPath, data, (error) => { - if (error) throw error - console.log(`Wrote PDF successfully to ${pdfPath}`) + win.webContents.on('did-finish-load', () => { + // Use default printing options + const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf') + win.webContents.printToPDF({}).then(data => { + fs.writeFile(pdfPath, data, (error) => { + if (error) throw error + console.log(`Wrote PDF successfully to ${pdfPath}`) + }) + }).catch(error => { + console.log(`Failed to write PDF to ${pdfPath}: `, error) }) - }).catch(error => { - console.log(`Failed to write PDF to ${pdfPath}: `, error) }) }) ``` @@ -1461,7 +1799,7 @@ See [Page.printToPdf](https://chromedevtools.github.io/devtools-protocol/tot/Pag Adds the specified path to DevTools workspace. Must be used after DevTools creation: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() win.webContents.on('devtools-opened', () => { @@ -1539,7 +1877,7 @@ ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => { An example of showing devtools in a `BrowserWindow`: -```js +```js title='main.js' const { app, BrowserWindow } = require('electron') let win = null @@ -1562,6 +1900,7 @@ app.whenReady().then(() => { In `undocked` mode it's possible to dock back. In `detach` mode it's not. * `activate` boolean (optional) - Whether to bring the opened devtools window to the foreground. The default is `true`. + * `title` string (optional) - A title for the DevTools window (only in `undocked` or `detach` mode). Opens the devtools. @@ -1582,6 +1921,18 @@ Returns `boolean` - Whether the devtools is opened. Returns `boolean` - Whether the devtools view is focused . +#### `contents.getDevToolsTitle()` + +Returns `string` - the current title of the DevTools window. This will only be visible +if DevTools is opened in `undocked` or `detach` mode. + +#### `contents.setDevToolsTitle(title)` + +* `title` string + +Changes the title of the DevTools window to `title`. This will only be visible if DevTools is +opened in `undocked` or `detach` mode. + #### `contents.toggleDevTools()` Toggles the developer tools. @@ -1617,49 +1968,23 @@ Opens the developer tools for the service worker context. * `...args` any[] Send an asynchronous message to the renderer process via `channel`, along with -arguments. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE**: Sending non-standard JavaScript types such as DOM objects or -> special Electron objects will throw an exception. +:::warning -The renderer process can handle the message by listening to `channel` with the -[`ipcRenderer`](ipc-renderer.md) module. +Sending non-standard JavaScript types such as DOM objects or +special Electron objects will throw an exception. -An example of sending messages from the main process to the renderer process: +::: -```javascript -// In the main process. -const { app, BrowserWindow } = require('electron') -let win = null - -app.whenReady().then(() => { - win = new BrowserWindow({ width: 800, height: 600 }) - win.loadURL(`file://${__dirname}/index.html`) - win.webContents.on('did-finish-load', () => { - win.webContents.send('ping', 'whoooooooh!') - }) -}) -``` - -```html -<!-- index.html --> -<html> -<body> - <script> - require('electron').ipcRenderer.on('ping', (event, message) => { - console.log(message) // Prints 'whoooooooh!' - }) - </script> -</body> -</html> -``` +For additional reading, refer to [Electron's IPC guide](../tutorial/ipc.md). #### `contents.sendToFrame(frameId, channel, ...args)` -* `frameId` Integer | [number, number] - the ID of the frame to send to, or a +* `frameId` Integer | \[number, number] - the ID of the frame to send to, or a pair of `[processId, frameId]` if the frame is in a different process to the main frame. * `channel` string @@ -1711,8 +2036,9 @@ For example: ```js // Main process +const win = new BrowserWindow() const { port1, port2 } = new MessageChannelMain() -webContents.postMessage('port', { message: 'hello' }, [port1]) +win.webContents.postMessage('port', { message: 'hello' }, [port1]) // Renderer process ipcRenderer.on('port', (e, msg) => { @@ -1796,7 +2122,7 @@ the cursor when dragging. Returns `Promise<void>` - resolves if the page is saved. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -1817,36 +2143,36 @@ Shows pop-up dictionary that searches the selected word on the page. #### `contents.isOffscreen()` -Returns `boolean` - Indicates whether *offscreen rendering* is enabled. +Returns `boolean` - Indicates whether _offscreen rendering_ is enabled. #### `contents.startPainting()` -If *offscreen rendering* is enabled and not painting, start painting. +If _offscreen rendering_ is enabled and not painting, start painting. #### `contents.stopPainting()` -If *offscreen rendering* is enabled and painting, stop painting. +If _offscreen rendering_ is enabled and painting, stop painting. #### `contents.isPainting()` -Returns `boolean` - If *offscreen rendering* is enabled returns whether it is currently painting. +Returns `boolean` - If _offscreen rendering_ is enabled returns whether it is currently painting. #### `contents.setFrameRate(fps)` * `fps` Integer -If *offscreen rendering* is enabled sets the frame rate to the specified number. +If _offscreen rendering_ is enabled sets the frame rate to the specified number. Only values between 1 and 240 are accepted. #### `contents.getFrameRate()` -Returns `Integer` - If *offscreen rendering* is enabled returns the current frame rate. +Returns `Integer` - If _offscreen rendering_ is enabled returns the current frame rate. #### `contents.invalidate()` Schedules a full repaint of the window this web contents is in. -If *offscreen rendering* is enabled invalidates the frame and generates a new +If _offscreen rendering_ is enabled invalidates the frame and generates a new one through the `'paint'` event. #### `contents.getWebRTCIPHandlingPolicy()` @@ -1874,6 +2200,24 @@ Setting the WebRTC IP handling policy allows you to control which IPs are exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for more details. +#### `contents.getWebRTCUDPPortRange()` + +Returns `Object`: + +* `min` Integer - The minimum UDP port number that WebRTC should use. +* `max` Integer - The maximum UDP port number that WebRTC should use. + +By default this value is `{ min: 0, max: 0 }` , which would apply no restriction on the udp port range. + +#### `contents.setWebRTCUDPPortRange(udpPortRange)` + +* `udpPortRange` Object + * `min` Integer - The minimum UDP port number that WebRTC should use. + * `max` Integer - The maximum UDP port number that WebRTC should use. + +Setting the WebRTC UDP Port Range allows you to restrict the udp port range used by WebRTC. By default the port range is unrestricted. +**Note:** To reset to an unrestricted port range this value should be set to `{ min: 0, max: 0 }`. + #### `contents.getMediaSourceId(requestWebContents)` * `requestWebContents` WebContents - Web contents that the id will be registered to. @@ -1908,6 +2252,15 @@ when the page becomes backgrounded. This also affects the Page Visibility API. #### `contents.setBackgroundThrottling(allowed)` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/38924 + description: "`WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow`" + breaking-changes-header: behavior-changed-webcontentsbackgroundthrottling-set-to-false-affects-all-webcontents-in-the-host-browserwindow +``` +--> + * `allowed` boolean Controls whether or not this WebContents will throttle animations and timers @@ -1987,7 +2340,7 @@ The zoom factor is the zoom percent divided by 100, so 300% = 3.0. An `Integer` property that sets the frame rate of the web contents to the specified number. Only values between 1 and 240 are accepted. -Only applicable if *offscreen rendering* is enabled. +Only applicable if _offscreen rendering_ is enabled. #### `contents.id` _Readonly_ @@ -1997,6 +2350,10 @@ A `Integer` representing the unique ID of this WebContents. Each ID is unique am A [`Session`](session.md) used by this webContents. +#### `contents.navigationHistory` _Readonly_ + +A [`NavigationHistory`](navigation-history.md) used by this webContents. + #### `contents.hostWebContents` _Readonly_ A [`WebContents`](web-contents.md) instance that might own this `WebContents`. @@ -2014,6 +2371,15 @@ A [`Debugger`](debugger.md) instance for this webContents. #### `contents.backgroundThrottling` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/38924 + description: "`WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow`" + breaking-changes-header: behavior-changed-webcontentsbackgroundthrottling-set-to-false-affects-all-webcontents-in-the-host-browserwindow +``` +--> + A `boolean` property that determines whether or not this WebContents will throttle animations and timers when the page becomes backgrounded. This also affects the Page Visibility API. @@ -2021,7 +2387,13 @@ when the page becomes backgrounded. This also affects the Page Visibility API. A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of the page's frame hierarchy. +#### `contents.opener` _Readonly_ + +A [`WebFrameMain`](web-frame-main.md) property that represents the frame that opened this WebContents, either +with open(), or by navigating a link with a target attribute. + [keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage +[`MessagePortMain`]: message-port-main.md diff --git a/docs/api/web-frame-main.md b/docs/api/web-frame-main.md index 8ce004b6e9172..45b01d5b25a25 100644 --- a/docs/api/web-frame-main.md +++ b/docs/api/web-frame-main.md @@ -8,7 +8,7 @@ The `webFrameMain` module can be used to lookup frames across existing [`WebContents`](web-contents.md) instances. Navigation events are the common use case. -```javascript +```js const { BrowserWindow, webFrameMain } = require('electron') const win = new BrowserWindow({ width: 800, height: 1500 }) @@ -29,7 +29,7 @@ win.webContents.on( You can also access frames of existing pages by using the `mainFrame` property of [`WebContents`](web-contents.md). -```javascript +```js const { BrowserWindow } = require('electron') async function main () { @@ -97,16 +97,19 @@ this limitation. Returns `boolean` - Whether the reload was initiated successfully. Only results in `false` when the frame has no history. +#### `frame.isDestroyed()` + +Returns `boolean` - Whether the frame is destroyed. + #### `frame.send(channel, ...args)` * `channel` string * `...args` any[] Send an asynchronous message to the renderer process via `channel`, along with -arguments. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be -included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will -throw an exception. +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`postMessage`][], so prototype chains will not be included. +Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. The renderer process can handle the message by listening to `channel` with the [`ipcRenderer`](ipc-renderer.md) module. @@ -128,8 +131,9 @@ For example: ```js // Main process +const win = new BrowserWindow() const { port1, port2 } = new MessageChannelMain() -webContents.mainFrame.postMessage('port', { message: 'hello' }, [port1]) +win.webContents.mainFrame.postMessage('port', { message: 'hello' }, [port1]) // Renderer process ipcRenderer.on('port', (e, msg) => { @@ -138,6 +142,29 @@ ipcRenderer.on('port', (e, msg) => { }) ``` +#### `frame.collectJavaScriptCallStack()` _Experimental_ + +Returns `Promise<string> | Promise<void>` - A promise that resolves with the currently running JavaScript call +stack. If no JavaScript runs in the frame, the promise will never resolve. In cases where the call stack is +otherwise unable to be collected, it will return `undefined`. + +This can be useful to determine why the frame is unresponsive in cases where there's long-running JavaScript. +For more information, see the [proposed Crash Reporting API.](https://wicg.github.io/crash-reporting/) + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('enable-features', 'DocumentPolicyIncludeJSCallStacksInCrashReports') + +app.on('web-contents-created', (_, webContents) => { + webContents.on('unresponsive', async () => { + // Interrupt execution and collect call stack from unresponsive renderer + const callStack = await webContents.mainFrame.collectJavaScriptCallStack() + console.log('Renderer unresponsive\n', callStack) + }) +}) +``` + ### Instance Properties #### `frame.ipc` _Readonly_ @@ -169,6 +196,16 @@ convenient when `nodeIntegrationInSubFrames` is not enabled. A `string` representing the current URL of the frame. +#### `frame.origin` _Readonly_ + +A `string` representing the current origin of the frame, serialized according +to [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454). This may be different +from the URL. For instance, if the frame is a child window opened to +`about:blank`, then `frame.origin` will return the parent frame's origin, while +`frame.url` will return the empty string. Pages without a scheme/host/port +triple origin will have the serialized origin of `"null"` (that is, the string +containing the letters n, u, l, l). + #### `frame.top` _Readonly_ A `WebFrameMain | null` representing top frame in the frame hierarchy to which `frame` @@ -221,5 +258,13 @@ A `string` representing the [visibility state](https://developer.mozilla.org/en- See also how the [Page Visibility API](browser-window.md#page-visibility) is affected by other Electron APIs. +#### `frame.detached` _Readonly_ + +A `Boolean` representing whether the frame is detached from the frame tree. If a frame is accessed +while the corresponding page is running any [unload][] listeners, it may become detached as the +newly navigated page replaced it in the frame tree. + [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage +[`MessagePortMain`]: message-port-main.md +[unload]: https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 06bf313547d01..b0148f4bfe043 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -10,7 +10,7 @@ certain properties and methods (e.g. `webFrame.firstChild`). An example of zooming current page to 200%. -```javascript +```js const { webFrame } = require('electron') webFrame.setZoomFactor(2) @@ -96,13 +96,12 @@ with an array of misspelt words when complete. An example of using [node-spellchecker][spellchecker] as provider: -```javascript +```js @ts-expect-error=[2,6] const { webFrame } = require('electron') const spellChecker = require('spellchecker') webFrame.setSpellCheckProvider('en-US', { spellCheck (words, callback) { setTimeout(() => { - const spellchecker = require('spellchecker') const misspelled = words.filter(x => spellchecker.isMisspelled(x)) callback(misspelled) }, 0) @@ -114,7 +113,7 @@ webFrame.setSpellCheckProvider('en-US', { * `css` string * `options` Object (optional) - * `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. + * `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. Returns `string` - A key for the inserted CSS that can later be used to remove the CSS via `webFrame.removeInsertedCSS(key)`. @@ -183,7 +182,7 @@ dispatch errors of isolated worlds to foreign worlds. ### `webFrame.setIsolatedWorldInfo(worldId, info)` -* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electrons `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here. +* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here. * `info` Object * `securityOrigin` string (optional) - Security origin for the isolated world. * `csp` string (optional) - Content Security Policy for the isolated world. @@ -206,14 +205,14 @@ Returns `Object`: Returns an object describing usage information of Blink's internal memory caches. -```javascript +```js const { webFrame } = require('electron') console.log(webFrame.getResourceUsage()) ``` This will generate: -```javascript +```js { images: { count: 22, diff --git a/docs/api/web-request.md b/docs/api/web-request.md index 9f3e4347ccf5d..062084831d67e 100644 --- a/docs/api/web-request.md +++ b/docs/api/web-request.md @@ -23,12 +23,12 @@ called with a `response` object when `listener` has done its work. An example of adding `User-Agent` header for requests: -```javascript +```js const { session } = require('electron') // Modify the user agent for all requests to the following urls. const filter = { - urls: ['https://*.github.com/*', '*://electron.github.io'] + urls: ['https://*.github.com/*', '*://electron.github.io/*'] } session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => { @@ -51,7 +51,8 @@ The following methods are available on instances of `WebRequest`: * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double @@ -94,16 +95,17 @@ Some examples of valid `urls`: * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double * `uploadData` [UploadData[]](structures/upload-data.md) (optional) - * `requestHeaders` Record<string, string> + * `requestHeaders` Record\<string, string\> * `callback` Function * `beforeSendResponse` Object * `cancel` boolean (optional) - * `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made + * `requestHeaders` Record\<string, string | string[]\> (optional) - When provided, request will be made with these headers. The `listener` will be called with `listener(details, callback)` before sending @@ -122,11 +124,12 @@ The `callback` has to be called with a `response` object. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double - * `requestHeaders` Record<string, string> + * `requestHeaders` Record\<string, string\> The `listener` will be called with `listener(details)` just before a request is going to be sent to the server, modifications of previous `onBeforeSendHeaders` @@ -142,17 +145,18 @@ response are visible by the time this listener is fired. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double * `statusLine` string * `statusCode` Integer - * `responseHeaders` Record<string, string[]> (optional) + * `responseHeaders` Record\<string, string[]\> (optional) * `callback` Function * `headersReceivedResponse` Object * `cancel` boolean (optional) - * `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed + * `responseHeaders` Record\<string, string | string[]\> (optional) - When provided, the server is assumed to have responded with these headers. * `statusLine` string (optional) - Should be provided when overriding `responseHeaders` to change header status otherwise original response @@ -173,11 +177,12 @@ The `callback` has to be called with a `response` object. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double - * `responseHeaders` Record<string, string[]> (optional) + * `responseHeaders` Record\<string, string[]\> (optional) * `fromCache` boolean - Indicates whether the response was fetched from disk cache. * `statusCode` Integer @@ -197,7 +202,8 @@ and response headers are available. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double @@ -207,7 +213,7 @@ and response headers are available. * `ip` string (optional) - The server IP address that the request was actually sent to. * `fromCache` boolean - * `responseHeaders` Record<string, string[]> (optional) + * `responseHeaders` Record\<string, string[]\> (optional) The `listener` will be called with `listener(details)` when a server initiated redirect is about to occur. @@ -222,11 +228,12 @@ redirect is about to occur. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double - * `responseHeaders` Record<string, string[]> (optional) + * `responseHeaders` Record\<string, string[]\> (optional) * `fromCache` boolean * `statusCode` Integer * `statusLine` string @@ -245,7 +252,8 @@ completed. * `method` string * `webContentsId` Integer (optional) * `webContents` WebContents (optional) - * `frame` WebFrameMain (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. * `referrer` string * `timestamp` Double diff --git a/docs/api/web-utils.md b/docs/api/web-utils.md new file mode 100644 index 0000000000000..2162d9b36cbfc --- /dev/null +++ b/docs/api/web-utils.md @@ -0,0 +1,26 @@ +# webUtils + +> A utility layer to interact with Web API objects (Files, Blobs, etc.) + +Process: [Renderer](../glossary.md#renderer-process) + +## Methods + +The `webUtils` module has the following methods: + +### `webUtils.getPathForFile(file)` + +* `file` File - A web [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object. + +Returns `string` - The file system path that this `File` object points to. In the case where the object passed in is not a `File` object an exception is thrown. In the case where the File object passed in was constructed in JS and is not backed by a file on disk an empty string is returned. + +This method superseded the previous augmentation to the `File` object with the `path` property. An example is included below. + +```js +// Before +const oldPath = document.querySelector('input').files[0].path + +// After +const { webUtils } = require('electron') +const newPath = webUtils.getPathForFile(document.querySelector('input').files[0]) +``` diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 499d348b4c507..14103680f7f4e 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -4,9 +4,10 @@ Electron's `webview` tag is based on [Chromium's `webview`][chrome-webview], which is undergoing dramatic architectural changes. This impacts the stability of `webviews`, -including rendering, navigation, and event routing. We currently recommend to not -use the `webview` tag and to consider alternatives, like `iframe`, [Electron's `BrowserView`](browser-view.md), -or an architecture that avoids embedded content altogether. +including rendering, navigation, and event routing. We currently recommend to +not use the `webview` tag and to consider alternatives, like `iframe`, a +[`WebContentsView`](web-contents-view.md), or an architecture that avoids +embedded content altogether. ## Enabling @@ -112,7 +113,7 @@ The `src` attribute can also accept data URLs, such as ### `nodeintegration` ```html -<webview src="http://www.google.com/" nodeintegration></webview> +<webview src="https://www.google.com/" nodeintegration></webview> ``` A `boolean`. When this attribute is present the guest page in `webview` will have node @@ -123,7 +124,7 @@ page. ### `nodeintegrationinsubframes` ```html -<webview src="http://www.google.com/" nodeintegrationinsubframes></webview> +<webview src="https://www.google.com/" nodeintegrationinsubframes></webview> ``` A `boolean` for the experimental option for enabling NodeJS support in sub-frames such as iframes @@ -161,7 +162,7 @@ after this script has finished executing. ### `httpreferrer` ```html -<webview src="https://www.github.com/" httpreferrer="http://cheng.guru"></webview> +<webview src="https://www.github.com/" httpreferrer="https://example.com/"></webview> ``` A `string` that sets the referrer URL for the guest page. @@ -184,6 +185,8 @@ page is loaded, use the `setUserAgent` method to change the user agent. A `boolean`. When this attribute is present the guest page will have web security disabled. Web security is enabled by default. +This value can only be modified before the first navigation. + ### `partition` ```html @@ -253,7 +256,7 @@ The `webview` tag has the following methods: **Example** -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('dom-ready', () => { webview.openDevTools() @@ -278,9 +281,11 @@ if the page fails to load (see Loads the `url` in the webview, the `url` must contain the protocol prefix, e.g. the `http://` or `file://`. -### `<webview>.downloadURL(url)` +### `<webview>.downloadURL(url[, options])` * `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url` without navigating. @@ -463,6 +468,10 @@ Executes editing command `cut` in page. Executes editing command `copy` in page. +#### `<webview>.centerSelection()` + +Centers the current text selection in page. + ### `<webview>.paste()` Executes editing command `paste` in page. @@ -483,6 +492,25 @@ Executes editing command `selectAll` in page. Executes editing command `unselect` in page. +#### `<webview>.scrollToTop()` + +Scrolls to the top of the current `<webview>`. + +#### `<webview>.scrollToBottom()` + +Scrolls to the bottom of the current `<webview>`. + +#### `<webview>.adjustSelection(options)` + +* `options` Object + * `start` Number (optional) - Amount to shift the start index of the current selection. + * `end` Number (optional) - Amount to shift the end index of the current selection. + +Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document. + +See [`webContents.adjustSelection`](web-contents.md#contentsadjustselectionoptions) for +examples. + ### `<webview>.replace(text)` * `text` string @@ -550,7 +578,7 @@ Stops any `findInPage` request for the `webview` with the provided `action`. * `from` number - Index of the first page to print (0-based). * `to` number - Index of the last page to print (inclusive) (0-based). * `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. - * `dpi` Record<string, number> (optional) + * `dpi` Record\<string, number\> (optional) * `horizontal` number (optional) - The horizontal dpi. * `vertical` number (optional) - The vertical dpi. * `header` string (optional) - string to be printed as page header. @@ -576,10 +604,12 @@ Prints `webview`'s web page. Same as `webContents.print([options])`. * `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches). * `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches). * `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches). - * `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. + * `pageRanges` string (optional) - Page ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. * `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title. * `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`. * `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. + * `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards. + * `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false. Returns `Promise<Uint8Array>` - Resolves with the generated PDF data. @@ -609,7 +639,7 @@ examples. ### `<webview>.sendToFrame(frameId, channel, ...args)` -* `frameId` [number, number] - `[processId, frameId]` +* `frameId` \[number, number] - `[processId, frameId]` * `channel` string * `...args` any[] @@ -774,7 +804,7 @@ Fired when the guest window logs a console message. The following example code forwards all log messages to the embedder's console without regard for log level or other properties. -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('console-message', (e) => { console.log('Guest page logged a message:', e.message) @@ -795,7 +825,7 @@ Returns: Fired when a result is available for [`webview.findInPage`](#webviewfindinpagetext-options) request. -```javascript +```js @ts-expect-error=[3,6] const webview = document.querySelector('webview') webview.addEventListener('found-in-page', (e) => { webview.stopFindInPage('keepSelection') @@ -821,7 +851,29 @@ It is also not emitted during in-page navigation, such as clicking anchor links or updating the `window.location.hash`. Use `did-navigate-in-page` event for this purpose. -Calling `event.preventDefault()` does __NOT__ have any effect. +Calling `event.preventDefault()` does **NOT** have any effect. + +### Event: 'will-frame-navigate' + +Returns: + +* `url` string +* `isMainFrame` boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted when a user or the page wants to start navigation anywhere in the `<webview>` +or any frames embedded within. It can happen when the `window.location` object is +changed or a user clicks a link in the page. + +This event will not emit when the navigation is started programmatically with +APIs like `<webview>.loadURL` and `<webview>.back`. + +It is also not emitted during in-page navigation, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. + +Calling `event.preventDefault()` does **NOT** have any effect. ### Event: 'did-start-navigation' @@ -898,7 +950,7 @@ Fired when the guest page attempts to close itself. The following example code navigates the `webview` to `about:blank` when the guest attempts to close itself. -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('close', () => { webview.src = 'about:blank' @@ -909,7 +961,7 @@ webview.addEventListener('close', () => { Returns: -* `frameId` [number, number] - pair of `[processId, frameId]`. +* `frameId` \[number, number] - pair of `[processId, frameId]`. * `channel` string * `args` any[] @@ -918,7 +970,7 @@ Fired when the guest page has sent an asynchronous message to embedder page. With `sendToHost` method and `ipc-message` event you can communicate between guest page and embedder page: -```javascript +```js @ts-expect-error=[4,7] // In embedder page. const webview = document.querySelector('webview') webview.addEventListener('ipc-message', (event) => { @@ -928,7 +980,7 @@ webview.addEventListener('ipc-message', (event) => { webview.send('ping') ``` -```javascript +```js // In guest page. const { ipcRenderer } = require('electron') ipcRenderer.on('ping', () => { @@ -936,9 +988,14 @@ ipcRenderer.on('ping', () => { }) ``` -### Event: 'crashed' +### Event: 'render-process-gone' + +Returns: + +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) -Fired when the renderer process is crashed. +Fired when the renderer process unexpectedly disappears. This is normally +because it was crashed or killed. ### Event: 'plugin-crashed' @@ -981,6 +1038,23 @@ Returns: Emitted when mouse moves over a link or the keyboard moves the focus to a link. +### Event: 'devtools-open-url' + +Returns: + +* `url` string - URL of the link that was clicked or selected. + +Emitted when a link is clicked in DevTools or 'Open in new tab' is selected for a link in its context menu. + +#### Event: 'devtools-search-query' + +Returns: + +* `event` Event +* `query` string - text to query for. + +Emitted when 'Search' is selected for text in its context menu. + ### Event: 'devtools-opened' Emitted when DevTools is opened. @@ -993,7 +1067,7 @@ Emitted when DevTools is closed. Emitted when DevTools is focused / opened. -[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70 +[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5 [chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/ ### Event: 'context-menu' @@ -1035,9 +1109,15 @@ Returns: word and spellchecker is enabled. * `frameCharset` string - The character encoding of the frame on which the menu was invoked. - * `inputFieldType` string - If the context menu was invoked on an input - field, the type of that field. Possible values are `none`, `plainText`, - `password`, `other`. + * `formControlType` string - The source that the context menu was invoked on. + Possible values include `none`, `button-button`, `field-set`, + `input-button`, `input-checkbox`, `input-color`, `input-date`, + `input-datetime-local`, `input-email`, `input-file`, `input-hidden`, + `input-image`, `input-month`, `input-number`, `input-password`, `input-radio`, + `input-range`, `input-reset`, `input-search`, `input-submit`, `input-telephone`, + `input-text`, `input-time`, `input-url`, `input-week`, `output`, `reset-button`, + `select-list`, `select-list`, `select-multiple`, `select-one`, `submit-button`, + and `text-area`, * `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled. * `menuSourceType` string - Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 1925a5d1e7e5d..7285c956bd056 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -33,12 +33,12 @@ because it is invoked in the main process. Returns [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) | null `features` is a comma-separated key-value list, following the standard format of -the browser. Electron will parse `BrowserWindowConstructorOptions` out of this +the browser. Electron will parse [`BrowserWindowConstructorOptions`](structures/browser-window-options.md) out of this list where possible, for convenience. For full control and better ergonomics, consider using `webContents.setWindowOpenHandler` to customize the BrowserWindow creation. -A subset of `WebPreferences` can be set directly, +A subset of [`WebPreferences`](structures/web-preferences.md) can be set directly, unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, and `webviewTag`. @@ -59,8 +59,8 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn * Non-standard features (that are not handled by Chromium or Electron) given in `features` will be passed to any registered `webContents`'s `did-create-window` event handler in the `options` argument. -* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters). -* When opening `about:blank`, the child window's `WebPreferences` will be copied +* `frameName` follows the specification of `target` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters). +* When opening `about:blank`, the child window's [`WebPreferences`](structures/web-preferences.md) will be copied from the parent window, and there is no way to override it because Chromium skips browser side navigation in this case. @@ -68,7 +68,7 @@ To customize or cancel the creation of the window, you can optionally set an override handler with `webContents.setWindowOpenHandler()` from the main process. Returning `{ action: 'deny' }` cancels the window. Returning `{ action: 'allow', overrideBrowserWindowOptions: { ... } }` will allow opening -the window and setting the `BrowserWindowConstructorOptions` to be used when +the window and setting the [`BrowserWindowConstructorOptions`](structures/browser-window-options.md) to be used when creating the window. Note that this is more powerful than passing options through the feature string, as the renderer has more limited privileges in deciding security preferences than the main process. @@ -80,7 +80,7 @@ window will not close when the opener window closes. The default value is `false ### Native `Window` example -```javascript +```js // main.js const mainWindow = new BrowserWindow() @@ -104,7 +104,7 @@ mainWindow.webContents.setWindowOpenHandler(({ url }) => { }) ``` -```javascript +```js // renderer process (mainWindow) const childWindow = window.open('', 'modal') childWindow.document.write('<h1>Hello</h1>') diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index f7bea50260f1d..67862f71f8746 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -12,14 +12,854 @@ This document uses the following convention to categorize breaking changes: * **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. * **Removed:** An API or feature was removed, and is no longer supported by Electron. +## Planned Breaking API Changes (35.0) + +### Deprecated: `getFromVersionID` on `session.serviceWorkers` + +The `session.serviceWorkers.fromVersionID(versionId)` API has been deprecated +in favor of `session.serviceWorkers.getInfoFromVersionID(versionId)`. This was +changed to make it more clear which object is returned with the introduction +of the `session.serviceWorkers.getWorkerFromVersionID(versionId)` API. + +```js +// Deprecated +session.serviceWorkers.fromVersionID(versionId) + +// Replace with +session.serviceWorkers.getInfoFromVersionID(versionId) +``` + +### Deprecated: `setPreloads`, `getPreloads` on `Session` + +`registerPreloadScript`, `unregisterPreloadScript`, and `getPreloadScripts` are introduced as a +replacement for the deprecated methods. These new APIs allow third-party libraries to register +preload scripts without replacing existing scripts. Also, the new `type` option allows for +additional preload targets beyond `frame`. + +```js +// Deprecated +session.setPreloads([path.join(__dirname, 'preload.js')]) + +// Replace with: +session.registerPreloadScript({ + type: 'frame', + id: 'app-preload', + filePath: path.join(__dirname, 'preload.js') +}) +``` + +### Deprecated: `level`, `message`, `line`, and `sourceId` arguments in `console-message` event on `WebContents` + +The `console-message` event on `WebContents` has been updated to provide details on the `Event` +argument. + +```js +// Deprecated +webContents.on('console-message', (event, level, message, line, sourceId) => {}) + +// Replace with: +webContents.on('console-message', ({ level, message, lineNumber, sourceId, frame }) => {}) +``` + +Additionally, `level` is now a string with possible values of `info`, `warning`, `error`, and `debug`. + +## Planned Breaking API Changes (34.0) + +### Behavior Changed: menu bar will be hidden during fullscreen on Windows + +This brings the behavior to parity with Linux. Prior behavior: Menu bar is still visible during fullscreen on Windows. New behavior: Menu bar is hidden during fullscreen on Windows. + +**Correction**: This was previously listed as a breaking change in Electron 33, but was first released in Electron 34. + +## Planned Breaking API Changes (33.0) + +### Behavior Changed: frame properties may retrieve detached WebFrameMain instances or none at all + +APIs which provide access to a `WebFrameMain` instance may return an instance +with `frame.detached` set to `true`, or possibly return `null`. + +When a frame performs a cross-origin navigation, it enters into a detached state +in which it's no longer attached to the page. In this state, it may be running +[unload](https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event) +handlers prior to being deleted. In the event of an IPC sent during this state, +`frame.detached` will be set to `true` with the frame being destroyed shortly +thereafter. + +When receiving an event, it's important to access WebFrameMain properties +immediately upon being received. Otherwise, it's not guaranteed to point to the +same webpage as when received. To avoid misaligned expectations, Electron will +return `null` in the case of late access where the webpage has changed. + +```js +ipcMain.on('unload-event', (event) => { + event.senderFrame // ✅ accessed immediately +}) + +ipcMain.on('unload-event', async (event) => { + await crossOriginNavigationPromise + event.senderFrame // ❌ returns `null` due to late access +}) +``` + +### Behavior Changed: custom protocol URL handling on Windows + +Due to changes made in Chromium to support [Non-Special Scheme URLs](http://bit.ly/url-non-special), custom protocol URLs that use Windows file paths will no longer work correctly with the deprecated `protocol.registerFileProtocol` and the `baseURLForDataURL` property on `BrowserWindow.loadURL`, `WebContents.loadURL`, and `<webview>.loadURL`. `protocol.handle` will also not work with these types of URLs but this is not a change since it has always worked that way. + +```js +// No longer works +protocol.registerFileProtocol('other', () => { + callback({ filePath: '/path/to/my/file' }) +}) + +const mainWindow = new BrowserWindow() +mainWindow.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: 'other://C:\\myapp' }) +mainWindow.loadURL('other://C:\\myapp\\index.html') + +// Replace with +const path = require('node:path') +const nodeUrl = require('node:url') +protocol.handle(other, (req) => { + const srcPath = 'C:\\myapp\\' + const reqURL = new URL(req.url) + return net.fetch(nodeUrl.pathToFileURL(path.join(srcPath, reqURL.pathname)).toString()) +}) + +mainWindow.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: 'other://' }) +mainWindow.loadURL('other://index.html') +``` + +### Behavior Changed: `webContents` property on `login` on `app` + +The `webContents` property in the `login` event from `app` will be `null` +when the event is triggered for requests from the [utility process](api/utility-process.md) +created with `respondToAuthRequestsFromMainProcess` option. + +### Deprecated: `textured` option in `BrowserWindowConstructorOption.type` + +The `textured` option of `type` in `BrowserWindowConstructorOptions` has been deprecated with no replacement. This option relied on the [`NSWindowStyleMaskTexturedBackground`](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemasktexturedbackground) style mask on macOS, which has been deprecated with no alternative. + +### Removed: macOS 10.15 support + +macOS 10.15 (Catalina) is no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/5734361). + +Older versions of Electron will continue to run on Catalina, but macOS 11 (Big Sur) +or later will be required to run Electron v33.0.0 and higher. + +### Deprecated: `systemPreferences.accessibilityDisplayShouldReduceTransparency` + +The `systemPreferences.accessibilityDisplayShouldReduceTransparency` property is now deprecated in favor of the new `nativeTheme.prefersReducedTransparency`, which provides identical information and works cross-platform. + +```js +// Deprecated +const shouldReduceTransparency = systemPreferences.accessibilityDisplayShouldReduceTransparency + +// Replace with: +const prefersReducedTransparency = nativeTheme.prefersReducedTransparency +``` + +## Planned Breaking API Changes (32.0) + +### Removed: `File.path` + +The nonstandard `path` property of the Web `File` object was added in an early version of Electron as a convenience method for working with native files when doing everything in the renderer was more common. However, it represents a deviation from the standard and poses a minor security risk as well, so beginning in Electron 32.0 it has been removed in favor of the [`webUtils.getPathForFile`](api/web-utils.md#webutilsgetpathforfilefile) method. + +```js +// Before (renderer) + +const file = document.querySelector('input[type=file]').files[0] +alert(`Uploaded file path was: ${file.path}`) +``` + +```js +// After (renderer) + +const file = document.querySelector('input[type=file]').files[0] +electron.showFilePath(file) + +// (preload) +const { contextBridge, webUtils } = require('electron') + +contextBridge.exposeInMainWorld('electron', { + showFilePath (file) { + // It's best not to expose the full file path to the web content if + // possible. + const path = webUtils.getPathForFile(file) + alert(`Uploaded file path was: ${path}`) + } +}) +``` + +### Deprecated: `clearHistory`, `canGoBack`, `goBack`, `canGoForward`, `goForward`, `goToIndex`, `canGoToOffset`, `goToOffset` on `WebContents` + +The navigation-related APIs are now deprecated. + +These APIs have been moved to the `navigationHistory` property of `WebContents` to provide a more structured and intuitive interface for managing navigation history. + +```js +// Deprecated +win.webContents.clearHistory() +win.webContents.canGoBack() +win.webContents.goBack() +win.webContents.canGoForward() +win.webContents.goForward() +win.webContents.goToIndex(index) +win.webContents.canGoToOffset() +win.webContents.goToOffset(index) + +// Replace with +win.webContents.navigationHistory.clear() +win.webContents.navigationHistory.canGoBack() +win.webContents.navigationHistory.goBack() +win.webContents.navigationHistory.canGoForward() +win.webContents.navigationHistory.goForward() +win.webContents.navigationHistory.canGoToOffset() +win.webContents.navigationHistory.goToOffset(index) +``` + +## Planned Breaking API Changes (31.0) + +### Removed: `WebSQL` support + +Chromium has removed support for WebSQL upstream, transitioning it to Android only. See +[Chromium's intent to remove discussion](https://groups.google.com/a/chromium.org/g/blink-dev/c/fWYb6evVA-w/m/wGI863zaAAAJ) +for more information. + +### Behavior Changed: `nativeImage.toDataURL` will preserve PNG colorspace + +PNG decoder implementation has been changed to preserve colorspace data, the +encoded data returned from this function now matches it. + +See [crbug.com/332584706](https://issues.chromium.org/issues/332584706) for more information. + +### Behavior Changed: `window.flashFrame(bool)` will flash dock icon continuously on macOS + +This brings the behavior to parity with Windows and Linux. Prior behavior: The first `flashFrame(true)` bounces the dock icon only once (using the [NSInformationalRequest](https://developer.apple.com/documentation/appkit/nsrequestuserattentiontype/nsinformationalrequest) level) and `flashFrame(false)` does nothing. New behavior: Flash continuously until `flashFrame(false)` is called. This uses the [NSCriticalRequest](https://developer.apple.com/documentation/appkit/nsrequestuserattentiontype/nscriticalrequest) level instead. To explicitly use `NSInformationalRequest` to cause a single dock icon bounce, it is still possible to use [`dock.bounce('informational')`](https://www.electronjs.org/docs/latest/api/dock#dockbouncetype-macos). + +## Planned Breaking API Changes (30.0) + +### Behavior Changed: cross-origin iframes now use Permission Policy to access features + +Cross-origin iframes must now specify features available to a given `iframe` via the `allow` +attribute in order to access them. + +See [documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#allow) for +more information. + +### Removed: The `--disable-color-correct-rendering` switch + +This switch was never formally documented but it's removal is being noted here regardless. Chromium itself now has better support for color spaces so this flag should not be needed. + +### Behavior Changed: `BrowserView.setAutoResize` behavior on macOS + +In Electron 30, BrowserView is now a wrapper around the new [WebContentsView](api/web-contents-view.md) API. + +Previously, the `setAutoResize` function of the `BrowserView` API was backed by [autoresizing](https://developer.apple.com/documentation/appkit/nsview/1483281-autoresizingmask?language=objc) on macOS, and by a custom algorithm on Windows and Linux. +For simple use cases such as making a BrowserView fill the entire window, the behavior of these two approaches was identical. +However, in more advanced cases, BrowserViews would be autoresized differently on macOS than they would be on other platforms, as the custom resizing algorithm for Windows and Linux did not perfectly match the behavior of macOS's autoresizing API. +The autoresizing behavior is now standardized across all platforms. + +If your app uses `BrowserView.setAutoResize` to do anything more complex than making a BrowserView fill the entire window, it's likely you already had custom logic in place to handle this difference in behavior on macOS. +If so, that logic will no longer be needed in Electron 30 as autoresizing behavior is consistent. + +### Deprecated: `BrowserView` + +The [`BrowserView`](./api/browser-view.md) class has been deprecated and +replaced by the new [`WebContentsView`](./api/web-contents-view.md) class. + +`BrowserView` related methods in [`BrowserWindow`](./api/browser-window.md) have +also been deprecated: + +```js +BrowserWindow.fromBrowserView(browserView) +win.setBrowserView(browserView) +win.getBrowserView() +win.addBrowserView(browserView) +win.removeBrowserView(browserView) +win.setTopBrowserView(browserView) +win.getBrowserViews() +``` + +### Removed: `params.inputFormType` property on `context-menu` on `WebContents` + +The `inputFormType` property of the params object in the `context-menu` +event from `WebContents` has been removed. Use the new `formControlType` +property instead. + +### Removed: `process.getIOCounters()` + +Chromium has removed access to this information. + +## Planned Breaking API Changes (29.0) + +### Behavior Changed: `ipcRenderer` can no longer be sent over the `contextBridge` + +Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will now result in +an empty object on the receiving side of the bridge. This change was made to remove / mitigate +a security footgun. You should not directly expose ipcRenderer or its methods over the bridge. +Instead, provide a safe wrapper like below: + +```js +contextBridge.exposeInMainWorld('app', { + onEvent: (cb) => ipcRenderer.on('foo', (e, ...args) => cb(args)) +}) +``` + +### Removed: `renderer-process-crashed` event on `app` + +The `renderer-process-crashed` event on `app` has been removed. +Use the new `render-process-gone` event instead. + +```js +// Removed +app.on('renderer-process-crashed', (event, webContents, killed) => { /* ... */ }) + +// Replace with +app.on('render-process-gone', (event, webContents, details) => { /* ... */ }) +``` + +### Removed: `crashed` event on `WebContents` and `<webview>` + +The `crashed` events on `WebContents` and `<webview>` have been removed. +Use the new `render-process-gone` event instead. + +```js +// Removed +win.webContents.on('crashed', (event, killed) => { /* ... */ }) +webview.addEventListener('crashed', (event) => { /* ... */ }) + +// Replace with +win.webContents.on('render-process-gone', (event, details) => { /* ... */ }) +webview.addEventListener('render-process-gone', (event) => { /* ... */ }) +``` + +### Removed: `gpu-process-crashed` event on `app` + +The `gpu-process-crashed` event on `app` has been removed. +Use the new `child-process-gone` event instead. + +```js +// Removed +app.on('gpu-process-crashed', (event, killed) => { /* ... */ }) + +// Replace with +app.on('child-process-gone', (event, details) => { /* ... */ }) +``` + +## Planned Breaking API Changes (28.0) + +### Behavior Changed: `WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow` + +`WebContents.backgroundThrottling` set to false will disable frames throttling +in the `BrowserWindow` for all `WebContents` displayed by it. + +### Removed: `BrowserWindow.setTrafficLightPosition(position)` + +`BrowserWindow.setTrafficLightPosition(position)` has been removed, the +`BrowserWindow.setWindowButtonPosition(position)` API should be used instead +which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to +system default. + +```js +// Removed in Electron 28 +win.setTrafficLightPosition({ x: 10, y: 10 }) +win.setTrafficLightPosition({ x: 0, y: 0 }) + +// Replace with +win.setWindowButtonPosition({ x: 10, y: 10 }) +win.setWindowButtonPosition(null) +``` + +### Removed: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been removed, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +```js +// Removed in Electron 28 +const pos = win.getTrafficLightPosition() +if (pos.x === 0 && pos.y === 0) { + // No custom position. +} + +// Replace with +const ret = win.getWindowButtonPosition() +if (ret === null) { + // No custom position. +} +``` + +### Removed: `ipcRenderer.sendTo()` + +The `ipcRenderer.sendTo()` API has been removed. It should be replaced by setting up a [`MessageChannel`](tutorial/message-ports.md#setting-up-a-messagechannel-between-two-renderers) between the renderers. + +The `senderId` and `senderIsMainFrame` properties of `IpcRendererEvent` have been removed as well. + +### Removed: `app.runningUnderRosettaTranslation` + +The `app.runningUnderRosettaTranslation` property has been removed. +Use `app.runningUnderARM64Translation` instead. + +```js +// Removed +console.log(app.runningUnderRosettaTranslation) +// Replace with +console.log(app.runningUnderARM64Translation) +``` + +### Deprecated: `renderer-process-crashed` event on `app` + +The `renderer-process-crashed` event on `app` has been deprecated. +Use the new `render-process-gone` event instead. + +```js +// Deprecated +app.on('renderer-process-crashed', (event, webContents, killed) => { /* ... */ }) + +// Replace with +app.on('render-process-gone', (event, webContents, details) => { /* ... */ }) +``` + +### Deprecated: `params.inputFormType` property on `context-menu` on `WebContents` + +The `inputFormType` property of the params object in the `context-menu` +event from `WebContents` has been deprecated. Use the new `formControlType` +property instead. + +### Deprecated: `crashed` event on `WebContents` and `<webview>` + +The `crashed` events on `WebContents` and `<webview>` have been deprecated. +Use the new `render-process-gone` event instead. + +```js +// Deprecated +win.webContents.on('crashed', (event, killed) => { /* ... */ }) +webview.addEventListener('crashed', (event) => { /* ... */ }) + +// Replace with +win.webContents.on('render-process-gone', (event, details) => { /* ... */ }) +webview.addEventListener('render-process-gone', (event) => { /* ... */ }) +``` + +### Deprecated: `gpu-process-crashed` event on `app` + +The `gpu-process-crashed` event on `app` has been deprecated. +Use the new `child-process-gone` event instead. + +```js +// Deprecated +app.on('gpu-process-crashed', (event, killed) => { /* ... */ }) + +// Replace with +app.on('child-process-gone', (event, details) => { /* ... */ }) +``` + +## Planned Breaking API Changes (27.0) + +### Removed: macOS 10.13 / 10.14 support + +macOS 10.13 (High Sierra) and macOS 10.14 (Mojave) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/4629466). + +Older versions of Electron will continue to run on these operating systems, but macOS 10.15 (Catalina) +or later will be required to run Electron v27.0.0 and higher. + +### Deprecated: `ipcRenderer.sendTo()` + +The `ipcRenderer.sendTo()` API has been deprecated. It should be replaced by setting up a [`MessageChannel`](tutorial/message-ports.md#setting-up-a-messagechannel-between-two-renderers) between the renderers. + +The `senderId` and `senderIsMainFrame` properties of `IpcRendererEvent` have been deprecated as well. + +### Removed: color scheme events in `systemPreferences` + +The following `systemPreferences` events have been removed: + +* `inverted-color-scheme-changed` +* `high-contrast-color-scheme-changed` + +Use the new `updated` event on the `nativeTheme` module instead. + +```js +// Removed +systemPreferences.on('inverted-color-scheme-changed', () => { /* ... */ }) +systemPreferences.on('high-contrast-color-scheme-changed', () => { /* ... */ }) + +// Replace with +nativeTheme.on('updated', () => { /* ... */ }) +``` + +### Removed: Some `window.setVibrancy` options on macOS + +The following vibrancy options have been removed: + +* 'light' +* 'medium-light' +* 'dark' +* 'ultra-dark' +* 'appearance-based' + +These were previously deprecated and have been removed by Apple in 10.15. + +### Removed: `webContents.getPrinters` + +The `webContents.getPrinters` method has been removed. Use +`webContents.getPrintersAsync` instead. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed +console.log(w.webContents.getPrinters()) +// Replace with +w.webContents.getPrintersAsync().then((printers) => { + console.log(printers) +}) +``` + +### Removed: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance` + +The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance` +methods have been removed, as well as the `systemPreferences.appLevelAppearance` property. +Use the `nativeTheme` module instead. + +```js +// Removed +systemPreferences.getAppLevelAppearance() +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed +systemPreferences.appLevelAppearance +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed +systemPreferences.setAppLevelAppearance('dark') +// Replace with +nativeTheme.themeSource = 'dark' +``` + +### Removed: `alternate-selected-control-text` value for `systemPreferences.getColor` + +The `alternate-selected-control-text` value for `systemPreferences.getColor` +has been removed. Use `selected-content-background` instead. + +```js +// Removed +systemPreferences.getColor('alternate-selected-control-text') +// Replace with +systemPreferences.getColor('selected-content-background') +``` + +## Planned Breaking API Changes (26.0) + +### Deprecated: `webContents.getPrinters` + +The `webContents.getPrinters` method has been deprecated. Use +`webContents.getPrintersAsync` instead. + +```js +const w = new BrowserWindow({ show: false }) + +// Deprecated +console.log(w.webContents.getPrinters()) +// Replace with +w.webContents.getPrintersAsync().then((printers) => { + console.log(printers) +}) +``` + +### Deprecated: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance` + +The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance` +methods have been deprecated, as well as the `systemPreferences.appLevelAppearance` property. +Use the `nativeTheme` module instead. + +```js +// Deprecated +systemPreferences.getAppLevelAppearance() +// Replace with +nativeTheme.shouldUseDarkColors + +// Deprecated +systemPreferences.appLevelAppearance +// Replace with +nativeTheme.shouldUseDarkColors + +// Deprecated +systemPreferences.setAppLevelAppearance('dark') +// Replace with +nativeTheme.themeSource = 'dark' +``` + +### Deprecated: `alternate-selected-control-text` value for `systemPreferences.getColor` + +The `alternate-selected-control-text` value for `systemPreferences.getColor` +has been deprecated. Use `selected-content-background` instead. + +```js +// Deprecated +systemPreferences.getColor('alternate-selected-control-text') +// Replace with +systemPreferences.getColor('selected-content-background') +``` + +## Planned Breaking API Changes (25.0) + +### Deprecated: `protocol.{un,}{register,intercept}{Buffer,String,Stream,File,Http}Protocol` and `protocol.isProtocol{Registered,Intercepted}` + +The `protocol.register*Protocol` and `protocol.intercept*Protocol` methods have +been replaced with [`protocol.handle`](api/protocol.md#protocolhandlescheme-handler). + +The new method can either register a new protocol or intercept an existing +protocol, and responses can be of any type. + +```js +// Deprecated in Electron 25 +protocol.registerBufferProtocol('some-protocol', () => { + callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return new Response( + Buffer.from('<h5>Response</h5>'), // Could also be a string or ReadableStream. + { headers: { 'content-type': 'text/html' } } + ) +}) +``` + +```js +// Deprecated in Electron 25 +protocol.registerHttpProtocol('some-protocol', () => { + callback({ url: 'https://electronjs.org' }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return net.fetch('https://electronjs.org') +}) +``` + +```js +// Deprecated in Electron 25 +protocol.registerFileProtocol('some-protocol', () => { + callback({ filePath: '/path/to/my/file' }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return net.fetch('file:///path/to/my/file') +}) +``` + +### Deprecated: `BrowserWindow.setTrafficLightPosition(position)` + +`BrowserWindow.setTrafficLightPosition(position)` has been deprecated, the +`BrowserWindow.setWindowButtonPosition(position)` API should be used instead +which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to +system default. + +```js +// Deprecated in Electron 25 +win.setTrafficLightPosition({ x: 10, y: 10 }) +win.setTrafficLightPosition({ x: 0, y: 0 }) + +// Replace with +win.setWindowButtonPosition({ x: 10, y: 10 }) +win.setWindowButtonPosition(null) +``` + +### Deprecated: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been deprecated, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +```js +// Deprecated in Electron 25 +const pos = win.getTrafficLightPosition() +if (pos.x === 0 && pos.y === 0) { + // No custom position. +} + +// Replace with +const ret = win.getWindowButtonPosition() +if (ret === null) { + // No custom position. +} +``` + +## Planned Breaking API Changes (24.0) + +### API Changed: `nativeImage.createThumbnailFromPath(path, size)` + +The `maxSize` parameter has been changed to `size` to reflect that the size passed in will be the size the thumbnail created. Previously, Windows would not scale the image up if it were smaller than `maxSize`, and +macOS would always set the size to `maxSize`. Behavior is now the same across platforms. + +Updated Behavior: + +```js +// a 128x128 image. +const imagePath = path.join('path', 'to', 'capybara.png') + +// Scaling up a smaller image. +const upSize = { width: 256, height: 256 } +nativeImage.createThumbnailFromPath(imagePath, upSize).then(result => { + console.log(result.getSize()) // { width: 256, height: 256 } +}) + +// Scaling down a larger image. +const downSize = { width: 64, height: 64 } +nativeImage.createThumbnailFromPath(imagePath, downSize).then(result => { + console.log(result.getSize()) // { width: 64, height: 64 } +}) +``` + +Previous Behavior (on Windows): + +```js +// a 128x128 image +const imagePath = path.join('path', 'to', 'capybara.png') +const size = { width: 256, height: 256 } +nativeImage.createThumbnailFromPath(imagePath, size).then(result => { + console.log(result.getSize()) // { width: 128, height: 128 } +}) +``` + +## Planned Breaking API Changes (23.0) + +### Behavior Changed: Draggable Regions on macOS + +The implementation of draggable regions (using the CSS property `-webkit-app-region: drag`) has changed on macOS to bring it in line with Windows and Linux. Previously, when a region with `-webkit-app-region: no-drag` overlapped a region with `-webkit-app-region: drag`, the `no-drag` region would always take precedence on macOS, regardless of CSS layering. That is, if a `drag` region was above a `no-drag` region, it would be ignored. Beginning in Electron 23, a `drag` region on top of a `no-drag` region will correctly cause the region to be draggable. + +Additionally, the `customButtonsOnHover` BrowserWindow property previously created a draggable region which ignored the `-webkit-app-region` CSS property. This has now been fixed (see [#37210](https://github.com/electron/electron/issues/37210#issuecomment-1440509592) for discussion). + +As a result, if your app uses a frameless window with draggable regions on macOS, the regions which are draggable in your app may change in Electron 23. + +### Removed: Windows 7 / 8 / 8.1 support + +[Windows 7, Windows 8, and Windows 8.1 are no longer supported](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). Electron follows the planned Chromium deprecation policy, which will [deprecate Windows 7 support beginning in Chromium 109](https://support.google.com/chrome/thread/185534985/sunsetting-support-for-windows-7-8-8-1-in-early-2023?hl=en). + +Older versions of Electron will continue to run on these operating systems, but Windows 10 or later will be required to run Electron v23.0.0 and higher. + +### Removed: BrowserWindow `scroll-touch-*` events + +The deprecated `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` +events on BrowserWindow have been removed. Instead, use the newly available +[`input-event` event](api/web-contents.md#event-input-event) on WebContents. + +```js +// Removed in Electron 23.0 +win.on('scroll-touch-begin', scrollTouchBegin) +win.on('scroll-touch-edge', scrollTouchEdge) +win.on('scroll-touch-end', scrollTouchEnd) + +// Replace with +win.webContents.on('input-event', (_, event) => { + if (event.type === 'gestureScrollBegin') { + scrollTouchBegin() + } else if (event.type === 'gestureScrollUpdate') { + scrollTouchEdge() + } else if (event.type === 'gestureScrollEnd') { + scrollTouchEnd() + } +}) +``` + +### Removed: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.incrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.decrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + ## Planned Breaking API Changes (22.0) +### Deprecated: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +`webContents.incrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Deprecated: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +`webContents.decrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + ### Removed: WebContents `new-window` event The `new-window` event of WebContents has been removed. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler). ```js -// Removed in Electron 21 +// Removed in Electron 22 webContents.on('new-window', (event) => { event.preventDefault() }) @@ -30,13 +870,70 @@ webContents.setWindowOpenHandler((details) => { }) ``` -## Planned Breaking API Changes (20.0) +### Removed: `<webview>` `new-window` event + +The `new-window` event of `<webview>` has been removed. There is no direct replacement. + +```js +// Removed in Electron 22 +webview.addEventListener('new-window', (event) => {}) +``` + +```js +// Replace with + +// main.js +mainWindow.webContents.on('did-attach-webview', (event, wc) => { + wc.setWindowOpenHandler((details) => { + mainWindow.webContents.send('webview-new-window', wc.id, details) + return { action: 'deny' } + }) +}) + +// preload.js +const { ipcRenderer } = require('electron') +ipcRenderer.on('webview-new-window', (e, webContentsId, details) => { + console.log('webview-new-window', webContentsId, details) + document.getElementById('webview').dispatchEvent(new Event('new-window')) +}) + +// renderer.js +document.getElementById('webview').addEventListener('new-window', () => { + console.log('got new-window event') +}) +``` + +### Deprecated: BrowserWindow `scroll-touch-*` events + +The `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` events on +BrowserWindow are deprecated. Instead, use the newly available +[`input-event` event](api/web-contents.md#event-input-event) on WebContents. + +```js +// Deprecated +win.on('scroll-touch-begin', scrollTouchBegin) +win.on('scroll-touch-edge', scrollTouchEdge) +win.on('scroll-touch-end', scrollTouchEnd) + +// Replace with +win.webContents.on('input-event', (_, event) => { + if (event.type === 'gestureScrollBegin') { + scrollTouchBegin() + } else if (event.type === 'gestureScrollUpdate') { + scrollTouchEdge() + } else if (event.type === 'gestureScrollEnd') { + scrollTouchEnd() + } +}) +``` + +## Planned Breaking API Changes (21.0) ### Behavior Changed: V8 Memory Cage enabled The V8 memory cage has been enabled, which has implications for native modules -which wrap non-V8 memory with `ArrayBuffer` or `Buffer`. See the [blog post -about the V8 memory cage](https://www.electronjs.org/blog/v8-memory-cage) for +which wrap non-V8 memory with `ArrayBuffer` or `Buffer`. See the +[blog post about the V8 memory cage](https://www.electronjs.org/blog/v8-memory-cage) for more details. ### API Changed: `webContents.printToPDF()` @@ -94,6 +991,15 @@ webContents.printToPDF({ }) ``` +## Planned Breaking API Changes (20.0) + +### Removed: macOS 10.11 / 10.12 support + +macOS 10.11 (El Capitan) and macOS 10.12 (Sierra) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/3646050). + +Older versions of Electron will continue to run on these operating systems, but macOS 10.13 (High Sierra) +or later will be required to run Electron v20.0.0 and higher. + ### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default Previously, renderers that specified a preload script defaulted to being @@ -118,7 +1024,7 @@ requires unsafe mode), so Electron is unable to support this feature on Linux. The handler invoked when `session.setDevicePermissionHandler(handler)` is used has a change to its arguments. This handler no longer is passed a frame -`[WebFrameMain](api/web-frame-main.md)`, but instead is passed the `origin`, which +[`WebFrameMain`](api/web-frame-main.md), but instead is passed the `origin`, which is the origin that is checking for device permission. ## Planned Breaking API Changes (19.0) @@ -219,6 +1125,18 @@ to open synchronously scriptable child windows, among other incompatibilities. See the documentation for [window.open in Electron](api/window-open.md) for more details. +### Deprecated: `app.runningUnderRosettaTranslation` + +The `app.runningUnderRosettaTranslation` property has been deprecated. +Use `app.runningUnderARM64Translation` instead. + +```js +// Deprecated +console.log(app.runningUnderRosettaTranslation) +// Replace with +console.log(app.runningUnderARM64Translation) +``` + ## Planned Breaking API Changes (14.0) ### Removed: `remote` module @@ -617,8 +1535,7 @@ const w = new BrowserWindow({ }) ``` -We [recommend moving away from the remote -module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). +We [recommend moving away from the remote module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). ### `protocol.unregisterProtocol` @@ -626,7 +1543,7 @@ module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful- The APIs are now synchronous and the optional callback is no longer needed. -```javascript +```js // Deprecated protocol.unregisterProtocol(scheme, () => { /* ... */ }) // Replace with @@ -655,7 +1572,7 @@ protocol.unregisterProtocol(scheme) The APIs are now synchronous and the optional callback is no longer needed. -```javascript +```js // Deprecated protocol.registerFileProtocol(scheme, handler, () => { /* ... */ }) // Replace with @@ -670,7 +1587,7 @@ until navigation happens. This API is deprecated and users should use `protocol.isProtocolRegistered` and `protocol.isProtocolIntercepted` instead. -```javascript +```js // Deprecated protocol.isProtocolHandled(scheme).then(() => { /* ... */ }) // Replace with @@ -778,12 +1695,11 @@ You can see the original API proposal and reasoning [here](https://github.com/el ### Behavior Changed: Values sent over IPC are now serialized with Structured Clone Algorithm -The algorithm used to serialize objects sent over IPC (through -`ipcRenderer.send`, `ipcRenderer.sendSync`, `WebContents.send` and related -methods) has been switched from a custom algorithm to V8's built-in [Structured -Clone Algorithm][SCA], the same algorithm used to serialize messages for -`postMessage`. This brings about a 2x performance improvement for large -messages, but also brings some breaking changes in behavior. +The algorithm used to serialize objects sent over IPC (through `ipcRenderer.send`, +`ipcRenderer.sendSync`, `WebContents.send` and related methods) has been switched from a custom +algorithm to V8's built-in [Structured Clone Algorithm][SCA], the same algorithm used to serialize +messages for `postMessage`. This brings about a 2x performance improvement for large messages, +but also brings some breaking changes in behavior. * Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any such values, over IPC will now throw an exception, instead of silently @@ -1009,7 +1925,7 @@ folder └── file3 ``` -In Electron <=6, this would return a `FileList` with a `File` object for: +In Electron <=6, this would return a `FileList` with a `File` object for: ```console path/to/folder @@ -1025,7 +1941,7 @@ In Electron 7, this now returns a `FileList` with a `File` object for: Note that `webkitdirectory` no longer exposes the path to the selected folder. If you require the path to the selected folder rather than the folder contents, -see the `dialog.showOpenDialog` API ([link](api/dialog.md#dialogshowopendialogbrowserwindow-options)). +see the `dialog.showOpenDialog` API ([link](api/dialog.md#dialogshowopendialogwindow-options)). ### API Changed: Callback-based versions of promisified APIs @@ -1290,8 +2206,8 @@ app.getGPUInfo('basic') When building native modules for windows, the `win_delay_load_hook` variable in the module's `binding.gyp` must be true (which is the default). If this hook is not present, then the native module will fail to load on Windows, with an error -message like `Cannot find module`. See the [native module -guide](/docs/tutorial/using-native-node-modules.md) for more. +message like `Cannot find module`. +See the [native module guide](./tutorial/using-native-node-modules.md) for more. ### Removed: IA32 Linux support diff --git a/docs/development/README.md b/docs/development/README.md index fcf147f1cac0f..2fcb45e965731 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -54,7 +54,7 @@ See [issues](issues.md) for more information. Most pull requests opened against the `electron/electron` repository include changes to either the C/C++ code in the `shell/` folder, the TypeScript code in the `lib/` folder, the documentation in `docs/`, -or tests in the `spec/` and `spec-main/` folders. +or tests in the `spec/` folder. See [pull requests](pull-requests.md) for more information. diff --git a/docs/development/api-history-migration-guide.md b/docs/development/api-history-migration-guide.md new file mode 100644 index 0000000000000..f4128dbf527de --- /dev/null +++ b/docs/development/api-history-migration-guide.md @@ -0,0 +1,190 @@ +# Electron API History Migration Guide + +This document demonstrates how to add API History blocks to existing APIs. + +## API history information + +Here are some resources you can use to find information on the history of an API: + +### Breaking Changes + +* [`breaking-changes.md`](../breaking-changes.md) + +### Additions + +* `git blame` +* [Release notes](https://github.com/electron/electron/releases/) +* [`electron-api-historian`](https://github.com/electron/electron-api-historian) + +## Example + +> [!NOTE] +> The associated API is already removed, we will ignore that for the purpose of +> this example. + +If we search through [`breaking-changes.md`](../breaking-changes.md) we can find +[a function that was deprecated in Electron `25.0`](../breaking-changes.md#deprecated-browserwindowsettrafficlightpositionposition). + +```markdown +<!-- docs/breaking-changes.md --> +### Deprecated: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been deprecated, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +<!-- docs/api/browser-window.md --> +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +``` + +We can then use `git blame` to find the Pull Request associated with that entry: + +```bash +$ grep -n "BrowserWindow.getTrafficLightPosition" docs/breaking-changes.md +523:### Deprecated: `BrowserWindow.getTrafficLightPosition()` +525:`BrowserWindow.getTrafficLightPosition()` has been deprecated, the + +$ git blame -L523,524 -- docs/breaking-changes.md +1e206deec3e (Keeley Hammond 2023-04-06 21:23:29 -0700 523) ### Deprecated: `BrowserWindow.getTrafficLightPosition()` +1e206deec3e (Keeley Hammond 2023-04-06 21:23:29 -0700 524) + +$ git log -1 1e206deec3e +commit 1e206deec3ef142460c780307752a84782f9baed (tag: v26.0.0-nightly.20230407) +Author: Keeley Hammond <vertedinde@electronjs.org> +Date: Thu Apr 6 21:23:29 2023 -0700 + + docs: update E24/E25 breaking changes (#37878) <-- This is the associated Pull Request +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +> [!NOTE] +> Refer to the [API History section of `styleguide.md`](../styleguide.md#api-history) +for information on how to create API History blocks. + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/37878 + breaking-changes-header: deprecated-browserwindowgettrafficlightposition +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` + +You can keep looking through `breaking-changes.md` to find other breaking changes +and add those in. + +You can also use [`git log -L :<funcname>:<file>`](https://git-scm.com/docs/git-log#Documentation/git-log.txt--Lltfuncnamegtltfilegt): + +```bash +$ git log --reverse -L :GetTrafficLightPosition:shell/browser/native_window_mac.mm +commit e01b1831d96d5d68f54af879b00c617358df5372 +Author: Cheng Zhao <zcbenz@gmail.com> +Date: Wed Dec 16 14:30:39 2020 +0900 + + feat: make trafficLightPosition work for customButtonOnHover (#26789) +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22533 +changes: + - pr-url: https://github.com/electron/electron/pull/26789 + description: "Made `trafficLightPosition` option work for `customButtonOnHover` window." + breaking-changes-header: behavior-changed-draggable-regions-on-macos +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` + +We will then look for when the API was originally added: + +```bash +$ git log --reverse -L :GetTrafficLightPosition:shell/browser/native_window_mac.mm +commit 3e2cec83d927b991855e21cc311ca9046e332601 +Author: Samuel Attard <sattard@slack-corp.com> +Date: Thu Mar 5 14:22:12 2020 -0800 + + feat: programmatically modify traffic light positioning (#22533) +``` + +Alternatively, you can use `git blame`: + +```bash +$ git checkout 1e206deec3e^ +HEAD is now at e8c87859c4 fix: showAboutPanel also on linux (#37828) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +1867:#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +$ git blame -L1867,1868 -- docs/api/browser-window.md +0de1012280e (Cheng Zhao 2023-02-17 19:06:32 +0900 1867) #### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1868) + +$ git checkout 0de1012280e^ +HEAD is now at 0a5e634736 test: rename & split internal module tests (#37318) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +1851:#### `win.getTrafficLightPosition()` _macOS_ + +$ git blame -L1851,1852 -- docs/api/browser-window.md +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1851) #### `win.getTrafficLightPosition()` _macOS_ +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1852) + +$ git checkout 3e2cec83d92^ +HEAD is now at 1811751c6c docs: clean up dark mode related docs (#22489) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +(Nothing) + +$ git checkout 3e2cec83d92 +HEAD is now at 3e2cec83d9 feat: programmatically modify traffic light positioning (#22533) +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22533 +changes: + - pr-url: https://github.com/electron/electron/pull/26789 + description: "Made `trafficLightPosition` option work for `customButtonOnHover` window." + breaking-changes-header: behavior-changed-draggable-regions-on-macos +deprecated: + - pr-url: https://github.com/electron/electron/pull/37878 + breaking-changes-header: deprecated-browserwindowgettrafficlightposition +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` diff --git a/docs/development/azure-vm-setup.md b/docs/development/azure-vm-setup.md deleted file mode 100644 index 477e9ee781de0..0000000000000 --- a/docs/development/azure-vm-setup.md +++ /dev/null @@ -1,62 +0,0 @@ -# Updating an Appveyor Azure Image - -Electron CI on Windows uses AppVeyor, which in turn uses Azure VM images to run. Occasionally, these VM images need to be updated due to changes in Chromium requirements. In order to update you will need [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6) and the [Azure PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-1.8.0&viewFallbackFrom=azurermps-6.13.0). - -Occasionally we need to update these images owing to changes in Chromium or other miscellaneous build requirement changes. - -Example Use Case: - * We need `VS15.9` and we have `VS15.7` installed; this would require us to update an Azure image. - -1. Identify the image you wish to modify. - * In [appveyor.yml](https://github.com/electron/electron/blob/main/appveyor.yml), the image is identified by the property *image*. - * The names used correspond to the *"images"* defined for a build cloud, eg the [libcc-20 cloud](https://windows-ci.electronjs.org/build-clouds/8). - * Find the image you wish to modify in the build cloud and make note of the **VHD Blob Path** for that image, which is the value for that corresponding key. - * You will need this URI path to copy into a new image. - * You will also need the storage account name which is labeled in AppVeyor as the **Disk Storage Account Name** - -2. Get the Azure storage account key - * Log into Azure using credentials stored in LastPass (under Azure Enterprise) and then find the storage account corresponding to the name found in AppVeyor. - * Example, for `appveyorlibccbuilds` **Disk Storage Account Name** you'd look for `appveyorlibccbuilds` in the list of storage accounts @ Home < Storage Accounts - * Click into it and look for `Access Keys`, and then you can use any of the keys present in the list. - -3. Get the full virtual machine image URI from Azure - * Navigate to Home < Storage Accounts < `$ACCT_NAME` < Blobs < Images - * In the following list, look for the VHD path name you got from Appveyor and then click on it. - * Copy the whole URL from the top of the subsequent window. - -4. Copy the image using the [Copy Master Image PowerShell script](https://github.com/appveyor/ci/blob/master/scripts/enterprise/copy-master-image-azure.ps1). - * It is essential to copy the VM because if you spin up a VM against an image that image cannot at the same time be used by AppVeyor. - * Use the storage account name, key, and URI obtained from Azure to run this script. - * See Step 3 for URI & when prompted, press enter to use same storage account as destination. - * Use default destination container name `(images)` - * Also, when naming the copy, use a name that indicates what the new image will contain (if that has changed) and date stamp. - * Ex. `libcc-20core-vs2017-15.9-2019-04-15.vhd` - * Go into Azure and get the URI for the newly created image as described in a previous step - -5. Spin up a new VM using the [Create Master VM from VHD PowerShell](https://github.com/appveyor/ci/blob/master/scripts/enterprise/create_master_vm_from_vhd.ps1). - * From PowerShell, execute `ps1` file with `./create_master_vm_from_vhd.ps1` - * You will need the credential information available in the AppVeyor build cloud definition. - * This includes: - * Client ID - * Client Secret - * Tenant ID - * Subscription ID - * Resource Group - * Virtual Network - * You will also need to specify - * Master VM name - just a unique name to identify the temporary VM - * Master VM size - use `Standard_F32s_v2` - * Master VHD URI - use URI obtained @ end of previous step - * Location use `East US` - -6. Log back into Azure and find the VM you just created in Home < Virtual Machines < `$YOUR_NEW_VM` - * You can download a RDP (Remote Desktop) file to access the VM. - -7. Using Microsoft Remote Desktop, click `Connect` to connect to the VM. - * Credentials for logging into the VM are found in LastPass under the `AppVeyor Enterprise master VM` credentials. - -8. Modify the VM as required. - -9. Shut down the VM and then delete it in Azure. - -10. Add the new image to the Appveyor Cloud settings or modify an existing image to point to the new VHD. diff --git a/docs/development/build-instructions-gn.md b/docs/development/build-instructions-gn.md index cd955743df3b9..64c897b5ea59f 100644 --- a/docs/development/build-instructions-gn.md +++ b/docs/development/build-instructions-gn.md @@ -110,22 +110,51 @@ $ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools On Windows: ```sh +# cmd $ cd src $ set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools + +# PowerShell +$ cd src +$ $env:CHROMIUM_BUILDTOOLS_PATH = "$(Get-Location)\buildtools" ``` **To generate Testing build config of Electron:** +On Linux & MacOS + ```sh $ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")" ``` +On Windows: + +```sh +# cmd +$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")" + +# PowerShell +gn gen out/Testing --args="import(\`"//electron/build/args/testing.gn\`")" +``` + **To generate Release build config of Electron:** +On Linux & MacOS + ```sh $ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")" ``` +On Windows: + +```sh +# cmd +$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")" + +# PowerShell +$ gn gen out/Release --args="import(\`"//electron/build/args/release.gn\`")" +``` + **Note:** This will generate a `out/Testing` or `out/Release` build directory under `src/` with the testing or release build depending upon the configuration passed above. You can replace `Testing|Release` with another names, but it should be a subdirectory of `out`. Also you shouldn't have to run `gn gen` again—if you want to change the build arguments, you can run `gn args out/Testing` to bring up an editor. To see the list of available build configuration options, run `gn args out/Testing --list`. @@ -146,7 +175,7 @@ $ ninja -C out/Release electron ``` This will build all of what was previously 'libchromiumcontent' (i.e. the -`content/` directory of `chromium` and its dependencies, incl. WebKit and V8), +`content/` directory of `chromium` and its dependencies, incl. Blink and V8), so it will take a while. The built executable will be under `./out/Testing`: @@ -225,7 +254,7 @@ generate build headers for the modules to compile against, run the following under `src/` directory. ```sh -$ ninja -C out/Testing third_party/electron_node:headers +$ ninja -C out/Testing electron:node_headers ``` You can now [run the tests](testing.md#unit-tests). @@ -281,9 +310,26 @@ $ cd electron $ gclient sync -f ``` +This may also happen if you have checked out a branch (as opposed to having a detached head) in `electron/src/` +or some other dependency’s repository. If that is the case, a `git checkout --detach HEAD` in the appropriate repository should do the trick. + ### I'm being asked for a username/password for chromium-internal.googlesource.com If you see a prompt for `Username for 'https://chrome-internal.googlesource.com':` when running `gclient sync` on Windows, it's probably because the `DEPOT_TOOLS_WIN_TOOLCHAIN` environment variable is not set to 0. Open `Control Panel` → `System and Security` → `System` → `Advanced system settings` and add a system variable `DEPOT_TOOLS_WIN_TOOLCHAIN` with value `0`. This tells `depot_tools` to use your locally installed version of Visual Studio (by default, `depot_tools` will try to download a Google-internal version that only Googlers have access to). + +### `e` Module not found + +If `e` is not recognized despite running `npm i -g @electron/build-tools`, ie: + +```sh +Error: Cannot find module '/Users/<user>/.electron_build_tools/src/e' +``` + +We recommend installing Node through [nvm](https://github.com/nvm-sh/nvm). This allows for easier Node version management, and is often a fix for missing `e` modules. + +### RBE authentication randomly fails with "Token not valid" + +This could be caused by the local clock time on the machine being off by a small amount. Use [time.is](https://time.is/) to check. diff --git a/docs/development/build-instructions-macos.md b/docs/development/build-instructions-macos.md index fb4ef30497727..8ab4670d1971c 100644 --- a/docs/development/build-instructions-macos.md +++ b/docs/development/build-instructions-macos.md @@ -13,6 +13,46 @@ Follow the guidelines below for building **Electron itself** on macOS, for the p * [node.js](https://nodejs.org) (external) * Python >= 3.7 +### Arm64-specific prerequisites + +* Rosetta 2 + * We recommend installing Rosetta if using dependencies that need to cross-compile on x64 and arm64 machines. Rosetta can be installed by using the softwareupdate command line tool. + * `$ softwareupdate --install-rosetta` + ## Building Electron See [Build Instructions: GN](build-instructions-gn.md). + +## Troubleshooting + +### Xcode "incompatible architecture" errors (MacOS arm64-specific) + +If both Xcode and Xcode command line tools are installed (`$ xcode -select --install`, or directly download the correct version [here](https://developer.apple.com/download/all/?q=command%20line%20tools)), but the stack trace says otherwise like so: + +```sh +xcrun: error: unable to load libxcrun +(dlopen(/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode.app/Contents/Developer/usr/lib/libxcrun.dylib), 0x0005): + tried: '/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode.app/Contents/Developer/usr/lib/libxcrun.dylib)' + (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e))), '/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode-11.1.0.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode-11.1.0.app/Contents/Developer/usr/lib/libxcrun.dylib)' (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))).` +``` + +If you are on arm64 architecture, the build script may be pointing to the wrong Xcode version (11.x.y doesn't support arm64). Navigate to `/Users/<user>/.electron_build_tools/third_party/Xcode/` and rename `Xcode-13.3.0.app` to `Xcode.app` to ensure the right Xcode version is used. + +### Certificates fail to verify + +installing [`certifi`](https://pypi.org/project/certifi/) will fix the following error: + +```sh +________ running 'python3 src/tools/clang/scripts/update.py' in '/Users/<user>/electron' +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 5 s ... +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 10 s ... +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 20 s ... +``` + +This issue has to do with Python 3.6 using its [own](https://github.com/python/cpython/blob/560ea272b01acaa6c531cc7d94331b2ef0854be6/Mac/BuildScript/resources/ReadMe.rtf#L35) copy of OpenSSL in lieu of the deprecated Apple-supplied OpenSSL libraries. `certifi` adds a curated bundle of default root certificates. This issue is documented in the Electron repo [here](https://github.com/electron/build-tools/issues/55). Further information about this issue can be found [here](https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error) and [here](https://stackoverflow.com/questions/40684543/how-to-make-python-use-ca-certificates-from-mac-os-truststore). diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 171679ddab5ba..8d7e7943308a4 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -7,13 +7,12 @@ Follow the guidelines below for building **Electron itself** on Windows, for the ## Prerequisites * Windows 10 / Server 2012 R2 or higher -* Visual Studio 2017 15.7.2 or higher - [download VS 2019 Community Edition for - free](https://www.visualstudio.com/vs/) +* Visual Studio 2019 (>=16.0.0) to build, but Visual Studio 2022 (>=17.0.0) is preferred - [download VS 2022 Community Edition for free](https://www.visualstudio.com/vs/) * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio components are required. * If your Visual Studio is installed in a directory other than the default, you'll need to set a few environment variables to point the toolchains to your installation path. - * `vs2019_install = DRIVE:\path\to\Microsoft Visual Studio\2019\Community`, replacing `2019` and `Community` with your installed versions and replacing `DRIVE:` with the drive that Visual Studio is on. Often, this will be `C:`. + * `vs2022_install = DRIVE:\path\to\Microsoft Visual Studio\2022\Community`, replacing `2022` and `Community` with your installed versions and replacing `DRIVE:` with the drive that Visual Studio is on. Often, this will be `C:`. * `WINDOWSSDKDIR = DRIVE:\path\to\Windows Kits\10`, replacing `DRIVE:` with the drive that Windows Kits is on. Often, this will be `C:`. * [Node.js](https://nodejs.org/download/) * [Git](https://git-scm.com) @@ -24,7 +23,7 @@ store from `.pdb` files. SDK, open Visual Studio Installer, select `Modify` → `Individual Components`, scroll down and select the appropriate Windows SDK to install. Another option would be to look at the - [Windows SDK and emulator archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive) + [Windows SDK and emulator archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/) and download the standalone version of the SDK respectively. * The SDK Debugging Tools must also be installed. If the Windows 10 SDK was installed via the Visual Studio installer, then they can be installed by going to: @@ -33,7 +32,7 @@ store from `.pdb` files. Or, you can download the standalone SDK installer and use it to install the Debugging Tools. If you don't currently have a Windows installation, -[dev.microsoftedge.com](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/) +[developer.microsoft.com](https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/) has timebombed versions of Windows that you can use to build Electron. Building Electron is done entirely with command-line scripts and cannot be done @@ -116,10 +115,6 @@ $ git config --system core.longpaths true This can happen during build, when Debugging Tools for Windows has been installed with Windows Driver Kit. Uninstall Windows Driver Kit and install Debugging Tools with steps described above. -### ImportError: No module named win32file - -Make sure you have installed `pywin32` with `pip install pywin32`. - ### Build Scripts Hang Until Keypress This bug is a "feature" of Windows' command prompt. It happens when clicking inside the prompt window with diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md index 6ad450dfbcb55..fc427b5d22a79 100644 --- a/docs/development/chromium-development.md +++ b/docs/development/chromium-development.md @@ -18,8 +18,8 @@ See also [V8 Development](v8-development.md) ### Code Resources -- [Code Search](https://cs.chromium.org/) - Indexed and searchable source code for Chromium and associated projects. -- [Source Code](https://cs.chromium.org/chromium/src/) - The source code for Chromium itself. +- [Code Search](https://source.chromium.org/chromium) - Indexed and searchable source code for Chromium and associated projects. +- [Source Code](https://source.chromium.org/chromium/chromium/src) - The source code for Chromium itself. - [Chromium Review](https://chromium-review.googlesource.com) - The searchable code host which facilitates code reviews for Chromium and related projects. ### Informational Resources diff --git a/docs/development/coding-style.md b/docs/development/coding-style.md index e7e66a357d9cf..98f18a5110641 100644 --- a/docs/development/coding-style.md +++ b/docs/development/coding-style.md @@ -24,8 +24,8 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and ## C++ and Python -For C++ and Python, we follow Chromium's [Coding -Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). +For C++ and Python, we follow Chromium's +[Coding Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). There is also a script `script/cpplint.py` to check whether all files conform. The Python version we are using now is Python 3.9. @@ -41,7 +41,7 @@ etc. * Write [remark](https://github.com/remarkjs/remark) markdown style. -You can run `npm run lint-docs` to ensure that your documentation changes are +You can run `npm run lint:docs` to ensure that your documentation changes are formatted correctly. ## JavaScript @@ -49,7 +49,7 @@ formatted correctly. * Write [standard](https://www.npmjs.com/package/standard) JavaScript style. * File names should be concatenated with `-` instead of `_`, e.g. `file-name.js` rather than `file_name.js`, because in - [github/atom](https://github.com/github/atom) module names are usually in + [atom/atom](https://github.com/atom/atom) module names are usually in the `module-name` form. This rule only applies to `.js` files. * Use newer ES6/ES2015 syntax where appropriate * [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) diff --git a/docs/development/creating-api.md b/docs/development/creating-api.md index 6b6527c66c424..62af7250c15b0 100644 --- a/docs/development/creating-api.md +++ b/docs/development/creating-api.md @@ -129,22 +129,22 @@ void Initialize(v8::Local<v8::Object> exports, In the [`typings/internal-ambient.d.ts`](https://github.com/electron/electron/blob/main/typings/internal-ambient.d.ts) file, we need to append a new property onto the `Process` interface like so: -```ts title='typings/internal-ambient.d.ts' +```ts title='typings/internal-ambient.d.ts' @ts-nocheck interface Process { - _linkedBinding(name: 'electron_browser_{api_name}', Electron.ApiName); + _linkedBinding(name: 'electron_browser_{api_name}'): Electron.ApiName; } ``` At the very bottom of your `api_name.cc` file: ```cpp title='api_name.cc' -NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_{api_name},Initialize) +NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_{api_name},Initialize) ``` In your [`shell/common/node_bindings.cc`](https://github.com/electron/electron/blob/main/shell/common/node_bindings.cc) file, add your node binding name to Electron's built-in modules. ```cpp title='shell/common/node_bindings.cc' -#define ELECTRON_BUILTIN_MODULES(V) \ +#define ELECTRON_BROWSER_MODULES(V) \ V(electron_browser_{api_name}) ``` @@ -158,13 +158,13 @@ We will need to create a new TypeScript file in the path that follows: `"lib/browser/api/{electron_browser_{api_name}}.ts"` -An example of the contents of this file can be found [here](https://github.com/electron/electron/blob/main/lib/browser/api/native-image.ts). +An example of the contents of this file can be found [here](https://github.com/electron/electron/blob/main/lib/browser/api/native-theme.ts). ### Expose your module to TypeScript Add your module to the module list found at `"lib/browser/api/module-list.ts"` like so: -```typescript title='lib/browser/api/module-list.ts' +```ts title='lib/browser/api/module-list.ts' @ts-nocheck export const browserModuleList: ElectronInternal.ModuleEntry[] = [ { name: 'apiName', loader: () => require('./api-name') }, ]; diff --git a/docs/development/debugging-on-windows.md b/docs/development/debugging-on-windows.md index aa047bf6803ef..6aecc0d3818fa 100644 --- a/docs/development/debugging-on-windows.md +++ b/docs/development/debugging-on-windows.md @@ -88,13 +88,13 @@ is doing to the operating system, it can be a valuable resource. For an introduction to ProcMon's basic and advanced debugging features, go check out [this video tutorial][procmon-instructions] provided by Microsoft. -[sys-internals]: https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx -[procmon-instructions]: https://channel9.msdn.com/shows/defrag-tools/defrag-tools-4-process-monitor +[sys-internals]: https://learn.microsoft.com/en-us/sysinternals/downloads/procmon +[procmon-instructions]: https://learn.microsoft.com/en-us/shows/defrag-tools/4-process-monitor ## Using WinDbg <!-- TODO(@codebytere): add images and more information here? --> -It's possible to debug crashes and issues in the Renderer process with [WinDbg](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/getting-started-with-windbg). +It's possible to debug crashes and issues in the Renderer process with [WinDbg](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/getting-started-with-windbg). To attach to a debug a process with WinDbg: diff --git a/docs/development/debugging-with-symbol-server.md b/docs/development/debugging-with-symbol-server.md index 336eb7a54f3f9..276490198cf4c 100644 --- a/docs/development/debugging-with-symbol-server.md +++ b/docs/development/debugging-with-symbol-server.md @@ -15,7 +15,7 @@ calls, and other compiler optimizations. The only workaround is to build an unoptimized local build. The official symbol server URL for Electron is -https://symbols.electronjs.org. +[https://symbols.electronjs.org](https://symbols.electronjs.org). You cannot visit this URL directly, you must add it to the symbol path of your debugging tool. In the examples below, a local cache directory is used to avoid repeatedly fetching the PDB from the server. Replace `c:\code\symbols` with an diff --git a/docs/development/debugging-with-xcode.md b/docs/development/debugging-with-xcode.md index 7e88a92bba755..ded8328be4086 100644 --- a/docs/development/debugging-with-xcode.md +++ b/docs/development/debugging-with-xcode.md @@ -17,7 +17,7 @@ See `gn help gen` for more information on generating IDE projects with GN. Launch Electron app after build. You can now open the xcode workspace created above and attach to the Electron process -through the Debug > Attach To Process > Electron debug menu. [Note: If you want to debug +through the Debug > Attach To Process > Electron debug menu. \[Note: If you want to debug the renderer process, you need to attach to the Electron Helper as well.] You can now set breakpoints in any of the indexed files. However, you will not be able diff --git a/docs/development/goma.md b/docs/development/goma.md deleted file mode 100644 index f0d2f37d1c34b..0000000000000 --- a/docs/development/goma.md +++ /dev/null @@ -1,56 +0,0 @@ -# Goma - -> Goma is a distributed compiler service for open-source projects such as -> Chromium and Android. - -Electron has a deployment of a custom Goma Backend that we make available to -all Electron Maintainers. See the [Access](#access) section below for details -on authentication. There is also a `cache-only` Goma endpoint that will be -used by default if you do not have credentials. Requests to the cache-only -Goma will not hit our cluster, but will read from our cache and should result -in significantly faster build times. - -## Enabling Goma - -Currently the only supported way to use Goma is to use our [Build Tools](https://github.com/electron/build-tools). -Goma configuration is automatically included when you set up `build-tools`. - -If you are a maintainer and have access to our cluster, please ensure that you run -`e init` with `--goma=cluster` in order to configure `build-tools` to use -the Goma cluster. If you have an existing config, you can just set `"goma": "cluster"` -in your config file. - -## Building with Goma - -When you are using Goma you can run `ninja` with a substantially higher `j` -value than would normally be supported by your machine. - -Please do not set a value higher than **200**. We monitor Goma system usage, and users -found to be abusing it with unreasonable concurrency will be de-activated. - -```bash -ninja -C out/Testing electron -j 200 -``` - -If you're using `build-tools`, appropriate `-j` values will automatically be used for you. - -## Monitoring Goma - -If you access [http://localhost:8088](http://localhost:8088) on your local -machine you can monitor compile jobs as they flow through the goma system. - -## Access - -For security and cost reasons, access to Electron's Goma cluster is currently restricted -to Electron Maintainers. If you want access please head to `#access-requests` in -Slack and ping `@goma-squad` to ask for access. Please be aware that being a -maintainer does not *automatically* grant access and access is determined on a -case by case basis. - -## Uptime / Support - -We have automated monitoring of our Goma cluster and cache at https://status.notgoma.com - -We do not provide support for usage of Goma and any issues raised asking for help / having -issues will _probably_ be closed without much reason, we do not have the capacity to handle -that kind of support. diff --git a/docs/development/issues.md b/docs/development/issues.md index 1eb530111c7a8..76b126bf07550 100644 --- a/docs/development/issues.md +++ b/docs/development/issues.md @@ -24,7 +24,7 @@ contribute: ## Asking for General Help -[The Electron website](https://electronjs.org/community) has a +[The Electron website](https://www.electronjs.org/community) has a list of resources for getting programming help, reporting security issues, contributing, and more. Please use the issue tracker for bugs only! @@ -57,7 +57,7 @@ unfriendly. Contributors are encouraged to solve issues collaboratively and help one another make progress. If you encounter an issue that you feel is invalid, or -which contains incorrect information, explain *why* you feel that way with +which contains incorrect information, explain _why_ you feel that way with additional supporting context, and be willing to be convinced that you may be wrong. By doing so, we can often reach the correct outcome faster. diff --git a/docs/development/patches.md b/docs/development/patches.md index 634a35c355a87..e7c744f34a551 100644 --- a/docs/development/patches.md +++ b/docs/development/patches.md @@ -65,6 +65,8 @@ $ git rebase --autosquash -i [COMMIT_SHA]^ $ ../electron/script/git-export-patches -o ../electron/patches/v8 ``` +Note that the `^` symbol [can cause trouble on Windows](https://stackoverflow.com/questions/14203952/git-reset-asks-more/14204318#14204318). The workaround is to either quote it `"[COMMIT_SHA]^"` or avoid it `[COMMIT_SHA]~1`. + #### Removing a patch ```bash diff --git a/docs/development/pull-requests.md b/docs/development/pull-requests.md index fa4b6dfbdf19b..a2301b5b70808 100644 --- a/docs/development/pull-requests.md +++ b/docs/development/pull-requests.md @@ -219,7 +219,7 @@ of the area you modified in order to land. Whenever a maintainer reviews a pull request they may request changes. These may be small, such as fixing a typo, or may involve substantive changes. Such requests are intended to be helpful, but at times may come across as abrupt or unhelpful, especially if they do not include -concrete suggestions on *how* to change them. +concrete suggestions on _how_ to change them. Try not to be discouraged. If you feel that a review is unfair, say so or seek the input of another project contributor. Often such comments are the result of diff --git a/docs/development/reclient.md b/docs/development/reclient.md new file mode 100644 index 0000000000000..f84b0515e01dd --- /dev/null +++ b/docs/development/reclient.md @@ -0,0 +1,46 @@ +# Reclient + +> Reclient integrates with an existing build system to enable remote execution and caching of build actions. + +Electron has a deployment of a [reclient](https://github.com/bazelbuild/reclient) +compatible RBE Backend that is available to all Electron Maintainers. +See the [Access](#access) section below for details on authentication. Non-maintainers +will not have access to the cluster, but can sign in to receive a `Cache Only` token +that gives access to the cache-only CAS backend. Using this should result in +significantly faster build times . + +## Enabling Reclient + +Currently the only supported way to use Reclient is to use our [Build Tools](https://github.com/electron/build-tools). +Reclient configuration is automatically included when you set up `build-tools`. + +If you have an existing config, you can just set `"reclient": "remote_exec"` +in your config file. + +## Building with Reclient + +When you are using Reclient, you can run `autoninja` with a substantially higher `j` +value than would normally be supported by your machine. + +Please do not set a value higher than **200**. The RBE system is monitored. +Users found to be abusing it with unreasonable concurrency will be deactivated. + +```bash +autoninja -C out/Testing electron -j 200 +``` + +If you're using `build-tools`, appropriate `-j` values will automatically be used for you. + +## Access + +For security and cost reasons, access to Electron's RBE backend is currently restricted +to Electron Maintainers. If you want access, please head to `#access-requests` in +Slack and ping `@infra-wg` to ask for it. Please be aware that being a +maintainer does not _automatically_ grant access. Access is determined on a +case-by-case basis. + +## Support + +We do not provide support for usage of Reclient. Issues raised asking for help / having +issues will _probably_ be closed without much reason. We do not have the capacity to handle +that kind of support. diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index a7d0105f7dcb6..d6c52bd6c307d 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -3,8 +3,8 @@ The source code of Electron is separated into a few parts, mostly following Chromium on the separation conventions. -You may need to become familiar with [Chromium's multi-process -architecture](https://dev.chromium.org/developers/design-documents/multi-process-architecture) +You may need to become familiar with +[Chromium's multi-process architecture](https://dev.chromium.org/developers/design-documents/multi-process-architecture) to understand the source code better. ## Structure of Source Code @@ -72,15 +72,13 @@ Electron | | message loop into Chromium's message loop. | └── api/ - The implementation of common APIs, and foundations of | Electron's built-in modules. -├── spec/ - Components of Electron's test suite run in the renderer process. -├── spec-main/ - Components of Electron's test suite run in the main process. +├── spec/ - Components of Electron's test suite run in the main process. └── BUILD.gn - Building rules of Electron. ``` ## Structure of Other Directories -* **.circleci** - Config file for CI with CircleCI. -* **.github** - GitHub-specific config files including issues templates and CODEOWNERS. +* **.github** - GitHub-specific config files including issues templates, CI with GitHub Actions and CODEOWNERS. * **dist** - Temporary directory created by `script/create-dist.py` script when creating a distribution. * **node_modules** - Third party node modules used for building. diff --git a/docs/development/testing.md b/docs/development/testing.md index f170dc6c8540e..cce8ea5eab463 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -32,9 +32,6 @@ app (surprise!) that can be found in the `spec` folder. Note that it has its own `package.json` and that its dependencies are therefore not defined in the top-level `package.json`. -To run only tests in a specific process, run `npm run test --runners=PROCESS` -where `PROCESS` is one of `main` or `remote`. - To run only specific tests matching a pattern, run `npm run test -- -g=PATTERN`, replacing the `PATTERN` with a regex that matches the tests you would like to run. As an example: If you want to run only IPC tests, you @@ -69,7 +66,7 @@ the Node.js source tree. 2. Node headers have to be compiled for your configuration. ```powershell - ninja -C out\Testing third_party\electron_node:headers + ninja -C out\Testing electron:node_headers ``` 3. The electron.lib has to be copied as node.lib. @@ -82,7 +79,7 @@ the Node.js source tree. #### Missing fonts -[Some Windows 10 devices](https://docs.microsoft.com/en-us/typography/fonts/windows_10_font_list) do not ship with the Meiryo font installed, which may cause a font fallback test to fail. To install Meiryo: +[Some Windows 10 devices](https://learn.microsoft.com/en-us/typography/fonts/windows_10_font_list) do not ship with the Meiryo font installed, which may cause a font fallback test to fail. To install Meiryo: 1. Push the Windows key and search for _Manage optional features_. 2. Click _Add a feature_. diff --git a/docs/experimental.md b/docs/experimental.md index b9bc620ea83a8..4d35388e2bfb2 100644 --- a/docs/experimental.md +++ b/docs/experimental.md @@ -1,6 +1,6 @@ # Experimental APIs -Some of Electrons APIs are tagged with `_Experimental_` in the documentation. +Some of Electron's APIs are tagged with `_Experimental_` in the documentation. This tag indicates that the API may not be considered stable and the API may be removed or modified more frequently than other APIs with less warning. @@ -20,4 +20,4 @@ happen at an API WG meeting. Things to consider when discussing / nominating: * During that time no major bugs / issues should have been caused by the adoption of this feature * The API is stable enough and hasn't been heavily impacted by Chromium upgrades * Is anyone using the API? -* Is the API fulfilling the original proposed usecases, does it have any gaps? +* Is the API fulfilling the original proposed use cases, does it have any gaps? diff --git a/docs/faq.md b/docs/faq.md index 174104aee9b0c..114731d69d689 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -60,12 +60,12 @@ garbage collected. If you encounter this problem, the following articles may prove helpful: * [Memory Management][memory-management] -* [Variable Scope][variable-scope] +* [Closures][closures] If you want a quick fix, you can make the variables global by changing your code from this: -```javascript +```js const { app, Tray } = require('electron') app.whenReady().then(() => { const tray = new Tray('/path/to/icon.png') @@ -75,7 +75,7 @@ app.whenReady().then(() => { to this: -```javascript +```js const { app, Tray } = require('electron') let tray = null app.whenReady().then(() => { @@ -92,7 +92,7 @@ for some libraries since they want to insert the symbols with the same names. To solve this, you can turn off node integration in Electron: -```javascript +```js // In the main process. const { BrowserWindow } = require('electron') const win = new BrowserWindow({ @@ -135,13 +135,13 @@ is only available in renderer processes. If [sub-pixel anti-aliasing](https://alienryderflex.com/sub_pixel/) is deactivated, then fonts on LCD screens can look blurry. Example: -![subpixel rendering example] +![Subpixel rendering example](images/subpixel-rendering-screenshot.gif) Sub-pixel anti-aliasing needs a non-transparent background of the layer containing the font glyphs. (See [this issue](https://github.com/electron/electron/issues/6344#issuecomment-420371918) for more info). To achieve this goal, set the background in the constructor for [BrowserWindow][browser-window]: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ backgroundColor: '#fff' @@ -153,12 +153,10 @@ The effect is visible only on (some?) LCD screens. Even if you don't see a diffe Notice that just setting the background in the CSS does not have the desired effect. [memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management -[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx -[electron-module]: https://www.npmjs.com/package/electron +[closures]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures [storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage [local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage [session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage [indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API [message-port]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort [browser-window]: api/browser-window.md -[subpixel rendering example]: images/subpixel-rendering-screenshot.gif diff --git a/docs/fiddles/features/dark-mode/index.html b/docs/fiddles/features/dark-mode/index.html new file mode 100644 index 0000000000000..85fd15ada5b28 --- /dev/null +++ b/docs/fiddles/features/dark-mode/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="UTF-8"> + <title>Hello World! + + + + +

Hello World!

+

Current theme source: System

+ + + + + + + diff --git a/docs/fiddles/features/dark-mode/main.js b/docs/fiddles/features/dark-mode/main.js new file mode 100644 index 0000000000000..00a343c8ac182 --- /dev/null +++ b/docs/fiddles/features/dark-mode/main.js @@ -0,0 +1,43 @@ +const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron/main') +const path = require('node:path') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + win.loadFile('index.html') +} + +ipcMain.handle('dark-mode:toggle', () => { + if (nativeTheme.shouldUseDarkColors) { + nativeTheme.themeSource = 'light' + } else { + nativeTheme.themeSource = 'dark' + } + return nativeTheme.shouldUseDarkColors +}) + +ipcMain.handle('dark-mode:system', () => { + nativeTheme.themeSource = 'system' +}) + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/features/dark-mode/preload.js b/docs/fiddles/features/dark-mode/preload.js new file mode 100644 index 0000000000000..752d9d71a0a57 --- /dev/null +++ b/docs/fiddles/features/dark-mode/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('darkMode', { + toggle: () => ipcRenderer.invoke('dark-mode:toggle'), + system: () => ipcRenderer.invoke('dark-mode:system') +}) diff --git a/docs/fiddles/features/macos-dark-mode/renderer.js b/docs/fiddles/features/dark-mode/renderer.js similarity index 100% rename from docs/fiddles/features/macos-dark-mode/renderer.js rename to docs/fiddles/features/dark-mode/renderer.js diff --git a/docs/fiddles/features/dark-mode/styles.css b/docs/fiddles/features/dark-mode/styles.css new file mode 100644 index 0000000000000..8f9ad8f04d39e --- /dev/null +++ b/docs/fiddles/features/dark-mode/styles.css @@ -0,0 +1,11 @@ +:root { + color-scheme: light dark; +} + +@media (prefers-color-scheme: dark) { + body { background: #333; color: white; } +} + +@media (prefers-color-scheme: light) { + body { background: #ddd; color: black; } +} diff --git a/docs/fiddles/features/drag-and-drop/main.js b/docs/fiddles/features/drag-and-drop/main.js index 9ad158beafd5e..0cf045a7c9b82 100644 --- a/docs/fiddles/features/drag-and-drop/main.js +++ b/docs/fiddles/features/drag-and-drop/main.js @@ -1,9 +1,9 @@ -const { app, BrowserWindow, ipcMain, nativeImage, NativeImage } = require('electron') -const path = require('path') -const fs = require('fs') -const https = require('https') +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') +const fs = require('node:fs') +const https = require('node:https') -function createWindow() { +function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, @@ -15,23 +15,23 @@ function createWindow() { win.loadFile('index.html') } -const iconName = path.join(__dirname, 'iconForDragAndDrop.png'); -const icon = fs.createWriteStream(iconName); +const iconName = path.join(__dirname, 'iconForDragAndDrop.png') +const icon = fs.createWriteStream(iconName) // Create a new file to copy - you can also copy existing files. fs.writeFileSync(path.join(__dirname, 'drag-and-drop-1.md'), '# First file to test drag and drop') fs.writeFileSync(path.join(__dirname, 'drag-and-drop-2.md'), '# Second file to test drag and drop') https.get('https://img.icons8.com/ios/452/drag-and-drop.png', (response) => { - response.pipe(icon); -}); + response.pipe(icon) +}) app.whenReady().then(createWindow) ipcMain.on('ondragstart', (event, filePath) => { event.sender.startDrag({ file: path.join(__dirname, filePath), - icon: iconName, + icon: iconName }) }) diff --git a/docs/fiddles/features/drag-and-drop/preload.js b/docs/fiddles/features/drag-and-drop/preload.js index 4609e12c75528..3c02ab61c1eb5 100644 --- a/docs/fiddles/features/drag-and-drop/preload.js +++ b/docs/fiddles/features/drag-and-drop/preload.js @@ -1,8 +1,5 @@ -const { contextBridge, ipcRenderer } = require('electron') -const path = require('path') +const { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electron', { - startDrag: (fileName) => { - ipcRenderer.send('ondragstart', fileName) - } + startDrag: (fileName) => ipcRenderer.send('ondragstart', fileName) }) diff --git a/docs/fiddles/features/keyboard-shortcuts/global/main.js b/docs/fiddles/features/keyboard-shortcuts/global/main.js index 24b2d343fbaaa..991c70d25f630 100644 --- a/docs/fiddles/features/keyboard-shortcuts/global/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/global/main.js @@ -1,9 +1,9 @@ -const { app, BrowserWindow, globalShortcut } = require('electron') +const { app, BrowserWindow, globalShortcut } = require('electron/main') function createWindow () { const win = new BrowserWindow({ width: 800, - height: 600, + height: 600 }) win.loadFile('index.html') diff --git a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js index 80e4012c812d1..62df976ea79e3 100644 --- a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow } = require('electron/main') app.whenReady().then(() => { const win = new BrowserWindow({ width: 800, height: 600 }) diff --git a/docs/fiddles/features/keyboard-shortcuts/local/main.js b/docs/fiddles/features/keyboard-shortcuts/local/main.js index c583469df4820..6393f27a22f62 100644 --- a/docs/fiddles/features/keyboard-shortcuts/local/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/local/main.js @@ -1,9 +1,9 @@ -const { app, BrowserWindow, Menu, MenuItem } = require('electron') +const { app, BrowserWindow, Menu, MenuItem } = require('electron/main') function createWindow () { const win = new BrowserWindow({ width: 800, - height: 600, + height: 600 }) win.loadFile('index.html') diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html index b19f3e92fd070..4effa03fc9f21 100644 --- a/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html @@ -9,7 +9,7 @@

Hello World!

- +

Hit any key with this window focused to see it captured here.

Last Key Pressed:
diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js index 5944f55c83f15..cf335b4a8433f 100644 --- a/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js @@ -1,17 +1,15 @@ // Modules to control application life and create native browser window -const {app, BrowserWindow} = require('electron') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') function createWindow () { // Create the browser window. const mainWindow = new BrowserWindow({ width: 800, - height: 600, + height: 600 }) // and load the index.html of the app. mainWindow.loadFile('index.html') - } // This method will be called when Electron has finished @@ -19,7 +17,7 @@ function createWindow () { // Some APIs can only be used after this event occurs. app.whenReady().then(() => { createWindow() - + app.on('activate', function () { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js index 7f7e406c4b2cc..e3e05209207dc 100644 --- a/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js @@ -1,6 +1,6 @@ function handleKeyPress (event) { // You can put code here to handle the keypress. - document.getElementById("last-keypress").innerText = event.key + document.getElementById('last-keypress').innerText = event.key console.log(`You pressed ${event.key}`) } diff --git a/docs/fiddles/features/macos-dark-mode/index.html b/docs/fiddles/features/macos-dark-mode/index.html deleted file mode 100644 index dfd1e075fd705..0000000000000 --- a/docs/fiddles/features/macos-dark-mode/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Hello World! - - - - -

Hello World!

-

Current theme source: System

- - - - - - - - diff --git a/docs/fiddles/features/macos-dark-mode/main.js b/docs/fiddles/features/macos-dark-mode/main.js deleted file mode 100644 index 9503efb5f9a92..0000000000000 --- a/docs/fiddles/features/macos-dark-mode/main.js +++ /dev/null @@ -1,43 +0,0 @@ -const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron') -const path = require('path') - -function createWindow () { - const win = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - preload: path.join(__dirname, 'preload.js') - } - }) - - win.loadFile('index.html') - - ipcMain.handle('dark-mode:toggle', () => { - if (nativeTheme.shouldUseDarkColors) { - nativeTheme.themeSource = 'light' - } else { - nativeTheme.themeSource = 'dark' - } - return nativeTheme.shouldUseDarkColors - }) - - ipcMain.handle('dark-mode:system', () => { - nativeTheme.themeSource = 'system' - }) -} - -app.whenReady().then(() => { - createWindow() - - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow() - } - }) -}) - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() - } -}) diff --git a/docs/fiddles/features/macos-dark-mode/preload.js b/docs/fiddles/features/macos-dark-mode/preload.js deleted file mode 100644 index 3def9e06ed8ea..0000000000000 --- a/docs/fiddles/features/macos-dark-mode/preload.js +++ /dev/null @@ -1,6 +0,0 @@ -const { contextBridge, ipcRenderer } = require('electron') - -contextBridge.exposeInMainWorld('darkMode', { - toggle: () => ipcRenderer.invoke('dark-mode:toggle'), - system: () => ipcRenderer.invoke('dark-mode:system') -}) diff --git a/docs/fiddles/features/macos-dark-mode/styles.css b/docs/fiddles/features/macos-dark-mode/styles.css deleted file mode 100644 index eb6dd2f243449..0000000000000 --- a/docs/fiddles/features/macos-dark-mode/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -@media (prefers-color-scheme: dark) { - body { background: #333; color: white; } -} - -@media (prefers-color-scheme: light) { - body { background: #ddd; color: black; } -} diff --git a/docs/fiddles/features/macos-dock-menu/main.js b/docs/fiddles/features/macos-dock-menu/main.js index f7f86a2361a80..5b8b154fe4a8f 100644 --- a/docs/fiddles/features/macos-dock-menu/main.js +++ b/docs/fiddles/features/macos-dock-menu/main.js @@ -1,9 +1,9 @@ -const { app, BrowserWindow, Menu } = require('electron') +const { app, BrowserWindow, Menu } = require('electron/main') function createWindow () { const win = new BrowserWindow({ width: 800, - height: 600, + height: 600 }) win.loadFile('index.html') diff --git a/docs/fiddles/features/navigation-history/index.html b/docs/fiddles/features/navigation-history/index.html new file mode 100644 index 0000000000000..584e04a26389d --- /dev/null +++ b/docs/fiddles/features/navigation-history/index.html @@ -0,0 +1,32 @@ + + + + + Enhanced Browser with Navigation History + + + + + +
+ + + + + + +
+ +
+ +
+

Navigation History Demo

+

This demo showcases Electron's NavigationHistory API functionality.

+

Back/Forward: Navigate through your browsing history.

+

Back History/Forward History: View and select from your browsing history.

+

URL Bar: Enter a URL and click 'Go' or press Enter to navigate.

+
+ + + + diff --git a/docs/fiddles/features/navigation-history/main.js b/docs/fiddles/features/navigation-history/main.js new file mode 100644 index 0000000000000..61f240f29fc67 --- /dev/null +++ b/docs/fiddles/features/navigation-history/main.js @@ -0,0 +1,58 @@ +const { app, BrowserWindow, BrowserView, ipcMain } = require('electron') +const path = require('path') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 1000, + height: 800, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + nodeIntegration: false, + contextIsolation: true + } + }) + + mainWindow.loadFile('index.html') + + const view = new BrowserView() + mainWindow.setBrowserView(view) + view.setBounds({ x: 0, y: 100, width: 1000, height: 800 }) + view.setAutoResize({ width: true, height: true }) + + const navigationHistory = view.webContents.navigationHistory + ipcMain.handle('nav:back', () => + navigationHistory.goBack() + ) + + ipcMain.handle('nav:forward', () => { + navigationHistory.goForward() + }) + + ipcMain.handle('nav:canGoBack', () => navigationHistory.canGoBack()) + ipcMain.handle('nav:canGoForward', () => navigationHistory.canGoForward()) + ipcMain.handle('nav:loadURL', (_, url) => + view.webContents.loadURL(url) + ) + ipcMain.handle('nav:getCurrentURL', () => view.webContents.getURL()) + ipcMain.handle('nav:getHistory', () => { + return navigationHistory.getAllEntries() + }) + + view.webContents.on('did-navigate', () => { + mainWindow.webContents.send('nav:updated') + }) + + view.webContents.on('did-navigate-in-page', () => { + mainWindow.webContents.send('nav:updated') + }) +} + +app.whenReady().then(createWindow) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit() +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() +}) diff --git a/docs/fiddles/features/navigation-history/preload.js b/docs/fiddles/features/navigation-history/preload.js new file mode 100644 index 0000000000000..6d5c38976cc91 --- /dev/null +++ b/docs/fiddles/features/navigation-history/preload.js @@ -0,0 +1,12 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electronAPI', { + goBack: () => ipcRenderer.invoke('nav:back'), + goForward: () => ipcRenderer.invoke('nav:forward'), + canGoBack: () => ipcRenderer.invoke('nav:canGoBack'), + canGoForward: () => ipcRenderer.invoke('nav:canGoForward'), + loadURL: (url) => ipcRenderer.invoke('nav:loadURL', url), + getCurrentURL: () => ipcRenderer.invoke('nav:getCurrentURL'), + getHistory: () => ipcRenderer.invoke('nav:getHistory'), + onNavigationUpdate: (callback) => ipcRenderer.on('nav:updated', callback) +}) diff --git a/docs/fiddles/features/navigation-history/renderer.js b/docs/fiddles/features/navigation-history/renderer.js new file mode 100644 index 0000000000000..741cc80933079 --- /dev/null +++ b/docs/fiddles/features/navigation-history/renderer.js @@ -0,0 +1,84 @@ +const backBtn = document.getElementById('backBtn') +const forwardBtn = document.getElementById('forwardBtn') +const backHistoryBtn = document.getElementById('backHistoryBtn') +const forwardHistoryBtn = document.getElementById('forwardHistoryBtn') +const urlInput = document.getElementById('urlInput') +const goBtn = document.getElementById('goBtn') +const historyPanel = document.getElementById('historyPanel') + +async function updateButtons () { + const canGoBack = await window.electronAPI.canGoBack() + const canGoForward = await window.electronAPI.canGoForward() + backBtn.disabled = !canGoBack + backHistoryBtn.disabled = !canGoBack + + forwardBtn.disabled = !canGoForward + forwardHistoryBtn.disabled = !canGoForward +} + +async function updateURL () { + urlInput.value = await window.electronAPI.getCurrentURL() +} + +function transformURL (url) { + if (!url.startsWith('http://') && !url.startsWith('https://')) { + const updatedUrl = 'https://' + url + return updatedUrl + } + return url +} + +async function navigate (url) { + const urlInput = transformURL(url) + + await window.electronAPI.loadURL(urlInput) +} + +async function showHistory (forward = false) { + const history = await window.electronAPI.getHistory() + const currentIndex = history.findIndex(entry => entry.url === transformURL(urlInput.value)) + + if (!currentIndex) { + return + } + + const relevantHistory = forward + ? history.slice(currentIndex + 1) + : history.slice(0, currentIndex).reverse() + + historyPanel.innerHTML = '' + relevantHistory.forEach(entry => { + const div = document.createElement('div') + div.textContent = `Title: ${entry.title}, URL: ${entry.url}` + div.onclick = () => navigate(entry.url) + historyPanel.appendChild(div) + }) + + historyPanel.style.display = 'block' +} + +backBtn.addEventListener('click', () => window.electronAPI.goBack()) +forwardBtn.addEventListener('click', () => window.electronAPI.goForward()) +backHistoryBtn.addEventListener('click', () => showHistory(false)) +forwardHistoryBtn.addEventListener('click', () => showHistory(true)) +goBtn.addEventListener('click', () => navigate(urlInput.value)) + +urlInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + navigate(urlInput.value) + } +}) + +document.addEventListener('click', (e) => { + if (e.target !== historyPanel && !historyPanel.contains(e.target) && + e.target !== backHistoryBtn && e.target !== forwardHistoryBtn) { + historyPanel.style.display = 'none' + } +}) + +window.electronAPI.onNavigationUpdate(() => { + updateButtons() + updateURL() +}) + +updateButtons() diff --git a/docs/fiddles/features/navigation-history/style.css b/docs/fiddles/features/navigation-history/style.css new file mode 100644 index 0000000000000..955e8482eaea4 --- /dev/null +++ b/docs/fiddles/features/navigation-history/style.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: Arial, sans-serif; + background-color: #f0f0f0; +} +#controls { + display: flex; + align-items: center; + padding: 10px; + background-color: #ffffff; + border-bottom: 1px solid #ccc; +} +button { + margin-right: 10px; + padding: 8px 12px; + font-size: 14px; + background-color: #4CAF50; + color: white; + border: none; + cursor: pointer; + transition: background-color 0.3s; +} +button:hover { + background-color: #45a049; +} +button:disabled { + background-color: #cccccc; + cursor: not-allowed; +} +#urlInput { + flex-grow: 1; + margin: 0 10px; + padding: 8px; + font-size: 14px; +} + +#historyPanel { + display: none; + position: absolute; + top: 60px; + left: 10px; + background: white; + border: 1px solid #ccc; + padding: 10px; + max-height: 300px; + overflow-y: auto; + z-index: 1000; +} + #historyPanel div { + cursor: pointer; + padding: 5px; +} + +#description { + background-color: #f0f0f0; + padding: 10px; + margin-top: 150px; +} diff --git a/docs/fiddles/features/notifications/main/main.js b/docs/fiddles/features/notifications/main/main.js index f6e6f867ccc88..b092c9a6ef4e8 100644 --- a/docs/fiddles/features/notifications/main/main.js +++ b/docs/fiddles/features/notifications/main/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow, Notification } = require('electron') +const { app, BrowserWindow, Notification } = require('electron/main') function createWindow () { const win = new BrowserWindow({ diff --git a/docs/fiddles/features/notifications/renderer/main.js b/docs/fiddles/features/notifications/renderer/main.js index e24a66dd52b8f..9f26d370c6ef3 100644 --- a/docs/fiddles/features/notifications/renderer/main.js +++ b/docs/fiddles/features/notifications/renderer/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow } = require('electron/main') function createWindow () { const win = new BrowserWindow({ diff --git a/docs/fiddles/features/notifications/renderer/renderer.js b/docs/fiddles/features/notifications/renderer/renderer.js index a6c88f9a79464..09099326b0849 100644 --- a/docs/fiddles/features/notifications/renderer/renderer.js +++ b/docs/fiddles/features/notifications/renderer/renderer.js @@ -2,5 +2,5 @@ const NOTIFICATION_TITLE = 'Title' const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.' const CLICK_MESSAGE = 'Notification clicked!' -new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY }) - .onclick = () => document.getElementById("output").innerText = CLICK_MESSAGE +new window.Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY }) + .onclick = () => { document.getElementById('output').innerText = CLICK_MESSAGE } diff --git a/docs/fiddles/features/offscreen-rendering/main.js b/docs/fiddles/features/offscreen-rendering/main.js index 10ad35d3d9a80..6c64afb10f654 100644 --- a/docs/fiddles/features/offscreen-rendering/main.js +++ b/docs/fiddles/features/offscreen-rendering/main.js @@ -1,19 +1,34 @@ -const { app, BrowserWindow } = require('electron') -const fs = require('fs') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') +const fs = require('node:fs') +const path = require('node:path') app.disableHardwareAcceleration() -let win +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + offscreen: true + } + }) -app.whenReady().then(() => { - win = new BrowserWindow({ webPreferences: { offscreen: true } }) win.loadURL('https://github.com') win.webContents.on('paint', (event, dirty, image) => { fs.writeFileSync('ex.png', image.toPNG()) }) win.webContents.setFrameRate(60) console.log(`The screenshot has been successfully saved to ${path.join(process.cwd(), 'ex.png')}`) +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) }) app.on('window-all-closed', () => { @@ -21,9 +36,3 @@ app.on('window-all-closed', () => { app.quit() } }) - -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow() - } -}) diff --git a/docs/fiddles/features/online-detection/index.html b/docs/fiddles/features/online-detection/index.html index 372e5a963f770..2ff4b4f3633e8 100644 --- a/docs/fiddles/features/online-detection/index.html +++ b/docs/fiddles/features/online-detection/index.html @@ -7,7 +7,7 @@

Connection status:

- + diff --git a/docs/fiddles/features/online-detection/main.js b/docs/fiddles/features/online-detection/main.js index 7bc42d7725670..4e9a092cb13f2 100644 --- a/docs/fiddles/features/online-detection/main.js +++ b/docs/fiddles/features/online-detection/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow } = require('electron/main') function createWindow () { const onlineStatusWindow = new BrowserWindow({ diff --git a/docs/fiddles/features/progress-bar/main.js b/docs/fiddles/features/progress-bar/main.js index c400638359011..4bcc1f55361f9 100644 --- a/docs/fiddles/features/progress-bar/main.js +++ b/docs/fiddles/features/progress-bar/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow } = require('electron/main') let progressInterval diff --git a/docs/fiddles/features/recent-documents/main.js b/docs/fiddles/features/recent-documents/main.js index d11a5bcc6705a..c4a399a78cdcd 100644 --- a/docs/fiddles/features/recent-documents/main.js +++ b/docs/fiddles/features/recent-documents/main.js @@ -1,6 +1,6 @@ -const { app, BrowserWindow } = require('electron') -const fs = require('fs') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') +const fs = require('node:fs') +const path = require('node:path') function createWindow () { const win = new BrowserWindow({ diff --git a/docs/fiddles/features/represented-file/main.js b/docs/fiddles/features/represented-file/main.js index 204a3fc4586eb..6898a110f97b8 100644 --- a/docs/fiddles/features/represented-file/main.js +++ b/docs/fiddles/features/represented-file/main.js @@ -1,5 +1,5 @@ -const { app, BrowserWindow } = require('electron') -const os = require('os'); +const { app, BrowserWindow } = require('electron/main') +const os = require('node:os') function createWindow () { const win = new BrowserWindow({ @@ -7,14 +7,20 @@ function createWindow () { height: 600 }) + win.setRepresentedFilename(os.homedir()) + win.setDocumentEdited(true) + win.loadFile('index.html') } app.whenReady().then(() => { - const win = new BrowserWindow() + createWindow() - win.setRepresentedFilename(os.homedir()) - win.setDocumentEdited(true) + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) }) app.on('window-all-closed', () => { @@ -22,9 +28,3 @@ app.on('window-all-closed', () => { app.quit() } }) - -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow() - } -}) diff --git a/docs/fiddles/features/web-bluetooth/index.html b/docs/fiddles/features/web-bluetooth/index.html index b2be53d400a6a..f31c883b0d5df 100644 --- a/docs/fiddles/features/web-bluetooth/index.html +++ b/docs/fiddles/features/web-bluetooth/index.html @@ -9,8 +9,9 @@

Web Bluetooth API

+ -

Currently selected bluetooth device:

+

Currently selected bluetooth device:

diff --git a/docs/fiddles/features/web-bluetooth/main.js b/docs/fiddles/features/web-bluetooth/main.js index b3cc55a438198..103c9891ba9e5 100644 --- a/docs/fiddles/features/web-bluetooth/main.js +++ b/docs/fiddles/features/web-bluetooth/main.js @@ -1,17 +1,45 @@ -const {app, BrowserWindow} = require('electron') -const path = require('path') +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') + +let bluetoothPinCallback +let selectBluetoothCallback function createWindow () { const mainWindow = new BrowserWindow({ width: 800, - height: 600 + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } }) mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => { event.preventDefault() - if (deviceList && deviceList.length > 0) { - callback(deviceList[0].deviceId) - } + selectBluetoothCallback = callback + const result = deviceList.find((device) => { + return device.deviceName === 'test' + }) + if (result) { + callback(result.deviceId) + } else { + // The device wasn't found so we need to either wait longer (eg until the + // device is turned on) or until the user cancels the request + } + }) + + ipcMain.on('cancel-bluetooth-request', (event) => { + selectBluetoothCallback('') + }) + + // Listen for a message from the renderer to get the response for the Bluetooth pairing. + ipcMain.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) + }) + + mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + bluetoothPinCallback = callback + // Send a message to the renderer to prompt the user to confirm the pairing. + mainWindow.webContents.send('bluetooth-pairing-request', details) }) mainWindow.loadFile('index.html') @@ -19,7 +47,7 @@ function createWindow () { app.whenReady().then(() => { createWindow() - + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) diff --git a/docs/fiddles/features/web-bluetooth/preload.js b/docs/fiddles/features/web-bluetooth/preload.js new file mode 100644 index 0000000000000..1b1c6367256ef --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/preload.js @@ -0,0 +1,7 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + cancelBluetoothRequest: () => ipcRenderer.send('cancel-bluetooth-request'), + bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', () => callback()), + bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response) +}) diff --git a/docs/fiddles/features/web-bluetooth/renderer.js b/docs/fiddles/features/web-bluetooth/renderer.js index e5830955599af..ca14ef9723872 100644 --- a/docs/fiddles/features/web-bluetooth/renderer.js +++ b/docs/fiddles/features/web-bluetooth/renderer.js @@ -1,8 +1,40 @@ -async function testIt() { +async function testIt () { const device = await navigator.bluetooth.requestDevice({ acceptAllDevices: true }) document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}` } -document.getElementById('clickme').addEventListener('click',testIt) \ No newline at end of file +document.getElementById('clickme').addEventListener('click', testIt) + +function cancelRequest () { + window.electronAPI.cancelBluetoothRequest() +} + +document.getElementById('cancel').addEventListener('click', cancelRequest) + +window.electronAPI.bluetoothPairingRequest((event, details) => { + const response = {} + + switch (details.pairingKind) { + case 'confirm': { + response.confirmed = window.confirm(`Do you want to connect to device ${details.deviceId}?`) + break + } + case 'confirmPin': { + response.confirmed = window.confirm(`Does the pin ${details.pin} match the pin displayed on device ${details.deviceId}?`) + break + } + case 'providePin': { + const pin = window.prompt(`Please provide a pin for ${details.deviceId}.`) + if (pin) { + response.pin = pin + response.confirmed = true + } else { + response.confirmed = false + } + } + } + + window.electronAPI.bluetoothPairingResponse(response) +}) diff --git a/docs/fiddles/features/web-hid/index.html b/docs/fiddles/features/web-hid/index.html index 659b5bc12395e..8b4243e325751 100644 --- a/docs/fiddles/features/web-hid/index.html +++ b/docs/fiddles/features/web-hid/index.html @@ -12,7 +12,7 @@

WebHID API

HID devices automatically granted access via setDevicePermissionHandler

- +

HID devices automatically granted access via select-hid-device

diff --git a/docs/fiddles/features/web-hid/main.js b/docs/fiddles/features/web-hid/main.js index 3304457db822f..315c39da37d0c 100644 --- a/docs/fiddles/features/web-hid/main.js +++ b/docs/fiddles/features/web-hid/main.js @@ -1,23 +1,22 @@ -const {app, BrowserWindow} = require('electron') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') function createWindow () { const mainWindow = new BrowserWindow({ width: 800, height: 600 }) - + mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => { - //Add events to handle devices being added or removed before the callback on - //`select-hid-device` is called. - mainWindow.webContents.session.on('hid-device-added', (event, device) => { + // Add events to handle devices being added or removed before the callback on + // `select-hid-device` is called. + mainWindow.webContents.session.on('hid-device-added', (event, device) => { console.log('hid-device-added FIRED WITH', device) - //Optionally update details.deviceList + // Optionally update details.deviceList }) - - mainWindow.webContents.session.on('hid-device-removed', (event, device) => { + + mainWindow.webContents.session.on('hid-device-removed', (event, device) => { console.log('hid-device-removed FIRED WITH', device) - //Optionally update details.deviceList + // Optionally update details.deviceList }) event.preventDefault() @@ -37,13 +36,13 @@ function createWindow () { return true } }) - + mainWindow.loadFile('index.html') } app.whenReady().then(() => { createWindow() - + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) diff --git a/docs/fiddles/features/web-hid/renderer.js b/docs/fiddles/features/web-hid/renderer.js index 54bda3f977106..133beb520cddc 100644 --- a/docs/fiddles/features/web-hid/renderer.js +++ b/docs/fiddles/features/web-hid/renderer.js @@ -1,19 +1,10 @@ -async function testIt() { - const grantedDevices = await navigator.hid.getDevices() - let grantedDeviceList = '' - grantedDevices.forEach(device => { - grantedDeviceList += `
${device.productName}` - }) - document.getElementById('granted-devices').innerHTML = grantedDeviceList - const grantedDevices2 = await navigator.hid.requestDevice({ - filters: [] - }) +function formatDevices (devices) { + return devices.map(device => device.productName).join('
') +} - grantedDeviceList = '' - grantedDevices2.forEach(device => { - grantedDeviceList += `
${device.productName}` - }) - document.getElementById('granted-devices2').innerHTML = grantedDeviceList +async function testIt () { + document.getElementById('granted-devices').innerHTML = formatDevices(await navigator.hid.getDevices()) + document.getElementById('granted-devices2').innerHTML = formatDevices(await navigator.hid.requestDevice({ filters: [] })) } -document.getElementById('clickme').addEventListener('click',testIt) +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/web-serial/main.js b/docs/fiddles/features/web-serial/main.js index 37b9f35c27b2f..1839f4f425446 100644 --- a/docs/fiddles/features/web-serial/main.js +++ b/docs/fiddles/features/web-serial/main.js @@ -1,31 +1,30 @@ -const {app, BrowserWindow} = require('electron') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') function createWindow () { const mainWindow = new BrowserWindow({ width: 800, height: 600 }) - - mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { - //Add listeners to handle ports being added or removed before the callback for `select-serial-port` - //is called. + mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { + // Add listeners to handle ports being added or removed before the callback for `select-serial-port` + // is called. mainWindow.webContents.session.on('serial-port-added', (event, port) => { console.log('serial-port-added FIRED WITH', port) - //Optionally update portList to add the new port + // Optionally update portList to add the new port }) - + mainWindow.webContents.session.on('serial-port-removed', (event, port) => { console.log('serial-port-removed FIRED WITH', port) - //Optionally update portList to remove the port + // Optionally update portList to remove the port }) event.preventDefault() if (portList && portList.length > 0) { callback(portList[0].portId) } else { - callback('') //Could not find any matching devices + // eslint-disable-next-line n/no-callback-literal + callback('') // Could not find any matching devices } }) @@ -33,14 +32,18 @@ function createWindow () { if (permission === 'serial' && details.securityOrigin === 'file:///') { return true } + + return false }) mainWindow.webContents.session.setDevicePermissionHandler((details) => { if (details.deviceType === 'serial' && details.origin === 'file://') { return true } + + return false }) - + mainWindow.loadFile('index.html') mainWindow.webContents.openDevTools() @@ -48,7 +51,7 @@ function createWindow () { app.whenReady().then(() => { createWindow() - + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) diff --git a/docs/fiddles/features/web-serial/renderer.js b/docs/fiddles/features/web-serial/renderer.js index 1d684d219252e..2c5eb369804c8 100644 --- a/docs/fiddles/features/web-serial/renderer.js +++ b/docs/fiddles/features/web-serial/renderer.js @@ -1,11 +1,11 @@ -async function testIt() { +async function testIt () { const filters = [ { usbVendorId: 0x2341, usbProductId: 0x0043 }, { usbVendorId: 0x2341, usbProductId: 0x0001 } - ]; + ] try { - const port = await navigator.serial.requestPort({filters}); - const portInfo = port.getInfo(); + const port = await navigator.serial.requestPort({ filters }) + const portInfo = port.getInfo() document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} ` } catch (ex) { if (ex.name === 'NotFoundError') { @@ -16,4 +16,4 @@ async function testIt() { } } -document.getElementById('clickme').addEventListener('click',testIt) +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/web-usb/index.html b/docs/fiddles/features/web-usb/index.html new file mode 100644 index 0000000000000..59c0cb9264dc6 --- /dev/null +++ b/docs/fiddles/features/web-usb/index.html @@ -0,0 +1,21 @@ + + + + + + WebUSB API + + +

WebUSB API

+ + + +

USB devices automatically granted access via setDevicePermissionHandler

+
+ +

USB devices automatically granted access via select-usb-device

+
+ + + + diff --git a/docs/fiddles/features/web-usb/main.js b/docs/fiddles/features/web-usb/main.js new file mode 100644 index 0000000000000..a60de9182ada9 --- /dev/null +++ b/docs/fiddles/features/web-usb/main.js @@ -0,0 +1,74 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + let grantedDeviceThroughPermHandler + + mainWindow.webContents.session.on('select-usb-device', (event, details, callback) => { + // Add events to handle devices being added or removed before the callback on + // `select-usb-device` is called. + mainWindow.webContents.session.on('usb-device-added', (event, device) => { + console.log('usb-device-added FIRED WITH', device) + // Optionally update details.deviceList + }) + + mainWindow.webContents.session.on('usb-device-removed', (event, device) => { + console.log('usb-device-removed FIRED WITH', device) + // Optionally update details.deviceList + }) + + event.preventDefault() + if (details.deviceList && details.deviceList.length > 0) { + const deviceToReturn = details.deviceList.find((device) => { + return !grantedDeviceThroughPermHandler || (device.deviceId !== grantedDeviceThroughPermHandler.deviceId) + }) + if (deviceToReturn) { + callback(deviceToReturn.deviceId) + } else { + callback() + } + } + }) + + mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'usb' && details.securityOrigin === 'file:///') { + return true + } + }) + + mainWindow.webContents.session.setDevicePermissionHandler((details) => { + if (details.deviceType === 'usb' && details.origin === 'file://') { + if (!grantedDeviceThroughPermHandler) { + grantedDeviceThroughPermHandler = details.device + return true + } else { + return false + } + } + }) + + mainWindow.webContents.session.setUSBProtectedClassesHandler((details) => { + return details.protectedClasses.filter((usbClass) => { + // Exclude classes except for audio classes + return usbClass.indexOf('audio') === -1 + }) + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/web-usb/renderer.js b/docs/fiddles/features/web-usb/renderer.js new file mode 100644 index 0000000000000..1c217d957d213 --- /dev/null +++ b/docs/fiddles/features/web-usb/renderer.js @@ -0,0 +1,32 @@ +function getDeviceDetails (device) { + return device.productName || `Unknown device ${device.deviceId}` +} + +async function testIt () { + const noDevicesFoundMsg = 'No devices found' + const grantedDevices = await navigator.usb.getDevices() + let grantedDeviceList = '' + if (grantedDevices.length > 0) { + for (const device of grantedDevices) { + grantedDeviceList += `
${getDeviceDetails(device)}` + } + } else { + grantedDeviceList = noDevicesFoundMsg + } + document.getElementById('granted-devices').innerHTML = grantedDeviceList + + grantedDeviceList = '' + try { + const grantedDevice = await navigator.usb.requestDevice({ + filters: [] + }) + grantedDeviceList += `
${getDeviceDetails(grantedDevice)}` + } catch (ex) { + if (ex.name === 'NotFoundError') { + grantedDeviceList = noDevicesFoundMsg + } + } + document.getElementById('granted-devices2').innerHTML = grantedDeviceList +} + +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html new file mode 100644 index 0000000000000..389fd9e760622 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html @@ -0,0 +1,14 @@ + + + + + + + + Custom Titlebar App + + + +
Cool titlebar
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js new file mode 100644 index 0000000000000..b862cdf9702fc --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controlls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css new file mode 100644 index 0000000000000..b5a046efdba67 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css @@ -0,0 +1,12 @@ +body { + margin: 0; +} +.titlebar { + height: 30px; + background: blue; + color: white; + display: flex; + justify-content: center; + align-items: center; + app-region: drag; +} \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html new file mode 100644 index 0000000000000..389fd9e760622 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html @@ -0,0 +1,14 @@ + + + + + + + + Custom Titlebar App + + + +
Cool titlebar
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js new file mode 100644 index 0000000000000..b862cdf9702fc --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controlls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css new file mode 100644 index 0000000000000..1f61248a977db --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css @@ -0,0 +1,12 @@ +body { + margin: 0; +} + +.titlebar { + height: 30px; + background: blue; + color: white; + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js b/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js new file mode 100644 index 0000000000000..fc59d41ca110d --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js @@ -0,0 +1,15 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controlls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js b/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js new file mode 100644 index 0000000000000..f85ee63f59319 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js @@ -0,0 +1,13 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden' + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js b/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js new file mode 100644 index 0000000000000..314899176a6f8 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js @@ -0,0 +1,10 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({}) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js b/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js new file mode 100644 index 0000000000000..86e486b1ee3d7 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js @@ -0,0 +1,14 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + width: 300, + height: 200, + frame: false + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html new file mode 100644 index 0000000000000..7c3dc93bddeec --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html @@ -0,0 +1,15 @@ + + + + + + + + Transparent Hello World + + +
+
Hello World!
+
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js new file mode 100644 index 0000000000000..42e63cf4d2868 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + width: 100, + height: 100, + resizable: false, + frame: false, + transparent: true + }) + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css new file mode 100644 index 0000000000000..361a8d87982d2 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css @@ -0,0 +1,16 @@ +body { + margin: 0; + padding: 0; + background-color: rgba(0, 0, 0, 0); /* Transparent background */ +} +.white-circle { + width: 100px; + height: 100px; + background-color: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + app-region: drag; + user-select: none; +} \ No newline at end of file diff --git a/docs/fiddles/ipc/pattern-1/main.js b/docs/fiddles/ipc/pattern-1/main.js index 2e9e97edb81b0..43799d4cb0b0c 100644 --- a/docs/fiddles/ipc/pattern-1/main.js +++ b/docs/fiddles/ipc/pattern-1/main.js @@ -1,5 +1,5 @@ -const {app, BrowserWindow, ipcMain} = require('electron') -const path = require('path') +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') function createWindow () { const mainWindow = new BrowserWindow({ @@ -19,7 +19,7 @@ function createWindow () { app.whenReady().then(() => { createWindow() - + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) diff --git a/docs/fiddles/ipc/pattern-1/preload.js b/docs/fiddles/ipc/pattern-1/preload.js index 822f4ed51622b..ce23688245237 100644 --- a/docs/fiddles/ipc/pattern-1/preload.js +++ b/docs/fiddles/ipc/pattern-1/preload.js @@ -1,5 +1,5 @@ -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electronAPI', { - setTitle: (title) => ipcRenderer.send('set-title', title) + setTitle: (title) => ipcRenderer.send('set-title', title) }) diff --git a/docs/fiddles/ipc/pattern-1/renderer.js b/docs/fiddles/ipc/pattern-1/renderer.js index c44f59a8df08c..67b775fa53945 100644 --- a/docs/fiddles/ipc/pattern-1/renderer.js +++ b/docs/fiddles/ipc/pattern-1/renderer.js @@ -1,6 +1,6 @@ const setButton = document.getElementById('btn') const titleInput = document.getElementById('title') setButton.addEventListener('click', () => { - const title = titleInput.value - window.electronAPI.setTitle(title) -}); + const title = titleInput.value + window.electronAPI.setTitle(title) +}) diff --git a/docs/fiddles/ipc/pattern-2/main.js b/docs/fiddles/ipc/pattern-2/main.js index 5492a7d159297..369ddf655787d 100644 --- a/docs/fiddles/ipc/pattern-2/main.js +++ b/docs/fiddles/ipc/pattern-2/main.js @@ -1,11 +1,9 @@ -const {app, BrowserWindow, ipcMain, dialog} = require('electron') -const path = require('path') +const { app, BrowserWindow, ipcMain, dialog } = require('electron/main') +const path = require('node:path') -async function handleFileOpen() { +async function handleFileOpen () { const { canceled, filePaths } = await dialog.showOpenDialog() - if (canceled) { - return - } else { + if (!canceled) { return filePaths[0] } } diff --git a/docs/fiddles/ipc/pattern-2/preload.js b/docs/fiddles/ipc/pattern-2/preload.js index cb78f84230f8b..32f4acd9da499 100644 --- a/docs/fiddles/ipc/pattern-2/preload.js +++ b/docs/fiddles/ipc/pattern-2/preload.js @@ -1,5 +1,5 @@ -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require('electron/renderer') -contextBridge.exposeInMainWorld('electronAPI',{ +contextBridge.exposeInMainWorld('electronAPI', { openFile: () => ipcRenderer.invoke('dialog:openFile') }) diff --git a/docs/fiddles/ipc/pattern-3/main.js b/docs/fiddles/ipc/pattern-3/main.js index 357aa64e0fb43..60e08ba80d443 100644 --- a/docs/fiddles/ipc/pattern-3/main.js +++ b/docs/fiddles/ipc/pattern-3/main.js @@ -1,5 +1,5 @@ -const {app, BrowserWindow, Menu, ipcMain} = require('electron') -const path = require('path') +const { app, BrowserWindow, Menu, ipcMain } = require('electron/main') +const path = require('node:path') function createWindow () { const mainWindow = new BrowserWindow({ @@ -12,14 +12,14 @@ function createWindow () { { label: app.name, submenu: [ - { - click: () => mainWindow.webContents.send('update-counter', 1), - label: 'Increment', - }, - { - click: () => mainWindow.webContents.send('update-counter', -1), - label: 'Decrement', - } + { + click: () => mainWindow.webContents.send('update-counter', 1), + label: 'Increment' + }, + { + click: () => mainWindow.webContents.send('update-counter', -1), + label: 'Decrement' + } ] } @@ -37,7 +37,7 @@ app.whenReady().then(() => { console.log(value) // will print value to Node console }) createWindow() - + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) diff --git a/docs/fiddles/ipc/pattern-3/preload.js b/docs/fiddles/ipc/pattern-3/preload.js index ad4dd27f1f9b2..b8d275650735e 100644 --- a/docs/fiddles/ipc/pattern-3/preload.js +++ b/docs/fiddles/ipc/pattern-3/preload.js @@ -1,5 +1,6 @@ -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electronAPI', { - handleCounter: (callback) => ipcRenderer.on('update-counter', callback) + onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)), + counterValue: (value) => ipcRenderer.send('counter-value', value) }) diff --git a/docs/fiddles/ipc/pattern-3/renderer.js b/docs/fiddles/ipc/pattern-3/renderer.js index 04fd4bca890a3..c1d97a8483319 100644 --- a/docs/fiddles/ipc/pattern-3/renderer.js +++ b/docs/fiddles/ipc/pattern-3/renderer.js @@ -1,8 +1,8 @@ const counter = document.getElementById('counter') -window.electronAPI.handleCounter((event, value) => { - const oldValue = Number(counter.innerText) - const newValue = oldValue + value - counter.innerText = newValue - event.sender.send('counter-value', newValue) +window.electronAPI.onUpdateCounter((value) => { + const oldValue = Number(counter.innerText) + const newValue = oldValue + value + counter.innerText = newValue.toString() + window.electronAPI.counterValue(newValue) }) diff --git a/docs/fiddles/ipc/webview-new-window/child.html b/docs/fiddles/ipc/webview-new-window/child.html new file mode 100644 index 0000000000000..90c94376c284b --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/child.html @@ -0,0 +1,3 @@ + + new window + diff --git a/docs/fiddles/ipc/webview-new-window/index.html b/docs/fiddles/ipc/webview-new-window/index.html new file mode 100644 index 0000000000000..8b461bd15f83a --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/index.html @@ -0,0 +1,4 @@ + + + + diff --git a/docs/fiddles/ipc/webview-new-window/main.js b/docs/fiddles/ipc/webview-new-window/main.js new file mode 100644 index 0000000000000..8b6aa41883c8a --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/main.js @@ -0,0 +1,51 @@ +// Modules to control application life and create native browser window +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') + +function createWindow () { + // Create the browser window. + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + webviewTag: true + } + }) + + mainWindow.webContents.on('did-attach-webview', (event, wc) => { + wc.setWindowOpenHandler((details) => { + mainWindow.webContents.send('webview-new-window', wc.id, details) + return { action: 'deny' } + }) + }) + + // and load the index.html of the app. + mainWindow.loadFile('index.html') + + // Open the DevTools. + // mainWindow.webContents.openDevTools() +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/ipc/webview-new-window/preload.js b/docs/fiddles/ipc/webview-new-window/preload.js new file mode 100644 index 0000000000000..99f3e6bc60f49 --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/preload.js @@ -0,0 +1,6 @@ +const { ipcRenderer } = require('electron/renderer') +const webview = document.getElementById('webview') +ipcRenderer.on('webview-new-window', (e, webContentsId, details) => { + console.log('webview-new-window', webContentsId, details) + webview.dispatchEvent(new Event('new-window')) +}) diff --git a/docs/fiddles/ipc/webview-new-window/renderer.js b/docs/fiddles/ipc/webview-new-window/renderer.js new file mode 100644 index 0000000000000..e62d0b4d17bc3 --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/renderer.js @@ -0,0 +1,4 @@ +const webview = document.getElementById('webview') +webview.addEventListener('new-window', () => { + console.log('got new-window event') +}) diff --git a/docs/fiddles/media/screenshot/take-screenshot/index.html b/docs/fiddles/media/screenshot/take-screenshot/index.html index 264899abddeac..ca05880ef4f98 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/index.html +++ b/docs/fiddles/media/screenshot/take-screenshot/index.html @@ -17,9 +17,6 @@

Take a Screenshot

Clicking the demo button will take a screenshot of your current screen and open it in your default viewer.

- + diff --git a/docs/fiddles/media/screenshot/take-screenshot/main.js b/docs/fiddles/media/screenshot/take-screenshot/main.js index be8ed98328b8d..2ce55cd94a37c 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/main.js +++ b/docs/fiddles/media/screenshot/take-screenshot/main.js @@ -1,10 +1,38 @@ -const { BrowserWindow, app, screen, ipcMain } = require('electron') +const { BrowserWindow, app, screen, ipcMain, desktopCapturer, shell } = require('electron/main') +const fs = require('node:fs').promises +const os = require('node:os') +const path = require('node:path') let mainWindow = null -ipcMain.handle('get-screen-size', () => { - return screen.getPrimaryDisplay().workAreaSize -}) +function determineScreenShotSize (devicePixelRatio) { + const screenSize = screen.getPrimaryDisplay().workAreaSize + const maxDimension = Math.max(screenSize.width, screenSize.height) + return { + width: maxDimension * devicePixelRatio, + height: maxDimension * devicePixelRatio + } +} + +async function takeScreenshot (devicePixelRatio) { + const thumbSize = determineScreenShotSize(devicePixelRatio) + const options = { types: ['screen'], thumbnailSize: thumbSize } + + const sources = await desktopCapturer.getSources(options) + for (const source of sources) { + const sourceName = source.name.toLowerCase() + if (sourceName === 'entire screen' || sourceName === 'screen 1') { + const screenshotPath = path.join(os.tmpdir(), 'screenshot.png') + + await fs.writeFile(screenshotPath, source.thumbnail.toPNG()) + shell.openExternal(`file://${screenshotPath}`) + + return `Saved screenshot to: ${screenshotPath}` + } + } +} + +ipcMain.handle('take-screenshot', (event, devicePixelRatio) => takeScreenshot(devicePixelRatio)) function createWindow () { const windowOptions = { @@ -12,7 +40,7 @@ function createWindow () { height: 300, title: 'Take a Screenshot', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } diff --git a/docs/fiddles/media/screenshot/take-screenshot/preload.js b/docs/fiddles/media/screenshot/take-screenshot/preload.js new file mode 100644 index 0000000000000..9af9f2faacf19 --- /dev/null +++ b/docs/fiddles/media/screenshot/take-screenshot/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + takeScreenshot: () => ipcRenderer.invoke('take-screenshot', window.devicePixelRatio) +}) diff --git a/docs/fiddles/media/screenshot/take-screenshot/renderer.js b/docs/fiddles/media/screenshot/take-screenshot/renderer.js index e7988f5067d18..6b4329e7df419 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/renderer.js +++ b/docs/fiddles/media/screenshot/take-screenshot/renderer.js @@ -1,42 +1,7 @@ -const { desktopCapturer, shell, ipcRenderer } = require('electron') - -const fs = require('fs') -const os = require('os') -const path = require('path') - const screenshot = document.getElementById('screen-shot') const screenshotMsg = document.getElementById('screenshot-path') screenshot.addEventListener('click', async (event) => { screenshotMsg.textContent = 'Gathering screens...' - const thumbSize = await determineScreenShotSize() - const options = { types: ['screen'], thumbnailSize: thumbSize } - - desktopCapturer.getSources(options, (error, sources) => { - if (error) return console.log(error) - - sources.forEach((source) => { - const sourceName = source.name.toLowerCase() - if (sourceName === 'entire screen' || sourceName === 'screen 1') { - const screenshotPath = path.join(os.tmpdir(), 'screenshot.png') - - fs.writeFile(screenshotPath, source.thumbnail.toPNG(), (error) => { - if (error) return console.log(error) - shell.openExternal(`file://${screenshotPath}`) - - const message = `Saved screenshot to: ${screenshotPath}` - screenshotMsg.textContent = message - }) - } - }) - }) + screenshotMsg.textContent = await window.electronAPI.takeScreenshot() }) - -async function determineScreenShotSize () { - const screenSize = await ipcRenderer.invoke('get-screen-size') - const maxDimension = Math.max(screenSize.width, screenSize.height) - return { - width: maxDimension * window.devicePixelRatio, - height: maxDimension * window.devicePixelRatio - } -} diff --git a/docs/fiddles/menus/customize-menus/index.html b/docs/fiddles/menus/customize-menus/index.html index e8b354f2a1865..1fda8f5ecd9df 100644 --- a/docs/fiddles/menus/customize-menus/index.html +++ b/docs/fiddles/menus/customize-menus/index.html @@ -1,128 +1,124 @@ - - - - - Customize Menus - - - -
-

Customize Menus

- -

- The Menu and MenuItem modules can be used to - create custom native menus. -

- -

- There are two kinds of menus: the application (top) menu and context - (right-click) menu. -

- -

- Open the - full API documentation(opens in new window) - in your browser. -

-
- -
-

Create an application menu

-
-
-

- The Menu and MenuItem modules allow you to - customize your application menu. If you don't set any menu, Electron - will generate a minimal menu for your app by default. -

- -

- If you click the 'View' option in the application menu and then the - 'App Menu Demo', you'll see an information box displayed. -

- -
-

ProTip

- Know operating system menu differences. -

- When designing an app for multiple operating systems it's - important to be mindful of the ways application menu conventions - differ on each operating system. -

-

- For instance, on Windows, accelerators are set with an - &. Naming conventions also vary, like between - "Settings" or "Preferences". Below are resources for learning - operating system specific standards. -

- -
-
-
-
- -
-

Create a context menu

-
-
-
- -
-

- A context, or right-click, menu can be created with the - Menu and MenuItem modules as well. You can - right-click anywhere in this app or click the demo button to see an - example context menu. -

- -

- In this demo we use the ipcRenderer module to show the - context menu when explicitly calling it from the renderer process. -

-

- See the full - context-menu event documentation - for all the available properties. -

-
-
-
- - - - + + + + + Customize Menus + + + +
+

Customize Menus

+ +

+ The Menu and MenuItem modules can be used to + create custom native menus. +

+ +

+ There are two kinds of menus: the application (top) menu and context + (right-click) menu. +

+ +

+ Open the + full API documentation(opens in new window) + in your browser. +

+
+ +
+

Create an application menu

+
+
+

+ The Menu and MenuItem modules allow you to + customize your application menu. If you don't set any menu, Electron + will generate a minimal menu for your app by default. +

+ +

+ If you click the 'View' option in the application menu and then the + 'App Menu Demo', you'll see an information box displayed. +

+ +
+

ProTip

+ Know operating system menu differences. +

+ When designing an app for multiple operating systems it's + important to be mindful of the ways application menu conventions + differ on each operating system. +

+

+ For instance, on Windows, accelerators are set with an + &. Naming conventions also vary, like between + "Settings" or "Preferences". Below are resources for learning + operating system specific standards. +

+ +
+
+
+
+ +
+

Create a context menu

+
+
+
+ +
+

+ A context, or right-click, menu can be created with the + Menu and MenuItem modules as well. You can + right-click anywhere in this app or click the demo button to see an + example context menu. +

+ +

+ In this demo we use the ipcRenderer module to show the + context menu when explicitly calling it from the renderer process. +

+

+ See the full + context-menu event documentation + for all the available properties. +

+
+
+
+ + + diff --git a/docs/fiddles/menus/customize-menus/main.js b/docs/fiddles/menus/customize-menus/main.js index db56e3f5fb519..e020c3c34c23d 100644 --- a/docs/fiddles/menus/customize-menus/main.js +++ b/docs/fiddles/menus/customize-menus/main.js @@ -6,8 +6,10 @@ const { ipcMain, app, shell, - dialog -} = require('electron') + dialog, + autoUpdater +} = require('electron/main') +const path = require('node:path') const menu = new Menu() menu.append(new MenuItem({ label: 'Hello' })) @@ -66,9 +68,9 @@ const template = [ // on reload, start fresh and close any old // open secondary windows if (focusedWindow.id === 1) { - BrowserWindow.getAllWindows().forEach(win => { + for (const win of BrowserWindow.getAllWindows()) { if (win.id > 1) win.close() - }) + } } focusedWindow.reload() } @@ -100,7 +102,7 @@ const template = [ })(), click: (item, focusedWindow) => { if (focusedWindow) { - focusedWindow.toggleDevTools() + focusedWindow.webContents.toggleDevTools() } } }, @@ -185,7 +187,7 @@ function addUpdateMenuItems (items, position) { visible: false, key: 'checkForUpdate', click: () => { - require('electron').autoUpdater.checkForUpdates() + autoUpdater.checkForUpdates() } }, { @@ -194,7 +196,7 @@ function addUpdateMenuItems (items, position) { visible: false, key: 'restartToUpdate', click: () => { - require('electron').autoUpdater.quitAndInstall() + autoUpdater.quitAndInstall() } } ] @@ -207,15 +209,15 @@ function findReopenMenuItem () { if (!menu) return let reopenMenuItem - menu.items.forEach(item => { + for (const item of menu.items) { if (item.submenu) { - item.submenu.items.forEach(item => { - if (item.key === 'reopenMenuItem') { - reopenMenuItem = item + for (const subitem of item.submenu.items) { + if (subitem.key === 'reopenMenuItem') { + reopenMenuItem = subitem } - }) + } } - }) + } return reopenMenuItem } @@ -294,7 +296,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -311,6 +313,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/menus/customize-menus/preload.js b/docs/fiddles/menus/customize-menus/preload.js new file mode 100644 index 0000000000000..00bc6be37da4f --- /dev/null +++ b/docs/fiddles/menus/customize-menus/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + showContextMenu: () => ipcRenderer.send('show-context-menu') +}) diff --git a/docs/fiddles/menus/customize-menus/renderer.js b/docs/fiddles/menus/customize-menus/renderer.js index 5527e1f20008d..89ba97dcc56a4 100644 --- a/docs/fiddles/menus/customize-menus/renderer.js +++ b/docs/fiddles/menus/customize-menus/renderer.js @@ -1,8 +1,6 @@ -const { ipcRenderer } = require('electron') - // Tell main process to show the menu when demo button is clicked const contextMenuBtn = document.getElementById('context-menu') contextMenuBtn.addEventListener('click', () => { - ipcRenderer.send('show-context-menu') + window.electronAPI.showContextMenu() }) diff --git a/docs/fiddles/menus/shortcuts/index.html b/docs/fiddles/menus/shortcuts/index.html index 6851357980c72..cabca0bf715a8 100644 --- a/docs/fiddles/menus/shortcuts/index.html +++ b/docs/fiddles/menus/shortcuts/index.html @@ -1,73 +1,73 @@ - - - - - - Keyboard Shortcuts - - - -
-

Keyboard Shortcuts

- -

The globalShortcut and Menu modules can be used to define keyboard shortcuts.

- -

- In Electron, keyboard shortcuts are called accelerators. - They can be assigned to actions in your application's Menu, - or they can be assigned globally so they'll be triggered even when - your app doesn't have keyboard focus. -

- -

- Open the full documentation for the - Menu, - Accelerator, - and - globalShortcut - APIs in your browser. -

- -
- -
-
-
-

- To try this demo, press CommandOrControl+Alt+K on your - keyboard. -

- -

- Global shortcuts are detected even when the app doesn't have - keyboard focus, and they must be registered after the app's - `ready` event is emitted. -

- -
-

ProTip

- Avoid overriding system-wide keyboard shortcuts. -

- When registering global shortcuts, it's important to be aware of - existing defaults in the target operating system, so as not to - override any existing behaviors. For an overview of each - operating system's keyboard shortcuts, view these documents: -

- - -
- -
-
-
- - - + + + + + + Keyboard Shortcuts + + + +
+

Keyboard Shortcuts

+ +

The globalShortcut and Menu modules can be used to define keyboard shortcuts.

+ +

+ In Electron, keyboard shortcuts are called accelerators. + They can be assigned to actions in your application's Menu, + or they can be assigned globally so they'll be triggered even when + your app doesn't have keyboard focus. +

+ +

+ Open the full documentation for the + Menu, + Accelerator, + and + globalShortcut + APIs in your browser. +

+ +
+ +
+
+
+

+ To try this demo, press CommandOrControl+Alt+K on your + keyboard. +

+ +

+ Global shortcuts are detected even when the app doesn't have + keyboard focus, and they must be registered after the app's + `ready` event is emitted. +

+ +
+

ProTip

+ Avoid overriding system-wide keyboard shortcuts. +

+ When registering global shortcuts, it's important to be aware of + existing defaults in the target operating system, so as not to + override any existing behaviors. For an overview of each + operating system's keyboard shortcuts, view these documents: +

+ + +
+ +
+
+
+ + + diff --git a/docs/fiddles/menus/shortcuts/main.js b/docs/fiddles/menus/shortcuts/main.js index ee3708bf565a7..9207702d44391 100644 --- a/docs/fiddles/menus/shortcuts/main.js +++ b/docs/fiddles/menus/shortcuts/main.js @@ -1,5 +1,5 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, globalShortcut, dialog } = require('electron') +const { app, BrowserWindow, globalShortcut, dialog, shell } = require('electron/main') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -9,10 +9,7 @@ function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } + height: 600 }) globalShortcut.register('CommandOrControl+Alt+K', () => { @@ -37,6 +34,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/dialogs/.keep b/docs/fiddles/native-ui/dialogs/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/index.html b/docs/fiddles/native-ui/dialogs/error-dialog/index.html index 2d516c28b683e..8f694ed265b9e 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/error-dialog/index.html @@ -1,81 +1,78 @@ - - - - - Error Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Error Dialog

-
-
- -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - error dialog. -

- -

- You can use an error dialog before the app's - ready event, which is useful for showing errors upon - startup. -

-
Renderer Process
-
-          
-const {ipcRenderer} = require('electron')
-
-const errorBtn = document.getElementById('error-dialog')
-
-errorBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-error-dialog')
-})
-          
-
Main Process
-
-          
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-error-dialog', (event) => {
-  dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
-})
-          
-        
-
-
-
- - - - + + + + + Error Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Error Dialog

+
+
+ +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + error dialog. +

+ +

+ You can use an error dialog before the app's + ready event, which is useful for showing errors upon + startup. +

+
Renderer Process
+
+          
+const {ipcRenderer} = require('electron')
+
+const errorBtn = document.getElementById('error-dialog')
+
+errorBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-error-dialog')
+})
+          
+
Main Process
+
+          
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-error-dialog', (event) => {
+  dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
+})
+          
+        
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/main.js b/docs/fiddles/native-ui/dialogs/error-dialog/main.js index 7567aa411bda2..149cf4e0f58ec 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/error-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/preload.js b/docs/fiddles/native-ui/dialogs/error-dialog/preload.js new file mode 100644 index 0000000000000..e47c74f614bf4 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/error-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openErrorDialog: () => ipcRenderer.send('open-error-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js index 4011066587dcb..20ae84f772242 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js @@ -1,18 +1,5 @@ -const { ipcRenderer, shell } = require('electron') - -const links = document.querySelectorAll('a[href]') const errorBtn = document.getElementById('error-dialog') -errorBtn.addEventListener('click', event => { - ipcRenderer.send('open-error-dialog') +errorBtn.addEventListener('click', () => { + window.electronAPI.openErrorDialog() }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/index.html b/docs/fiddles/native-ui/dialogs/information-dialog/index.html index 5600b653874ad..8e28f86362843 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/information-dialog/index.html @@ -1,104 +1,101 @@ - - - - - Information Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Information Dialog

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - information dialog. Options may be provided for responses which can - then be relayed back to the renderer process. -

- -

- Note: The title property is not displayed in macOS. -

- -

- An information dialog can contain an icon, your choice of buttons, - title and message. -

-
Renderer Process
-
-            
-const {ipcRenderer} = require('electron')
-
-const informationBtn = document.getElementById('information-dialog')
-
-informationBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-information-dialog')
-})
-
-ipcRenderer.on('information-dialog-selection', (event, index) => {
-  let message = 'You selected '
-  if (index === 0) message += 'yes.'
-  else message += 'no.'
-  document.getElementById('info-selection').innerHTML = message
-})
-            
-          
-
Main Process
-
-            
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-information-dialog', (event) => {
-  const options = {
-    type: 'info',
-    title: 'Information',
-    message: "This is an information dialog. Isn't it nice?",
-    buttons: ['Yes', 'No']
-  }
-  dialog.showMessageBox(options, (index) => {
-    event.sender.send('information-dialog-selection', index)
-  })
-})
-            
-          
-
-
-
- - - - + + + + + Information Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Information Dialog

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + information dialog. Options may be provided for responses which can + then be relayed back to the renderer process. +

+ +

+ Note: The title property is not displayed in macOS. +

+ +

+ An information dialog can contain an icon, your choice of buttons, + title and message. +

+
Renderer Process
+
+            
+const {ipcRenderer} = require('electron')
+
+const informationBtn = document.getElementById('information-dialog')
+
+informationBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-information-dialog')
+})
+
+ipcRenderer.on('information-dialog-selection', (event, index) => {
+  let message = 'You selected '
+  if (index === 0) message += 'yes.'
+  else message += 'no.'
+  document.getElementById('info-selection').innerHTML = message
+})
+            
+          
+
Main Process
+
+            
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-information-dialog', (event) => {
+  const options = {
+    type: 'info',
+    title: 'Information',
+    message: "This is an information dialog. Isn't it nice?",
+    buttons: ['Yes', 'No']
+  }
+  dialog.showMessageBox(options, (index) => {
+    event.sender.send('information-dialog-selection', index)
+  })
+})
+            
+          
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/main.js b/docs/fiddles/native-ui/dialogs/information-dialog/main.js index 3e81a5782076f..bbe460464c8cb 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/information-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,19 +59,15 @@ app.on('activate', function () { } }) - -ipcMain.on('open-information-dialog', event => { +ipcMain.handle('open-information-dialog', async () => { const options = { type: 'info', title: 'Information', message: "This is an information dialog. Isn't it nice?", buttons: ['Yes', 'No'] } - dialog.showMessageBox(options, index => { - event.sender.send('information-dialog-selection', index) - }) + return (await dialog.showMessageBox(options)).response }) - // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/preload.js b/docs/fiddles/native-ui/dialogs/information-dialog/preload.js new file mode 100644 index 0000000000000..5191aacea2bb2 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/information-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openInformationDialog: () => ipcRenderer.invoke('open-information-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js index 69ea9cdb1a2f2..57c8fcc0061b5 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js @@ -1,25 +1,7 @@ -const { ipcRenderer, shell } = require('electron') - const informationBtn = document.getElementById('information-dialog') -const links = document.querySelectorAll('a[href]') - -informationBtn.addEventListener('click', event => { - ipcRenderer.send('open-information-dialog') -}) -ipcRenderer.on('information-dialog-selection', (event, index) => { - let message = 'You selected ' - if (index === 0) message += 'yes.' - else message += 'no.' +informationBtn.addEventListener('click', async () => { + const index = await window.electronAPI.openInformationDialog() + const message = `You selected: ${index === 0 ? 'yes' : 'no'}` document.getElementById('info-selection').innerHTML = message }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html b/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html index df96f2e810812..9443a62ce91df 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html @@ -1,108 +1,105 @@ - - - - - Open File or Directory - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Open a File or Directory

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - open file (or directory) dialog. If a file is selected, the main - process can send that information back to the renderer process. -

-
Renderer Process
-
-          
-const {ipcRenderer} = require('electron')
-
-const selectDirBtn = document.getElementById('select-directory')
-
-selectDirBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-file-dialog')
-})
-
-ipcRenderer.on('selected-directory', (event, path) => {
-  document.getElementById('selected-file').innerHTML = `You selected: ${path}`
-})
-          
-        
-
Main Process
-
-          
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-file-dialog', (event) => {
-  dialog.showOpenDialog({
-    properties: ['openFile', 'openDirectory']
-  }, (files) => {
-    if (files) {
-      event.sender.send('selected-directory', files)
-    }
-  })
-})
-          
-        
- -
-

ProTip

- The sheet-style dialog on macOS. -

- On macOS you can choose between a "sheet" dialog or a default - dialog. The sheet version descends from the top of the window. To - use sheet version, pass the window as the first - argument in the dialog method. -

-
const ipc = require('electron').ipcMain
-const dialog = require('electron').dialog
-const BrowserWindow = require('electron').BrowserWindow
-
-
-ipc.on('open-file-dialog-sheet', function (event) {
-  const window = BrowserWindow.fromWebContents(event.sender)
-  const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
-})
-
-
-
-
- - - - + + + + + Open File or Directory + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Open a File or Directory

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + open file (or directory) dialog. If a file is selected, the main + process can send that information back to the renderer process. +

+
Renderer Process
+
+          
+const {ipcRenderer} = require('electron')
+
+const selectDirBtn = document.getElementById('select-directory')
+
+selectDirBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-file-dialog')
+})
+
+ipcRenderer.on('selected-directory', (event, path) => {
+  document.getElementById('selected-file').innerHTML = `You selected: ${path}`
+})
+          
+        
+
Main Process
+
+          
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-file-dialog', (event) => {
+  dialog.showOpenDialog({
+    properties: ['openFile', 'openDirectory']
+  }, (files) => {
+    if (files) {
+      event.sender.send('selected-directory', files)
+    }
+  })
+})
+          
+        
+ +
+

ProTip

+ The sheet-style dialog on macOS. +

+ On macOS you can choose between a "sheet" dialog or a default + dialog. The sheet version descends from the top of the window. To + use sheet version, pass the window as the first + argument in the dialog method. +

+
const ipc = require('electron').ipcMain
+const dialog = require('electron').dialog
+const BrowserWindow = require('electron').BrowserWindow
+
+
+ipc.on('open-file-dialog-sheet', function (event) {
+  const window = BrowserWindow.fromWebContents(event.sender)
+  const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
+})
+
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js index 24b9164dab3a9..5721c69869a55 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,18 +59,11 @@ app.on('activate', function () { } }) - -ipcMain.on('open-file-dialog', event => { - dialog.showOpenDialog( - { - properties: ['openFile', 'openDirectory'] - }, - files => { - if (files) { - event.sender.send('selected-directory', files) - } - } - ) +ipcMain.handle('open-file-dialog', async () => { + const options = { + properties: ['openFile', 'openDirectory'] + } + return (await dialog.showOpenDialog(options)).filePaths }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js new file mode 100644 index 0000000000000..ace7c2d165710 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openFileDialog: () => ipcRenderer.invoke('open-file-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js index 5389ea50709a0..badfd8776ef63 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js @@ -1,22 +1,6 @@ -const { ipcRenderer, shell } = require('electron') - const selectDirBtn = document.getElementById('select-directory') -const links = document.querySelectorAll('a[href]') - -selectDirBtn.addEventListener('click', event => { - ipcRenderer.send('open-file-dialog') -}) -ipcRenderer.on('selected-directory', (event, path) => { +selectDirBtn.addEventListener('click', async () => { + const path = await window.electronAPI.openFileDialog() document.getElementById('selected-file').innerHTML = `You selected: ${path}` }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/index.html b/docs/fiddles/native-ui/dialogs/save-dialog/index.html index b7ceaee7b1202..d8e97edbf8d5a 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/save-dialog/index.html @@ -1,91 +1,88 @@ - - - - - Save Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Save Dialog

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - save dialog. It returns the path selected by the user which can be - relayed back to the renderer process. -

-
Renderer Process
-
-            
-const {ipcRenderer} = require('electron')
-
-const saveBtn = document.getElementById('save-dialog')
-
-saveBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('save-dialog')
-})
-
-ipcRenderer.on('saved-file', (event, path) => {
-  if (!path) path = 'No path'
-  document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
-})
-            
-          
-
Main Process
-
-            
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('save-dialog', (event) => {
-  const options = {
-    title: 'Save an Image',
-    filters: [
-      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
-    ]
-  }
-  dialog.showSaveDialog(options, (filename) => {
-    event.sender.send('saved-file', filename)
-  })
-})
-            
-          
-
-
-
- - - - + + + + + Save Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Save Dialog

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + save dialog. It returns the path selected by the user which can be + relayed back to the renderer process. +

+
Renderer Process
+
+            
+const {ipcRenderer} = require('electron')
+
+const saveBtn = document.getElementById('save-dialog')
+
+saveBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('save-dialog')
+})
+
+ipcRenderer.on('saved-file', (event, path) => {
+  if (!path) path = 'No path'
+  document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
+})
+            
+          
+
Main Process
+
+            
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('save-dialog', (event) => {
+  const options = {
+    title: 'Save an Image',
+    filters: [
+      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
+    ]
+  }
+  dialog.showSaveDialog(options, (filename) => {
+    event.sender.send('saved-file', filename)
+  })
+})
+            
+          
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/main.js b/docs/fiddles/native-ui/dialogs/save-dialog/main.js index b6e6ec1331be9..44c8fa1a1e29b 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/save-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,14 +59,12 @@ app.on('activate', function () { } }) -ipcMain.on('save-dialog', event => { +ipcMain.handle('save-dialog', async () => { const options = { title: 'Save an Image', filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }] } - dialog.showSaveDialog(options, filename => { - event.sender.send('saved-file', filename) - }) + return (await dialog.showSaveDialog(options)).filePath }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/preload.js b/docs/fiddles/native-ui/dialogs/save-dialog/preload.js new file mode 100644 index 0000000000000..6d63c2e4552ef --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/save-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + saveDialog: () => ipcRenderer.invoke('save-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js index 9f6da5546946d..c36088c775564 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js @@ -1,23 +1,6 @@ -const { ipcRenderer, shell } = require('electron') - const saveBtn = document.getElementById('save-dialog') -const links = document.querySelectorAll('a[href]') - -saveBtn.addEventListener('click', event => { - ipcRenderer.send('save-dialog') -}) -ipcRenderer.on('saved-file', (event, path) => { - if (!path) path = 'No path' +saveBtn.addEventListener('click', async () => { + const path = await window.electronAPI.saveDialog() document.getElementById('file-saved').innerHTML = `Path selected: ${path}` }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/drag-and-drop/.keep b/docs/fiddles/native-ui/drag-and-drop/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/drag-and-drop/index.html b/docs/fiddles/native-ui/drag-and-drop/index.html index 40f2733cd266d..0ed547401f680 100644 --- a/docs/fiddles/native-ui/drag-and-drop/index.html +++ b/docs/fiddles/native-ui/drag-and-drop/index.html @@ -1,76 +1,73 @@ - - - - - Drag and drop files - - - -
-

Drag and drop files

-
Supports: Win, macOS, Linux | Process: Both
-

- Electron supports dragging files and content out from web content into - the operating system's world. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Dragging files

-
-
- Drag Demo -
-

- Click and drag the link above to copy the renderer process - javascript file on to your machine. -

- -

- In this demo, the webContents.startDrag() API is called - in response to the ondragstart event. -

-
Renderer Process
-

-const {ipcRenderer} = require('electron')
-
-const dragFileLink = document.getElementById('drag-file-link')
-
-dragFileLink.addEventListener('dragstart', (event) => {
-  event.preventDefault()
-  ipcRenderer.send('ondragstart', __filename)
-})
-        
-
Main Process
-
-            
-const {ipcMain} = require('electron')
-const path = require('path')
-
-ipcMain.on('ondragstart', (event, filepath) => {
-  const iconName = 'codeIcon.png'
-  event.sender.startDrag({
-    file: filepath,
-    icon: path.join(__dirname, iconName)
-  })
-})
-            
-
-
-
- - - - + + + + + Drag and drop files + + + +
+

Drag and drop files

+
Supports: Win, macOS, Linux | Process: Both
+

+ Electron supports dragging files and content out from web content into + the operating system's world. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Dragging files

+
+
+ Drag Demo +
+

+ Click and drag the link above to copy the renderer process + javascript file on to your machine. +

+ +

+ In this demo, the webContents.startDrag() API is called + in response to the ondragstart event. +

+
Renderer Process
+

+const {ipcRenderer} = require('electron')
+
+const dragFileLink = document.getElementById('drag-file-link')
+
+dragFileLink.addEventListener('dragstart', (event) => {
+  event.preventDefault()
+  ipcRenderer.send('ondragstart', __filename)
+})
+        
+
Main Process
+
+            
+const {ipcMain} = require('electron')
+const path = require('path')
+
+ipcMain.on('ondragstart', (event, filepath) => {
+  const iconName = 'codeIcon.png'
+  event.sender.startDrag({
+    file: filepath,
+    icon: path.join(__dirname, iconName)
+  })
+})
+            
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/drag-and-drop/main.js b/docs/fiddles/native-ui/drag-and-drop/main.js index b7093b59a868b..b4dce1a663708 100644 --- a/docs/fiddles/native-ui/drag-and-drop/main.js +++ b/docs/fiddles/native-ui/drag-and-drop/main.js @@ -1,5 +1,7 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, nativeImage } = require('electron') +const { app, BrowserWindow, ipcMain, nativeImage, shell } = require('electron/main') +const path = require('node:path') + // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow @@ -10,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -27,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -51,7 +59,8 @@ app.on('activate', function () { } }) -ipcMain.on('ondragstart', (event, filepath) => { +ipcMain.on('ondragstart', (event) => { + const filepath = path.join(__dirname, 'renderer.js') const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAACsZJREFUWAmtWFlsXFcZ/u82++Jt7IyT2Em6ZFHTpAtWIzspEgjEUhA8VNAiIYEQUvuABBIUwUMkQIVKPCIoEiABLShISEBbhFJwIGRpIKRpbNeJ7bh2HHvssR3PPnPnLnzfmRlju6EQqUc+c++c8y/fv54z1uQOh+/7Glh0TD59TE/TND7lnfa4/64OKsM071QoeZpA/y9WWvk/B4XCC06TUC+Xyw8HTXNQ1+Ww6PpOrMebewXxvBueJ6/XHOdMJBL5J9Y97m2R0SS/wweE6JxkGx5dilWr1S/7dXsEa2o4+LyFmcFcaL5zbX3Y9gh5hpeWYpSB9XV5/H678V89BGYDXnHJlCsWn4gHrGc1K9CXxferOdvPOOKUfF8cH7nUyCtklQZXih/VNNlmirk3GdBSoIcRswW7/vVkLPYi5W2Uze8bh7J+4wLfh4dViFx5/nmrUi7/MhGNvrCkBfpeWqnW/7BUdadqntQ8zwr6vhUV34xpYnDynWvcmwQNaclDXsqgLMqkocPDw7fNx7d5qIX+/PmJxKGD6VdDkeh7ztyqOFfrokGCEWiiZ1mp0uITnuKAosaT7+pNxMYTyefutcQfbA+b1XLpH5fnF97/yD335Fu6mqTqsclDINBVmI4fDxw80KPAvJSt1MZtMcLiGxYUu83p4UkgnJZlqcl3LAj3WnTkIS9lUBYNPJjueVWgg7qocyOgliFqjZsg8gq5tRdiieQTf1gq15Y8CUbRZtyWOzZwc8lEqS3PTCtgqd13ieO68BQ2uNl64tXAewktrFuX2mPdkWAxn3sxnmx7sqUTJGqso8MGS9tbXFz8DMH8bblUX3T9QARVi8RV8qljfcJy0zRlaf6mzHEuzEtmekqCoZB4rqp0OmudHtUnlEWZlE0d1EWd1N3EozourcO65pw4eTIZQTW9VazJtbqvw9XwKVFQMsKDBuNhtp4uvGGFI+IDgKnpMjYyIis3ZsQMBIR7pONsIaMsyqRs6ohY1rPUSd3EQFDqo+kdZ3Fh4aupbdu+99uFQr2A1CBs4uEAjZjIFUMHi4dVxMXzCdCXQj4vBrwVCofl0ulTcv/DAxJJJBUPc8mpoyI2JDw7bFyT+ifTcSubyXytJ51+roWBxwG9Q73WWjZ7eSUU3//nXM0NI+x0PBGrTSgsLS9JFuFxHFrvSqIrJV279gi6tjiVspTza3JjZhY+0CQZj0mlWJSeHTslCro6eFqymCcVVN77kkGjs1p4sy2VOoSlOrFwT+XR+PjkgGaZ+ycKVbRTYUdVrmaImCvzk1dlFCEJdHRJ284+ie/ol0h7p7jFvExcvCCXzp2Rqem3pAMAiqWS6JGYhFI9Mjo6KjevXVUyKEuFHrKpY6JQ8TXT3D8+OTkAHBw6o6LCFo9ag3o4JtlCyTHEt5AxKvS6YUi5kJeZG3Py0NAxlLcJ9xti+K7Mjo/JfGZRuvv6Ze+9+yWEhDZAvzg3JyhX2d6/S7q6e+TimdOS7ElLKBZDwqvmj6rztayr1fVI1IoXi4PAcYZY1tPEEO1wEVlXgRFBDcmIXTqJsS+XyhKLJ5A/OpIVXXptWUYv/UvaenfIocEhMQ2EzHHErlXFCgQl3paU1eVl6QAY8sQTCSmVihKJx1V/ogvgIYF/pACdcMBhqONoHhF88/2d+bojyA6cRvje2IdFjoSjUSnBS8hgyS9lZOzKFdmPxO3o6gQIGzwuDn1dVSCtCKPy1pZXlATXqUsVYMLRmKo87vP4Y1ioqwCdCegmMYx3W/VPn8RrSDwwIMMbcEjkYo29JZVOy+ybI7K4eksODx1VSqvligpReSVLgySM/FI5h2q062jNyL3s7FtoAyGJIlx1225UmwJF6aJRJ3XzHXO9bWvsJa3jQFlBJkz6iuXdu32HzM7MyP0PPNgAU6ko4Qzp6b+flr8MD9OYJg9CwtzL5+T65ITs2bsP3mGxN/ZbBcOn0sk20gAkLQ+huXpFi8vkoY9AoyDjxTR1mbo6Ltt275HpN0dlNxQE40mVM8Ajjxx9VAGhAvQR1akZFCq799ADysMuQqOxh2FNmamEaz51ItGLfFD9+oUJoZkLowHoFA2mljUacqOMflKuVmHpfmnfvlMuvXZeStmMBIMhcWEdjgFJtrUjXI0KchAuAg0ilxLJNoRVBxhIBm0TjjKAuqjTqTs3CQZ6QUUMGFW7eiWMUg6w+yo8YMW7DqtqlZLkUDV2ISfd29KyDwk9MjYmMyOXxQIIKuShqo4VGFNBEgeDQYqVam5N5tEePFQgURIUBCsd1EWd1XrtDUUMLARD9bKaK5ytQ2Gb75g8WMiEP6VkfnZGevv6UF1vSBW5E0PFDAweFRvlfun8WVmamhDNrkmweQ0pwaPt6M4m8mgKTTFXqcrV0ZH1FKBg6qAu6qTuJiCV1Cp2Q0NDr9Uq5Ym+oMEDlSewsoRwrVBEaij7AJ4s7zrOpumxEdm15y6558GHJVe1Zezy6zJx6aJkpq5JFB4z6zVZmBiX1VWUP0IY4CFMYcpQdZ3xqIs6oftCE5DHKwd0q/tzOV8svdDb3nk8VnG9qmgQC0ZURz8Ur91alXgSByZ6ES9kZZTr/PR16UOCh+7dq0CWyyXJ4xqCQ0nKt9YQSlPue2gAeYZzD7yNLk0wmqAreb2WYSxAJ8Dget64wxtEBlDaqVOn/K5dB67t6+t5MhoMJuc8w8UPKiQ9CQR9JK5czhZAQxPt7TKF3OiAIisUViAD2Lg5d0P2HDgoKeRaW0enyqVwBJcO5fFG5dqa7h406qaeX8384uTZL5w9+UqxhYHFp0YLIYA9ddfu3T+4UJF6Rg+YAc9D0+RoIGP1ULhpWspr10evyK7+ftWTrk9PS/++A9KZSm26cih2mMOErem6n/ZsZwA2TM/MPHXs2LEftnSTbh0Q36mIIbx44cLvOnu3f+xUwbWLmoHTCUlF6g2jBQo/GnFrnGNqSHdvr+rIKGMW1KahwEBdzHft98aNwMr8zd8/NDDwccihc0hLi3GubRjY0Bm6H19fPvnZI4c/fHd7PJ2peXYZ+WQ26JufZELjQ6lbAQtnWre0d3apY8TFIdtAo+Qri6mupsB49lBMC+QXF0YefObZT8j0eKWlswVjEyCCOXHihPGb575VCvVuf3lvetsH9rXF0rla3cnhpoIGjgsUPhR3I4TMKYJQV1Z6WO02aEjHa5mNe3OPW3OPRHVrbXFh9Ocvv/KR1372owx1Pf3005uc35Ddgtd8rsf06IdS5777zZ+mUqmPzjm6TPpmvayZOq4LyATeCzkanmiy4qEuC/yXiO8CSMRzvLs1x9phepLNZl868sy3Pyen/5hd1/EfRvWmuvSWNeaRS/RkPDI4+NjE1NSXEoXlpaNB1zqo20abi59/vu/UfM2pie7WUDVq8l3wTwnskeZ+zTbIQ17KoCzKpGzq2KqX32/roRbh8ePHdUzl0s9/5Rv9n/7go19MxCKfCkZiu3V06wrO5gocxL7Dgd/IEobEMH6rejg+auXidL5Y/vWv/vTX53/y/e/MkGajTH7fOt4RUJOY1df4RdtY6ICFRzqTySOhUOA+3Ai3o31H1ZbnlXBruFmt2iMrudy5xx9//BzWV7nXDBGN2xpjbt/5oGUEdhtO3iD47xZOvm8a5CHvpsV38wsUaMwBWsz3rbK5xr0mzdv2t9Jv/f5vhsF4J+Q63IUAAAAASUVORK5CYII=') event.sender.startDrag({ diff --git a/docs/fiddles/native-ui/drag-and-drop/preload.js b/docs/fiddles/native-ui/drag-and-drop/preload.js new file mode 100644 index 0000000000000..bad5ed4c8466c --- /dev/null +++ b/docs/fiddles/native-ui/drag-and-drop/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + dragStart: () => ipcRenderer.send('ondragstart') +}) diff --git a/docs/fiddles/native-ui/drag-and-drop/renderer.js b/docs/fiddles/native-ui/drag-and-drop/renderer.js index 67f35d61ee1b7..031601023d9a9 100644 --- a/docs/fiddles/native-ui/drag-and-drop/renderer.js +++ b/docs/fiddles/native-ui/drag-and-drop/renderer.js @@ -1,21 +1,6 @@ -const { ipcRenderer } = require('electron') -const shell = require('electron').shell - -const links = document.querySelectorAll('a[href]') - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) - const dragFileLink = document.getElementById('drag-file-link') dragFileLink.addEventListener('dragstart', event => { event.preventDefault() - ipcRenderer.send('ondragstart', __filename) + window.electronAPI.dragStart() }) diff --git a/docs/fiddles/native-ui/external-links-file-manager/.keep b/docs/fiddles/native-ui/external-links-file-manager/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html b/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html deleted file mode 100644 index f96fae00f79c6..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - Open external links - - -
-
-
-
- -
-

- If you do not want your app to open website links - within the app, you can use the shell module - to open them externally. When clicked, the links will open outside - of your app and in the user's default web browser. -

-

- When the demo button is clicked, the electron website will open in - your browser. -

-

-
Renderer Process
-

-                const { shell } = require('electron')
-                const exLinksBtn = document.getElementById('open-ex-links')
-                exLinksBtn.addEventListener('click', (event) => {
-                shell.openExternal('https://electronjs.org')
-                }) 
-            
- -
-

ProTip

- Open all outbound links externally. -

- You may want to open all http and - https links outside of your app. To do this, query - the document and loop through each link and add a listener. This - app uses the code below which is located in - assets/ex-links.js. -

-
Renderer Process
-

-                const { shell } = require('electron')
-                const links = document.querySelectorAll('a[href]')
-                Array.prototype.forEach.call(links, (link) => {
-                    const url = link.getAttribute('href')
-                    if (url.indexOf('http') === 0) {
-                    link.addEventListener('click', (e) => {
-                        e.preventDefault()
-                        shell.openExternal(url)
-                    })
-                }})
-            
-
-
-
-
- - - - diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js b/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js deleted file mode 100644 index 8c60edf69f8b3..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { app, BrowserWindow } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Open External Links', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js deleted file mode 100644 index 14ed2d979f628..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js +++ /dev/null @@ -1,21 +0,0 @@ -const { shell } = require('electron') - -const exLinksBtn = document.getElementById('open-ex-links') - -exLinksBtn.addEventListener('click', (event) => { - shell.openExternal('https://electronjs.org') -}) - -const OpenAllOutboundLinks = () => { - const links = document.querySelectorAll('a[href]') - - Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } - }) -} diff --git a/docs/fiddles/native-ui/external-links-file-manager/index.html b/docs/fiddles/native-ui/external-links-file-manager/index.html index c4b41b9905556..83788b8e4f74b 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/index.html +++ b/docs/fiddles/native-ui/external-links-file-manager/index.html @@ -1,104 +1,100 @@ - - - - - Open external links and the file manager - - -
-

- Open external links and the file manager -

-

- The shell module in Electron allows you to access certain - native elements like the file manager and default web browser. -

- -

This module works in both the main and renderer process.

-

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Open Path in File Manager

-
-
- -
-

- This demonstrates using the shell module to open the - system file manager at a particular location. -

-

- Clicking the demo button will open your file manager at the root. -

-
-
-
- -
-
-

Open External Links

-
-
- -
-

- If you do not want your app to open website links - within the app, you can use the shell module - to open them externally. When clicked, the links will open outside - of your app and in the user's default web browser. -

-

- When the demo button is clicked, the electron website will open in - your browser. -

-

- -
-

ProTip

- Open all outbound links externally. -

- You may want to open all http and - https links outside of your app. To do this, query - the document and loop through each link and add a listener. This - app uses the code below which is located in - assets/ex-links.js. -

-
Renderer Process
-
-                
-const shell = require('electron').shell
-
-const links = document.querySelectorAll('a[href]')
-
-Array.prototype.forEach.call(links, (link) => {
-  const url = link.getAttribute('href')
-  if (url.indexOf('http') === 0) {
-    link.addEventListener('click', (e) => {
-      e.preventDefault()
-      shell.openExternal(url)
-    })
-  }
-})
-                
-              
-
-
-
-
- - - - + + + + + Open external links and the file manager + + +
+

+ Open external links and the file manager +

+

+ The shell module in Electron allows you to access certain + native elements like the file manager and default web browser. +

+ +

This module works in both the main and renderer process.

+

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Open Path in File Manager

+
+
+ +
+

+ This demonstrates using the shell module to open the + system file manager at a particular location. +

+

+ Clicking the demo button will open your file manager at the root. +

+
+
+
+ +
+
+

Open External Links

+
+
+ +
+

+ If you do not want your app to open website links + within the app, you can use the shell module + to open them externally. When clicked, the links will open outside + of your app and in the user's default web browser. +

+

+ When the demo button is clicked, the electron website will open in + your browser. +

+

+ +
+

ProTip

+ Open all outbound links externally. +

+ You may want to open all http and + https links outside of your app. To do this, query + the document and loop through each link and add a listener. This + app uses the code below which is located in + assets/ex-links.js. +

+
Renderer Process
+
+                
+const shell = require('electron').shell
+
+const links = document.querySelectorAll('a[href]')
+
+for (const link of links) {
+  const url = link.getAttribute('href')
+  if (url.indexOf('http') === 0) {
+    link.addEventListener('click', (e) => {
+      e.preventDefault()
+      shell.openExternal(url)
+    })
+  }
+}
+                
+              
+
+
+
+
+ + + diff --git a/docs/fiddles/native-ui/external-links-file-manager/main.js b/docs/fiddles/native-ui/external-links-file-manager/main.js index 6291dcad9c993..b98a8669b0ba7 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/main.js +++ b/docs/fiddles/native-ui/external-links-file-manager/main.js @@ -1,5 +1,15 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell, ipcMain } = require('electron/main') +const path = require('node:path') +const os = require('node:os') + +ipcMain.on('open-home-dir', () => { + shell.showItemInFolder(os.homedir()) +}) + +ipcMain.on('open-external', (event, url) => { + shell.openExternal(url) +}) // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +21,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +38,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html deleted file mode 100644 index be6a38c9fa167..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - -
-
-

Open Path in File Manager

- Supports: Win, macOS, Linux | Process: Both -
-

This demonstrates using the shell module to open the system file manager at a particular location.

-

Clicking the demo button will open your file manager at the root.

-
- -
-
-
-
- - - \ No newline at end of file diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js deleted file mode 100644 index 9246b95bb242c..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { app, BrowserWindow } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Open Path in File Manager', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js deleted file mode 100644 index d49754cdb7311..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js +++ /dev/null @@ -1,8 +0,0 @@ -const { shell } = require('electron') -const os = require('os') - -const fileManagerBtn = document.getElementById('open-file-manager') - -fileManagerBtn.addEventListener('click', (event) => { - shell.showItemInFolder(os.homedir()) -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/preload.js b/docs/fiddles/native-ui/external-links-file-manager/preload.js new file mode 100644 index 0000000000000..9be85a13eaeba --- /dev/null +++ b/docs/fiddles/native-ui/external-links-file-manager/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openHomeDir: () => ipcRenderer.send('open-home-dir'), + openExternal: (url) => ipcRenderer.send('open-external', url) +}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/renderer.js index 5ce5bae2da3aa..6903268fd0d02 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/renderer.js +++ b/docs/fiddles/native-ui/external-links-file-manager/renderer.js @@ -1,13 +1,10 @@ -const { shell } = require('electron') -const os = require('os') - const exLinksBtn = document.getElementById('open-ex-links') const fileManagerBtn = document.getElementById('open-file-manager') fileManagerBtn.addEventListener('click', (event) => { - shell.showItemInFolder(os.homedir()) + window.electronAPI.openHomeDir() }) exLinksBtn.addEventListener('click', (event) => { - shell.openExternal('https://electronjs.org') + window.electronAPI.openExternal('https://electronjs.org') }) diff --git a/docs/fiddles/native-ui/notifications/.keep b/docs/fiddles/native-ui/notifications/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/notifications/basic-notification/index.html b/docs/fiddles/native-ui/notifications/basic-notification/index.html deleted file mode 100644 index 2ffd45453701a..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -
-

Basic notification

- Supports: Win 7+, macOS, Linux (that supports libnotify)| Process: Renderer -
-
- -
-

This demo demonstrates a basic notification. Text only.

-
-
- - - diff --git a/docs/fiddles/native-ui/notifications/basic-notification/main.js b/docs/fiddles/native-ui/notifications/basic-notification/main.js deleted file mode 100644 index b05ea9cbcc6e5..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { BrowserWindow, app } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 300, - title: 'Basic Notification', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/notifications/basic-notification/renderer.js b/docs/fiddles/native-ui/notifications/basic-notification/renderer.js deleted file mode 100644 index a46583c683dea..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const notification = { - title: 'Basic Notification', - body: 'Short message part' -} - -const notificationButton = document.getElementById('basic-noti') - -notificationButton.addEventListener('click', () => { - const myNotification = new window.Notification(notification.title, notification) - - myNotification.onclick = () => { - console.log('Notification clicked') - } -}) diff --git a/docs/fiddles/native-ui/notifications/index.html b/docs/fiddles/native-ui/notifications/index.html index 2848ad6d552d3..0eb9e213d556b 100644 --- a/docs/fiddles/native-ui/notifications/index.html +++ b/docs/fiddles/native-ui/notifications/index.html @@ -1,67 +1,64 @@ - - - - - Desktop notifications - - -
-

Desktop notifications

-

- The notification module in Electron allows you to add basic - desktop notifications. -

- -

- Electron conveniently allows developers to send notifications with the - HTML5 Notification API, - using the currently running operating system’s native notification - APIs to display it. -

- -

- Note: Since this is an HTML5 API it is only available in the - renderer process. -

- -

- Open the - - full API documentation(opens in new window) - - in your browser. -

-
- -
-
-

Basic notification

-
-
- -
-

This demo demonstrates a basic notification. Text only.

-
-
-
- -
-
-

Notification with image

-
-
- -
-

- This demo demonstrates a basic notification. Both text and a image -

-
-
-
- - - - + + + + + Desktop notifications + + +
+

Desktop notifications

+

+ The notification module in Electron allows you to add basic + desktop notifications. +

+ +

+ Electron conveniently allows developers to send notifications with the + HTML5 Notification API, + using the currently running operating system’s native notification + APIs to display it. +

+ +

+ Note: Since this is an HTML5 API it is only available in the + renderer process. +

+ +

+ Open the + + full API documentation(opens in new window) + + in your browser. +

+
+ +
+
+

Basic notification

+
+
+ +
+

This demo demonstrates a basic notification. Text only.

+
+
+
+ +
+
+

Notification with image

+
+
+ +
+

+ This demo demonstrates a basic notification. Both text and a image +

+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/notifications/main.js b/docs/fiddles/native-ui/notifications/main.js index 6291dcad9c993..f880a67a492c2 100644 --- a/docs/fiddles/native-ui/notifications/main.js +++ b/docs/fiddles/native-ui/notifications/main.js @@ -1,5 +1,5 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell } = require('electron/main') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -9,10 +9,7 @@ function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } + height: 600 }) // and load the index.html of the app. @@ -28,6 +25,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/index.html b/docs/fiddles/native-ui/notifications/notification-with-image/index.html deleted file mode 100644 index 5b9df4e78ecb5..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -
-

Notification with image

- Supports: Win 7+, macOS, Linux (that supports libnotify)| Process: Renderer -
-
- -
-

This demo demonstrates an advanced notification. Both text and image.

-
-
- - - diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/main.js b/docs/fiddles/native-ui/notifications/notification-with-image/main.js deleted file mode 100644 index 40c6001a99ecd..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { BrowserWindow, app } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 300, - title: 'Advanced Notification', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js b/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js deleted file mode 100644 index 84c43d2e111be..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const notification = { - title: 'Notification with image', - body: 'Short message plus a custom image', - icon: 'https://raw.githubusercontent.com/electron/electron-api-demos/v2.0.2/assets/img/programming.png' -} -const notificationButton = document.getElementById('advanced-noti') - -notificationButton.addEventListener('click', () => { - const myNotification = new window.Notification(notification.title, notification) - - myNotification.onclick = () => { - console.log('Notification clicked') - } -}) diff --git a/docs/fiddles/native-ui/tray/.keep b/docs/fiddles/native-ui/tray/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/tray/index.html b/docs/fiddles/native-ui/tray/index.html index 81a25e1a864ef..22156f39239c3 100644 --- a/docs/fiddles/native-ui/tray/index.html +++ b/docs/fiddles/native-ui/tray/index.html @@ -1,47 +1,47 @@ - - - - - Tray - - -
-

Tray

-

- The tray module allows you to create an icon in the - operating system's notification area. -

-

This icon can also have a context menu attached.

- -

- Open the - - full API documentation - - in your browser. -

-
-
-
-

ProTip

- Tray support in Linux. -

- On Linux distributions that only have app indicator support, users - will need to install libappindicator1 to make the - tray icon work. See the - - full API documentation - - for more details about using Tray on Linux. -

-
-
- - - - - - + + + + + Tray + + +
+

Tray

+

+ The tray module allows you to create an icon in the + operating system's notification area. +

+

This icon can also have a context menu attached.

+ +

+ Open the + + full API documentation + + in your browser. +

+
+
+
+

ProTip

+ Tray support in Linux. +

+ On Linux distributions that only have app indicator support, users + will need to install libappindicator1 to make the + tray icon work. See the + + full API documentation + + for more details about using Tray on Linux. +

+
+
+ + + + + + diff --git a/docs/fiddles/native-ui/tray/main.js b/docs/fiddles/native-ui/tray/main.js index 3d5ce65e02a43..2a238a265c4c0 100644 --- a/docs/fiddles/native-ui/tray/main.js +++ b/docs/fiddles/native-ui/tray/main.js @@ -1,4 +1,4 @@ -const { app, Tray, Menu, nativeImage } = require('electron') +const { app, Tray, Menu, nativeImage } = require('electron/main') let tray diff --git a/docs/fiddles/quick-start/main.js b/docs/fiddles/quick-start/main.js index 519a67947cdbb..c614294e01db3 100644 --- a/docs/fiddles/quick-start/main.js +++ b/docs/fiddles/quick-start/main.js @@ -1,5 +1,5 @@ -const { app, BrowserWindow } = require('electron') -const path = require('path') +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') function createWindow () { const win = new BrowserWindow({ @@ -28,4 +28,3 @@ app.on('window-all-closed', () => { app.quit() } }) - diff --git a/docs/fiddles/quick-start/preload.js b/docs/fiddles/quick-start/preload.js index 7674d012240c4..d5f73597ee86b 100644 --- a/docs/fiddles/quick-start/preload.js +++ b/docs/fiddles/quick-start/preload.js @@ -8,4 +8,3 @@ window.addEventListener('DOMContentLoaded', () => { replaceText(`${type}-version`, process.versions[type]) } }) - diff --git a/docs/fiddles/screen/fit-screen/main.js b/docs/fiddles/screen/fit-screen/main.js index 8fbaabcc5b850..9b1ffcbbe0c10 100644 --- a/docs/fiddles/screen/fit-screen/main.js +++ b/docs/fiddles/screen/fit-screen/main.js @@ -1,16 +1,13 @@ // Retrieve information about screen size, displays, cursor position, etc. // // For more info, see: -// https://electronjs.org/docs/api/screen +// https://www.electronjs.org/docs/latest/api/screen -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, screen } = require('electron/main') let mainWindow = null app.whenReady().then(() => { - // We cannot require the screen module until the app is ready. - const { screen } = require('electron') - // Create a window that fills the screen's available work area. const primaryDisplay = screen.getPrimaryDisplay() const { width, height } = primaryDisplay.workAreaSize diff --git a/docs/fiddles/system/clipboard/.keep b/docs/fiddles/system/clipboard/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/clipboard/copy/index.html b/docs/fiddles/system/clipboard/copy/index.html index 2bf063a2f516b..0b02eb7b8904b 100644 --- a/docs/fiddles/system/clipboard/copy/index.html +++ b/docs/fiddles/system/clipboard/copy/index.html @@ -2,12 +2,13 @@ +

Clipboard copy

- Supports: Win, macOS, Linux | Process: Both + Supports: Win, macOS, Linux | Process: Main, Renderer (non-sandboxed only)
@@ -17,8 +18,6 @@

Clipboard copy

+ - diff --git a/docs/fiddles/system/clipboard/copy/main.js b/docs/fiddles/system/clipboard/copy/main.js index 36ad14197f6b7..1c76f9d50acf5 100644 --- a/docs/fiddles/system/clipboard/copy/main.js +++ b/docs/fiddles/system/clipboard/copy/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, clipboard } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Clipboard copy', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -20,6 +21,18 @@ function createWindow () { }) } +ipcMain.handle('clipboard:writeText', (event, text) => { + clipboard.writeText(text) +}) + app.whenReady().then(() => { createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) diff --git a/docs/fiddles/system/clipboard/copy/preload.js b/docs/fiddles/system/clipboard/copy/preload.js new file mode 100644 index 0000000000000..580d3866576a6 --- /dev/null +++ b/docs/fiddles/system/clipboard/copy/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('clipboard', { + writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text) +}) diff --git a/docs/fiddles/system/clipboard/copy/renderer.js b/docs/fiddles/system/clipboard/copy/renderer.js index 75e204136e09a..cc2069adff95a 100644 --- a/docs/fiddles/system/clipboard/copy/renderer.js +++ b/docs/fiddles/system/clipboard/copy/renderer.js @@ -1,10 +1,8 @@ -const { clipboard } = require('electron') - const copyBtn = document.getElementById('copy-to') const copyInput = document.getElementById('copy-to-input') copyBtn.addEventListener('click', () => { if (copyInput.value !== '') copyInput.value = '' copyInput.placeholder = 'Copied! Paste here to see.' - clipboard.writeText('Electron Demo!') + window.clipboard.writeText('Electron Demo!') }) diff --git a/docs/fiddles/system/clipboard/paste/index.html b/docs/fiddles/system/clipboard/paste/index.html index 9cc2ac5ba7ce8..a7b300ea045b5 100644 --- a/docs/fiddles/system/clipboard/paste/index.html +++ b/docs/fiddles/system/clipboard/paste/index.html @@ -2,12 +2,13 @@ +

Clipboard paste

- Supports: Win, macOS, Linux | Process: Both + Supports: Win, macOS, Linux | Process: Main, Renderer (non-sandboxed only)
@@ -17,8 +18,6 @@

Clipboard paste

+ - diff --git a/docs/fiddles/system/clipboard/paste/main.js b/docs/fiddles/system/clipboard/paste/main.js index b0883e6f4e56f..58c2fbb3e88c8 100644 --- a/docs/fiddles/system/clipboard/paste/main.js +++ b/docs/fiddles/system/clipboard/paste/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, clipboard } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Clipboard paste', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -20,6 +21,22 @@ function createWindow () { }) } +ipcMain.handle('clipboard:readText', () => { + return clipboard.readText() +}) + +ipcMain.handle('clipboard:writeText', (event, text) => { + clipboard.writeText(text) +}) + app.whenReady().then(() => { createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) diff --git a/docs/fiddles/system/clipboard/paste/preload.js b/docs/fiddles/system/clipboard/paste/preload.js new file mode 100644 index 0000000000000..31ce721451d61 --- /dev/null +++ b/docs/fiddles/system/clipboard/paste/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('clipboard', { + readText: () => ipcRenderer.invoke('clipboard:readText'), + writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text) +}) diff --git a/docs/fiddles/system/clipboard/paste/renderer.js b/docs/fiddles/system/clipboard/paste/renderer.js index 27a52422cf0da..a4c75790f9385 100644 --- a/docs/fiddles/system/clipboard/paste/renderer.js +++ b/docs/fiddles/system/clipboard/paste/renderer.js @@ -1,9 +1,7 @@ -const { clipboard } = require('electron') - const pasteBtn = document.getElementById('paste-to') -pasteBtn.addEventListener('click', () => { - clipboard.writeText('What a demo!') - const message = `Clipboard contents: ${clipboard.readText()}` +pasteBtn.addEventListener('click', async () => { + await window.clipboard.writeText('What a demo!') + const message = `Clipboard contents: ${await window.clipboard.readText()}` document.getElementById('paste-from').innerHTML = message }) diff --git a/docs/fiddles/system/protocol-handler/.keep b/docs/fiddles/system/protocol-handler/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html index a3ddd1b933fc0..17e326b6cf8c5 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html @@ -16,7 +16,7 @@

App Default Protocol Demo

These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a browser asks to be your default for viewing web pages.

-

Open the full protocol API documentation in your +

Open the full protocol API documentation in your browser.

----- @@ -44,7 +44,7 @@

Demo

Packaging

This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS plist - for the app is updated to include the new protocol handler. If you're using electron-packager then you + for the app is updated to include the new protocol handler. If you're using @electron/packager then you can add the flag --extend-info with a path to the plist you've created. The one for this app is below:

diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js index 5a3b553612de3..84efd0cb9748a 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js @@ -1,15 +1,15 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron') -const path = require('path') +const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron/main') +const path = require('node:path') -let mainWindow; +let mainWindow if (process.defaultApp) { if (process.argv.length >= 2) { app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])]) } } else { - app.setAsDefaultProtocolClient('electron-fiddle') + app.setAsDefaultProtocolClient('electron-fiddle') } const gotTheLock = app.requestSingleInstanceLock() @@ -23,13 +23,15 @@ if (!gotTheLock) { if (mainWindow.isMinimized()) mainWindow.restore() mainWindow.focus() } + + dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0, -1)}`) }) // Create mainWindow, load the rest of the app, etc... app.whenReady().then(() => { createWindow() }) - + app.on('open-url', (event, url) => { dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) }) @@ -41,7 +43,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - preload: path.join(__dirname, 'preload.js'), + preload: path.join(__dirname, 'preload.js') } }) diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js index 1eebf784ad672..eda1d8c721844 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js @@ -1,11 +1,5 @@ -// All of the Node.js APIs are available in the preload process. -// It has the same sandbox as a Chrome extension. -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require('electron/renderer') -// Set up context bridge between the renderer process and the main process -contextBridge.exposeInMainWorld( - 'shell', - { - open: () => ipcRenderer.send('shell:open'), - } -) \ No newline at end of file +contextBridge.exposeInMainWorld('shell', { + open: () => ipcRenderer.send('shell:open') +}) diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js index 525f25ff2e76e..a933c04e70a88 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js @@ -4,5 +4,5 @@ // Binds the buttons to the context bridge API. document.getElementById('open-in-browser').addEventListener('click', () => { - shell.open(); -}); \ No newline at end of file + window.shell.open() +}) diff --git a/docs/fiddles/system/system-app-user-information/.keep b/docs/fiddles/system/system-app-user-information/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/system-app-user-information/app-information/index.html b/docs/fiddles/system/system-app-user-information/app-information/index.html index 18b05ae23dae6..f8b0e38c3fd13 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/index.html +++ b/docs/fiddles/system/system-app-user-information/app-information/index.html @@ -14,13 +14,10 @@

App Information

The main process app module can be used to get the path at which your app is located on the user's computer.

In this example, to get that information from the renderer process, we use the ipc module to send a message to the main process requesting the app's path.

-

See the app module documentation(opens in new window) for more.

+

See the app module documentation(opens in new window) for more.

- + - \ No newline at end of file + \ No newline at end of file diff --git a/docs/fiddles/system/system-app-user-information/app-information/main.js b/docs/fiddles/system/system-app-user-information/app-information/main.js index 64141f98e88dd..247bad8f5272c 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/main.js +++ b/docs/fiddles/system/system-app-user-information/app-information/main.js @@ -1,5 +1,34 @@ -const {app, ipcMain} = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') -ipcMain.on('get-app-path', (event) => { - event.sender.send('got-app-path', app.getAppPath()) -}) \ No newline at end of file +let mainWindow = null + +ipcMain.handle('get-app-path', (event) => app.getAppPath()) + +function createWindow () { + const windowOptions = { + width: 600, + height: 400, + title: 'Get app information', + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + } + + mainWindow = new BrowserWindow(windowOptions) + mainWindow.loadFile('index.html') + + mainWindow.on('closed', () => { + mainWindow = null + }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/system/system-app-user-information/app-information/preload.js b/docs/fiddles/system/system-app-user-information/app-information/preload.js new file mode 100644 index 0000000000000..92e3efa325035 --- /dev/null +++ b/docs/fiddles/system/system-app-user-information/app-information/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + getAppPath: () => ipcRenderer.invoke('get-app-path') +}) diff --git a/docs/fiddles/system/system-app-user-information/app-information/renderer.js b/docs/fiddles/system/system-app-user-information/app-information/renderer.js index 3f971abcab7c5..35b201bf4091e 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/renderer.js +++ b/docs/fiddles/system/system-app-user-information/app-information/renderer.js @@ -1,18 +1,7 @@ -const {ipcRenderer} = require('electron') - const appInfoBtn = document.getElementById('app-info') -const electron_doc_link = document.querySelectorAll('a[href]') - -appInfoBtn.addEventListener('click', () => { - ipcRenderer.send('get-app-path') -}) -ipcRenderer.on('got-app-path', (event, path) => { +appInfoBtn.addEventListener('click', async () => { + const path = await window.electronAPI.getAppPath() const message = `This app is located at: ${path}` document.getElementById('got-app-info').innerHTML = message }) - -electron_doc_link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) -}) \ No newline at end of file diff --git a/docs/fiddles/system/system-information/get-version-information/index.html b/docs/fiddles/system/system-information/get-version-information/index.html index b19df1f2b534b..3bd06b382ec04 100644 --- a/docs/fiddles/system/system-information/get-version-information/index.html +++ b/docs/fiddles/system/system-information/get-version-information/index.html @@ -15,12 +15,10 @@

Get version information

The process module is built into Node.js (therefore you can use this in both the main and renderer processes) and in Electron apps this object has a few more useful properties on it.

The example below gets the version of Electron in use by the app.

-

See the process documentation (opens in new window) for more.

+

See the process documentation (opens in new window) for more.

- + diff --git a/docs/fiddles/system/system-information/get-version-information/main.js b/docs/fiddles/system/system-information/get-version-information/main.js index daf87d0fda97a..e1a7434a52479 100644 --- a/docs/fiddles/system/system-information/get-version-information/main.js +++ b/docs/fiddles/system/system-information/get-version-information/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Get version information', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -18,6 +19,12 @@ function createWindow () { mainWindow.on('closed', () => { mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } app.whenReady().then(() => { diff --git a/docs/fiddles/system/system-information/get-version-information/preload.js b/docs/fiddles/system/system-information/get-version-information/preload.js new file mode 100644 index 0000000000000..fa4eab9154a8d --- /dev/null +++ b/docs/fiddles/system/system-information/get-version-information/preload.js @@ -0,0 +1,3 @@ +const { contextBridge } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronVersion', process.versions.electron) diff --git a/docs/fiddles/system/system-information/get-version-information/renderer.js b/docs/fiddles/system/system-information/get-version-information/renderer.js index 40f7f2cf2cf64..3e7c22e5c2075 100644 --- a/docs/fiddles/system/system-information/get-version-information/renderer.js +++ b/docs/fiddles/system/system-information/get-version-information/renderer.js @@ -1,8 +1,6 @@ const versionInfoBtn = document.getElementById('version-info') -const electronVersion = process.versions.electron - versionInfoBtn.addEventListener('click', () => { - const message = `This app is using Electron version: ${electronVersion}` + const message = `This app is using Electron version: ${window.electronVersion}` document.getElementById('got-version-info').innerHTML = message }) diff --git a/docs/fiddles/tutorial-first-app/main.js b/docs/fiddles/tutorial-first-app/main.js index 10d57a0696f0f..8e92734f271ee 100644 --- a/docs/fiddles/tutorial-first-app/main.js +++ b/docs/fiddles/tutorial-first-app/main.js @@ -1,26 +1,26 @@ -const { app, BrowserWindow } = require('electron'); +const { app, BrowserWindow } = require('electron/main') const createWindow = () => { const win = new BrowserWindow({ width: 800, - height: 600, - }); + height: 600 + }) - win.loadFile('index.html'); -}; + win.loadFile('index.html') +} app.whenReady().then(() => { - createWindow(); + createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); + createWindow() } - }); -}); + }) +}) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { - app.quit(); + app.quit() } -}); +}) diff --git a/docs/fiddles/tutorial-preload/main.js b/docs/fiddles/tutorial-preload/main.js index 6b7184900e6dd..f62f401355d11 100644 --- a/docs/fiddles/tutorial-preload/main.js +++ b/docs/fiddles/tutorial-preload/main.js @@ -1,30 +1,30 @@ -const { app, BrowserWindow } = require('electron'); -const path = require('path'); +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') const createWindow = () => { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { - preload: path.join(__dirname, 'preload.js'), - }, - }); + preload: path.join(__dirname, 'preload.js') + } + }) - win.loadFile('index.html'); -}; + win.loadFile('index.html') +} app.whenReady().then(() => { - createWindow(); + createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); + createWindow() } - }); -}); + }) +}) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { - app.quit(); + app.quit() } -}); +}) diff --git a/docs/fiddles/tutorial-preload/preload.js b/docs/fiddles/tutorial-preload/preload.js index e0dbdce1b8b2f..561df488dce66 100644 --- a/docs/fiddles/tutorial-preload/preload.js +++ b/docs/fiddles/tutorial-preload/preload.js @@ -1,7 +1,7 @@ -const { contextBridge } = require('electron'); +const { contextBridge } = require('electron/renderer') contextBridge.exposeInMainWorld('versions', { node: () => process.versions.node, chrome: () => process.versions.chrome, - electron: () => process.versions.electron, -}); + electron: () => process.versions.electron +}) diff --git a/docs/fiddles/tutorial-preload/renderer.js b/docs/fiddles/tutorial-preload/renderer.js index 7585229a91781..6c8c471aa3390 100644 --- a/docs/fiddles/tutorial-preload/renderer.js +++ b/docs/fiddles/tutorial-preload/renderer.js @@ -1,2 +1,2 @@ -const information = document.getElementById('info'); -information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`; +const information = document.getElementById('info') +information.innerText = `This app is using Chrome (v${window.versions.chrome()}), Node.js (v${window.versions.node()}), and Electron (v${window.versions.electron()})` diff --git a/docs/fiddles/windows/manage-windows/.keep b/docs/fiddles/windows/manage-windows/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/index.html b/docs/fiddles/windows/manage-windows/create-frameless-window/index.html deleted file mode 100644 index c83c43d636ed9..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -
-
-

Create a frameless window

- Supports: Win, macOS, Linux | Process: Main -
-

A frameless window is a window that has no "chrome", - such as toolbars, title bars, status bars, borders, etc. You can make - a browser window frameless by setting - frame to false when creating the window.

-
- -
-
-
-
- - - \ No newline at end of file diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/main.js b/docs/fiddles/windows/manage-windows/create-frameless-window/main.js deleted file mode 100644 index 05d530736a3b8..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/main.js +++ /dev/null @@ -1,22 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -ipcMain.on('create-frameless-window', (event, {url}) => { - const win = new BrowserWindow({ frame: false }) - win.loadURL(url) -}) - -function createWindow () { - const mainWindow = new BrowserWindow({ - width: 600, - height: 400, - title: 'Create a frameless window', - webPreferences: { - nodeIntegration: true - } - }) - mainWindow.loadFile('index.html') -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js b/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js deleted file mode 100644 index 21f91ad561b37..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js +++ /dev/null @@ -1,8 +0,0 @@ -const { ipcRenderer } = require('electron') - -const newWindowBtn = document.getElementById('frameless-window') - -newWindowBtn.addEventListener('click', () => { - const url = 'data:text/html,

Hello World!

Close this Window' - ipcRenderer.send('create-frameless-window', { url }) -}) diff --git a/docs/fiddles/windows/manage-windows/frameless-window/index.html b/docs/fiddles/windows/manage-windows/frameless-window/index.html index 58179e2e81ee5..69ef074f23a56 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/index.html +++ b/docs/fiddles/windows/manage-windows/frameless-window/index.html @@ -1,77 +1,73 @@ - - - - - Frameless window - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Create a frameless window

-
-
- -
-

- A frameless window is a window that has no - - "chrome" - - , such as toolbars, title bars, status bars, borders, etc. You can - make a browser window frameless by setting frame to - false when creating the window. -

- -

- Windows can have a transparent background, too. By setting the - transparent option to true, you can also - make your frameless window transparent: -

-
-var win = new BrowserWindow({
-  transparent: true,
-  frame: false
-})
- -

- For more details, see the - - Window Customization - - - documentation. -

-
-
-
- - - - + + + + + Frameless window + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Create a frameless window

+
+
+ +
+

+ A frameless window is a window that has no + + "chrome" + + , such as toolbars, title bars, status bars, borders, etc. You can + make a browser window frameless by setting frame to + false when creating the window. +

+ +

+ Windows can have a transparent background, too. By setting the + transparent option to true, you can also + make your frameless window transparent: +

+
+var win = new BrowserWindow({
+  transparent: true,
+  frame: false
+})
+ +

+ For more details, see the + + Window Customization + + + documentation. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/frameless-window/main.js b/docs/fiddles/windows/manage-windows/frameless-window/main.js index d7925cd7ff4a6..507242962ab05 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/main.js +++ b/docs/fiddles/windows/manage-windows/frameless-window/main.js @@ -1,7 +1,8 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') -ipcMain.on('create-frameless-window', (event, {url}) => { +ipcMain.on('create-frameless-window', (event, { url }) => { const win = new BrowserWindow({ frame: false }) win.loadURL(url) }) @@ -12,34 +13,38 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/frameless-window/preload.js b/docs/fiddles/windows/manage-windows/frameless-window/preload.js new file mode 100644 index 0000000000000..0feaa676755cc --- /dev/null +++ b/docs/fiddles/windows/manage-windows/frameless-window/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + createFramelessWindow: (args) => ipcRenderer.send('create-frameless-window', args) +}) diff --git a/docs/fiddles/windows/manage-windows/frameless-window/renderer.js b/docs/fiddles/windows/manage-windows/frameless-window/renderer.js index 21f91ad561b37..7638f56099f0e 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/renderer.js +++ b/docs/fiddles/windows/manage-windows/frameless-window/renderer.js @@ -1,8 +1,6 @@ -const { ipcRenderer } = require('electron') - const newWindowBtn = document.getElementById('frameless-window') newWindowBtn.addEventListener('click', () => { const url = 'data:text/html,

Hello World!

Close this Window' - ipcRenderer.send('create-frameless-window', { url }) + window.electronAPI.createFramelessWindow({ url }) }) diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/index.html b/docs/fiddles/windows/manage-windows/manage-window-state/index.html index e9e39ceccc18e..9c6236dd77d2b 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/index.html +++ b/docs/fiddles/windows/manage-windows/manage-window-state/index.html @@ -1,64 +1,60 @@ - - - - - Manage window state - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Manage window state

-
-
- - -
-

- In this demo we create a new window and listen for - move and resize events on it. Click the - demo button, change the new window and see the dimensions and - position update here, above. -

-

- There are a lot of methods for controlling the state of the window - such as the size, location, and focus status as well as events to - listen to for window changes. Visit the - - documentation (opens in new window) - - for the full list. -

-
-
-
- - - - + + + + + Manage window state + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Manage window state

+
+
+ + +
+

+ In this demo we create a new window and listen for + move and resize events on it. Click the + demo button, change the new window and see the dimensions and + position update here, above. +

+

+ There are a lot of methods for controlling the state of the window + such as the size, location, and focus status as well as events to + listen to for window changes. Visit the + + documentation (opens in new window) + + for the full list. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/main.js b/docs/fiddles/windows/manage-windows/manage-window-state/main.js index 166ff0fa62f5a..afb42233926be 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/main.js +++ b/docs/fiddles/windows/manage-windows/manage-window-state/main.js @@ -1,10 +1,11 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') ipcMain.on('create-demo-window', (event) => { const win = new BrowserWindow({ width: 400, height: 275 }) - function updateReply() { + function updateReply () { event.sender.send('bounds-changed', { size: win.getSize(), position: win.getPosition() @@ -18,38 +19,42 @@ ipcMain.on('create-demo-window', (event) => { function createWindow () { // Create the browser window. - mainWindow = new BrowserWindow({ + const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/preload.js b/docs/fiddles/windows/manage-windows/manage-window-state/preload.js new file mode 100644 index 0000000000000..d604ee529cb1e --- /dev/null +++ b/docs/fiddles/windows/manage-windows/manage-window-state/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + createDemoWindow: () => ipcRenderer.send('create-demo-window'), + onBoundsChanged: (callback) => ipcRenderer.on('bounds-changed', () => callback()) +}) diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js b/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js index 7b1aa8ae23b11..c152fd5ae1e90 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js +++ b/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js @@ -1,25 +1,11 @@ -const { shell, ipcRenderer } = require('electron') - const manageWindowBtn = document.getElementById('manage-window') -const links = document.querySelectorAll('a[href]') - -ipcRenderer.on('bounds-changed', (event, bounds) => { +window.electronAPI.onBoundsChanged((event, bounds) => { const manageWindowReply = document.getElementById('manage-window-reply') const message = `Size: ${bounds.size} Position: ${bounds.position}` manageWindowReply.textContent = message }) manageWindowBtn.addEventListener('click', (event) => { - ipcRenderer.send('create-demo-window') -}) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } + window.electronAPI.createDemoWindow() }) diff --git a/docs/fiddles/windows/manage-windows/new-window/index.html b/docs/fiddles/windows/manage-windows/new-window/index.html index 08fbcab03c943..3cd5df4a17966 100644 --- a/docs/fiddles/windows/manage-windows/new-window/index.html +++ b/docs/fiddles/windows/manage-windows/new-window/index.html @@ -8,18 +8,15 @@

Create a new window

Supports: Win, macOS, Linux | Process: Main

The BrowserWindow module gives you the ability to create new windows in your app.

-

There are a lot of options when creating a new window. A few are in this demo, but visit the documentation(opens in new window) -

-

ProTip

- Use an invisible browser window to run background tasks. -

You can set a new browser window to not be shown (be invisible) in order to use that additional renderer process as a kind of new thread in which to run JavaScript in the background of your app. You do this by setting the show property to false when defining the new window.

-
var win = new BrowserWindow({
+  

There are a lot of options when creating a new window. A few are in this demo, but visit the documentation(opens in new window) +

+

ProTip

+ Use an invisible browser window to run background tasks. +

You can set a new browser window to not be shown (be invisible) in order to use that additional renderer process as a kind of new thread in which to run JavaScript in the background of your app. You do this by setting the show property to false when defining the new window.

+
var win = new BrowserWindow({
   width: 400, height: 225, show: false
 })
-
- +
+ diff --git a/docs/fiddles/windows/manage-windows/new-window/main.js b/docs/fiddles/windows/manage-windows/new-window/main.js index 2e51387e37aca..109055ac80b0e 100644 --- a/docs/fiddles/windows/manage-windows/new-window/main.js +++ b/docs/fiddles/windows/manage-windows/new-window/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') ipcMain.on('new-window', (event, { url, width, height }) => { const win = new BrowserWindow({ width, height }) @@ -12,34 +13,38 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/new-window/preload.js b/docs/fiddles/windows/manage-windows/new-window/preload.js new file mode 100644 index 0000000000000..53019d908fb73 --- /dev/null +++ b/docs/fiddles/windows/manage-windows/new-window/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + newWindow: (args) => ipcRenderer.send('new-window', args) +}) diff --git a/docs/fiddles/windows/manage-windows/new-window/renderer.js b/docs/fiddles/windows/manage-windows/new-window/renderer.js index ccb8b22643296..22caea84a3153 100644 --- a/docs/fiddles/windows/manage-windows/new-window/renderer.js +++ b/docs/fiddles/windows/manage-windows/new-window/renderer.js @@ -1,14 +1,6 @@ -const { shell, ipcRenderer } = require('electron') - const newWindowBtn = document.getElementById('new-window') -const link = document.getElementById('browser-window-link') newWindowBtn.addEventListener('click', (event) => { const url = 'https://electronjs.org' - ipcRenderer.send('new-window', { url, width: 400, height: 320 }); -}) - -link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal("https://electronjs.org/docs/api/browser-window") + window.electronAPI.newWindow({ url, width: 400, height: 320 }) }) diff --git a/docs/fiddles/windows/manage-windows/window-events/index.html b/docs/fiddles/windows/manage-windows/window-events/index.html index d244bf167506c..5c05a3c9a2e76 100644 --- a/docs/fiddles/windows/manage-windows/window-events/index.html +++ b/docs/fiddles/windows/manage-windows/window-events/index.html @@ -1,58 +1,54 @@ - - - - - Window events - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Window events

-
-
- - -
-

- In this demo, we create a new window and listen for - blur event on it. Click the demo button to create a new - modal window, and switch focus back to the parent window by clicking - on it. You can click the Focus on Demo button to switch focus - to the modal window again. -

-
-
-
- - - - + + + + + Window events + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Window events

+
+
+ + +
+

+ In this demo, we create a new window and listen for + blur event on it. Click the demo button to create a new + modal window, and switch focus back to the parent window by clicking + on it. You can click the Focus on Demo button to switch focus + to the modal window again. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/window-events/main.js b/docs/fiddles/windows/manage-windows/window-events/main.js index 3effec304fc4f..5f10651d240a6 100644 --- a/docs/fiddles/windows/manage-windows/window-events/main.js +++ b/docs/fiddles/windows/manage-windows/window-events/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') function createWindow () { // Create the browser window. @@ -7,13 +8,19 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) + let demoWindow ipcMain.on('show-demo-window', () => { if (demoWindow) { @@ -23,6 +30,7 @@ function createWindow () { demoWindow = new BrowserWindow({ width: 600, height: 400 }) demoWindow.loadURL('https://electronjs.org') demoWindow.on('close', () => { + demoWindow = undefined mainWindow.webContents.send('window-close') }) demoWindow.on('focus', () => { @@ -41,23 +49,21 @@ function createWindow () { // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/window-events/preload.js b/docs/fiddles/windows/manage-windows/window-events/preload.js new file mode 100644 index 0000000000000..b33f860a6446e --- /dev/null +++ b/docs/fiddles/windows/manage-windows/window-events/preload.js @@ -0,0 +1,9 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + showDemoWindow: () => ipcRenderer.send('show-demo-window'), + focusDemoWindow: () => ipcRenderer.send('focus-demo-window'), + onWindowFocus: (callback) => ipcRenderer.on('window-focus', () => callback()), + onWindowBlur: (callback) => ipcRenderer.on('window-blur', () => callback()), + onWindowClose: (callback) => ipcRenderer.on('window-close', () => callback()) +}) diff --git a/docs/fiddles/windows/manage-windows/window-events/renderer.js b/docs/fiddles/windows/manage-windows/window-events/renderer.js index 575d283a615a3..814605ecbe295 100644 --- a/docs/fiddles/windows/manage-windows/window-events/renderer.js +++ b/docs/fiddles/windows/manage-windows/window-events/renderer.js @@ -1,5 +1,3 @@ -const { shell, ipcRenderer } = require('electron') - const listenToWindowBtn = document.getElementById('listen-to-window') const focusModalBtn = document.getElementById('focus-on-modal-window') @@ -15,25 +13,13 @@ const showFocusBtn = (btn) => { focusModalBtn.addEventListener('click', focusWindow) } const focusWindow = () => { - ipcRenderer.send('focus-demo-window') + window.electronAPI.focusDemoWindow() } -ipcRenderer.on('window-focus', hideFocusBtn) -ipcRenderer.on('window-close', hideFocusBtn) -ipcRenderer.on('window-blur', showFocusBtn) +window.electronAPI.onWindowFocus(hideFocusBtn) +window.electronAPI.onWindowClose(hideFocusBtn) +window.electronAPI.onWindowBlur(showFocusBtn) listenToWindowBtn.addEventListener('click', () => { - ipcRenderer.send('show-demo-window') -}) - -const links = document.querySelectorAll('a[href]') - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } + window.electronAPI.showDemoWindow() }) diff --git a/docs/glossary.md b/docs/glossary.md index 893c598c52b80..b917ed0d7b609 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -4,7 +4,7 @@ This page defines some terminology that is commonly used in Electron development ### ASAR -ASAR stands for Atom Shell Archive Format. An [asar] archive is a simple +ASAR stands for Atom Shell Archive Format. An [asar][] archive is a simple `tar`-like format that concatenates files into a single file. Electron can read arbitrary files from it without unpacking the whole file. @@ -20,7 +20,7 @@ macOS implement their own version of code signing. As a desktop app developer, it's important that you sign your code if you plan on distributing it to the general public. -For more information, read the [Code Signing] tutorial. +For more information, read the [Code Signing][] tutorial. ### context isolation @@ -30,7 +30,7 @@ contents in your renderer process. With context isolation enabled, the only way to expose APIs from your preload script is through the `contextBridge` API. -For more information, read the [Context Isolation] tutorial. +For more information, read the [Context Isolation][] tutorial. See also: [preload script](#preload-script), [renderer process](#renderer-process) @@ -83,7 +83,7 @@ See also: [process](#process), [renderer process](#renderer-process) ### MAS Acronym for Apple's Mac App Store. For details on submitting your app to the -MAS, see the [Mac App Store Submission Guide]. +MAS, see the [Mac App Store Submission Guide][]. ### Mojo @@ -105,7 +105,7 @@ More information can be found in [Microsoft's documentation][msi]. ### native modules -Native modules (also called [addons] in +Native modules (also called [addons][] in Node.js) are modules written in C or C++ that can be loaded into Node.js or Electron using the require() function, and used as if they were an ordinary Node.js module. They are used primarily to provide an interface @@ -116,7 +116,7 @@ likely to use a different V8 version from the Node binary installed in your system, you have to manually specify the location of Electron’s headers when building native modules. -For more information, read the [Native Node Modules] tutorial. +For more information, read the [Native Node Modules][] tutorial. ### notarization @@ -132,7 +132,7 @@ OSR (offscreen rendering) can be used for loading heavy page in background and then displaying it after (it will be much faster). It allows you to render page without showing it on screen. -For more information, read the [Offscreen Rendering][osr] tutorial. +For more information, read the [Offscreen Rendering][] tutorial. ### preload script @@ -146,7 +146,7 @@ See also: [renderer process](#renderer-process), [context isolation](#context-is ### process A process is an instance of a computer program that is being executed. Electron -apps that make use of the [main] and one or many [renderer] process are +apps that make use of the [main][] and one or many [renderer][] process are actually running several programs simultaneously. In Node.js and Electron, each running process has a `process` object. This @@ -169,14 +169,14 @@ See also: [process](#process), [main process](#main-process) The sandbox is a security feature inherited from Chromium that restricts your renderer processes to a limited set of permissions. -For more information, read the [Process Sandboxing] tutorial. +For more information, read the [Process Sandboxing][] tutorial. See also: [process](#process) ### Squirrel Squirrel is an open-source framework that enables Electron apps to update -automatically as new versions are released. See the [autoUpdater] API for +automatically as new versions are released. See the [autoUpdater][] API for info about getting started with Squirrel. ### userland @@ -194,6 +194,15 @@ overly prescriptive about how it should be used. Userland enables users to create and share tools that provide additional functionality on top of what is available in "core". +### utility process + +The utility process is a child of the main process that allows running any +untrusted services that cannot be run in the main process. Chromium uses this +process to perform network I/O, audio/video processing, device inputs etc. +In Electron, you can create this process using [UtilityProcess][] API. + +See also: [process](#process), [main process](#main-process) + ### V8 V8 is Google's open source JavaScript engine. It is written in C++ and is @@ -225,10 +234,9 @@ embedded content. [context isolation]: tutorial/context-isolation.md [mac app store submission guide]: tutorial/mac-app-store-submission-guide.md [main]: #main-process -[msi]: https://docs.microsoft.com/en-us/windows/win32/msi/windows-installer-portal +[msi]: https://learn.microsoft.com/en-us/windows/win32/msi/windows-installer-portal +[Native Node Modules]: tutorial/using-native-node-modules.md [offscreen rendering]: tutorial/offscreen-rendering.md [process sandboxing]: tutorial/sandbox.md [renderer]: #renderer-process -[userland]: #userland -[using native node modules]: tutorial/using-native-node-modules.md -[v8]: #v8 +[UtilityProcess]: api/utility-process.md diff --git a/docs/images/frameless-window.png b/docs/images/frameless-window.png new file mode 100644 index 0000000000000..586242c19bde1 Binary files /dev/null and b/docs/images/frameless-window.png differ diff --git a/docs/images/gatekeeper.png b/docs/images/gatekeeper.png index 22567135b7da1..ee5e22d63043c 100644 Binary files a/docs/images/gatekeeper.png and b/docs/images/gatekeeper.png differ diff --git a/docs/images/notification-main.png b/docs/images/notification-main.png deleted file mode 100644 index 221c7230e3eb6..0000000000000 Binary files a/docs/images/notification-main.png and /dev/null differ diff --git a/docs/images/notification-renderer.png b/docs/images/notification-renderer.png deleted file mode 100644 index e66bc96abd7fb..0000000000000 Binary files a/docs/images/notification-renderer.png and /dev/null differ diff --git a/docs/images/transparent-window-mission-control.png b/docs/images/transparent-window-mission-control.png new file mode 100644 index 0000000000000..444d87ddb4202 Binary files /dev/null and b/docs/images/transparent-window-mission-control.png differ diff --git a/docs/images/transparent-window.png b/docs/images/transparent-window.png new file mode 100644 index 0000000000000..8d5e51708177c Binary files /dev/null and b/docs/images/transparent-window.png differ diff --git a/docs/images/web-contents-text-selection-after.png b/docs/images/web-contents-text-selection-after.png new file mode 100644 index 0000000000000..6e57ce8ae0386 Binary files /dev/null and b/docs/images/web-contents-text-selection-after.png differ diff --git a/docs/images/web-contents-text-selection-before.png b/docs/images/web-contents-text-selection-before.png new file mode 100644 index 0000000000000..3609d4b629a94 Binary files /dev/null and b/docs/images/web-contents-text-selection-before.png differ diff --git a/docs/styleguide.md b/docs/styleguide.md index 92a5c1ccf7333..18e5ebb98631c 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -113,13 +113,13 @@ Using `autoUpdater` as an example: * [Instance Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods) must be listed under an `### Instance Methods` chapter. * All methods that have a return value must start their description with - "Returns `[TYPE]` - [Return description]" + "Returns `[TYPE]` - \[Return description]" * If the method returns an `Object`, its structure can be specified using a colon followed by a newline then an unordered list of properties in the same style as function parameters. * Instance Events must be listed under an `### Instance Events` chapter. * Instance Properties must be listed under an `### Instance Properties` chapter. - * Instance Properties must start with "A [Property Type] ..." + * Instance Properties must start with "A \[Property Type] ..." Using the `Session` and `Cookies` classes as an example: @@ -250,6 +250,157 @@ The properties chapter must be in following form: The heading can be `###` or `####`-levels depending on whether the property belongs to a module or a class. +## API History + +An "API History" block is a YAML code block encapsulated by an HTML comment that +should be placed directly after the Markdown header for a class or method, like so: + +`````markdown +#### `win.setTrafficLightPosition(position)` _macOS_ + + + +* `position` [Point](structures/point.md) + +Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`. +````` + +It should adhere to the API History [JSON Schema](https://json-schema.org/) +(`api-history.schema.json`) which you can find in the `docs` folder. +The [API History Schema RFC][api-history-schema-rfc] includes example usage and detailed +explanations for each aspect of the schema. + +The purpose of the API History block is to describe when/where/how/why an API was: + +* Added +* Changed (usually breaking changes) +* Deprecated + +Each API change listed in the block should include a link to the +PR where that change was made along with an optional short description of the +change. If applicable, include the [heading id](https://gist.github.com/asabaylus/3071099) +for that change from the [breaking changes documentation](./breaking-changes.md). + +The [API History linting script][api-history-linting-script] (`lint:api-history`) +validates API History blocks in the Electron documentation against the schema and +performs some other checks. You can look at its [tests][api-history-tests] for more +details. + +There are a few style guidelines that aren't covered by the linting script: + +### Format + +Always adhere to this format: + + ```markdown + API HEADER | #### `win.flashFrame(flag)` + BLANK LINE | + HTML COMMENT OPENING TAG | + BLANK LINE | + ``` + +### YAML + +* Use two spaces for indentation. +* Do not use comments. + +### Descriptions + +* Always wrap descriptions with double quotation marks (i.e. "example"). + * [Certain special characters (e.g. `[`, `]`) can break YAML parsing](https:/stackoverflow.com/a/37015689/19020549). +* Describe the change in a way relevant to app developers and make it + capitalized, punctuated, and past tense. + * Refer to [Clerk](https://github.com/electron/clerk/blob/main/README.md#examples) + for examples. +* Keep descriptions concise. + * Ideally, a description will match its corresponding header in the + breaking changes document. + * Favor using the release notes from the associated PR whenever possible. + * Developers can always view the breaking changes document or linked + pull request for more details. + +### Placement + +Generally, you should place the API History block directly after the Markdown header +for a class or method that was changed. However, there are some instances where this +is ambiguous: + +#### Chromium bump + +* [chore: bump chromium to 122.0.6194.0 (main)](https://github.com/electron/electron/pull/40750) + * [Behavior Changed: cross-origin iframes now use Permission Policy to access features][api-history-cross-origin] + +Sometimes a breaking change doesn't relate to any of the existing APIs. In this +case, it is ok not to add API History anywhere. + +#### Change affecting multiple APIs + +* [refactor: ensure IpcRenderer is not bridgable](https://github.com/electron/electron/pull/40330) + * [Behavior Changed: ipcRenderer can no longer be sent over the contextBridge][api-history-ipc-renderer] + +Sometimes a breaking change involves multiple APIs. In this case, place the +API History block under the top-level Markdown header for each of the +involved APIs. + +`````markdown +# contextBridge + + + +> Create a safe, bi-directional, synchronous bridge across isolated contexts +````` + +`````markdown +# ipcRenderer + + + +Process: [Renderer](../glossary.md#renderer-process) +````` + +Notice how an API History block wasn't added under: + +* `contextBridge.exposeInMainWorld(apiKey, api)` + +since that function wasn't changed, only how it may be used: + +```patch + contextBridge.exposeInMainWorld('app', { +- ipcRenderer, ++ onEvent: (cb) => ipcRenderer.on('foo', (e, ...args) => cb(args)) + }) +``` + ## Documentation translations See [electron/i18n](https://github.com/electron/i18n#readme) @@ -257,3 +408,8 @@ See [electron/i18n](https://github.com/electron/i18n#readme) [title-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case [sentence-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case [markdownlint]: https://github.com/DavidAnson/markdownlint +[api-history-schema-rfc]: https://github.com/electron/rfcs/blob/f36e0a8483e1ea844710890a8a7a1bd58ecbac05/text/0004-api-history-schema.md +[api-history-linting-script]: https://github.com/electron/lint-roller/blob/3030970136ec6b41028ef973f944d3e5cad68e1c/bin/lint-markdown-api-history.ts +[api-history-tests]: https://github.com/electron/lint-roller/blob/main/tests/lint-roller-markdown-api-history.spec.ts +[api-history-cross-origin]: https://github.com/electron/electron/blob/f508f6b6b570481a2b61d8c4f8c1951f492e4309/docs/breaking-changes.md#behavior-changed-cross-origin-iframes-now-use-permission-policy-to-access-features +[api-history-ipc-renderer]: https://github.com/electron/electron/blob/f508f6b6b570481a2b61d8c4f8c1951f492e4309/docs/breaking-changes.md#behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge diff --git a/docs/tutorial/accessibility.md b/docs/tutorial/accessibility.md index 31f0b83fef631..45c13cdc92bd6 100644 --- a/docs/tutorial/accessibility.md +++ b/docs/tutorial/accessibility.md @@ -28,6 +28,8 @@ On macOS, third-party assistive technology can toggle accessibility features ins Electron applications by setting the `AXManualAccessibility` attribute programmatically: +Using Objective-C: + ```objc CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility"); @@ -43,7 +45,16 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility"); } ``` +Using Swift: + +```swift +import Cocoa +let name = CommandLine.arguments.count >= 2 ? CommandLine.arguments[1] : "Electron" +let pid = NSWorkspace.shared.runningApplications.first(where: {$0.localizedName == name})!.processIdentifier +let axApp = AXUIElementCreateApplication(pid) +let result = AXUIElementSetAttributeValue(axApp, "AXManualAccessibility" as CFString, true as CFTypeRef) +print("Setting 'AXManualAccessibility' \(error.rawValue == 0 ? "succeeded" : "failed")") +``` + [a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology -[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools -[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules [setAccessibilitySupportEnabled]: ../api/app.md#appsetaccessibilitysupportenabledenabled-macos-windows diff --git a/docs/tutorial/application-debugging.md b/docs/tutorial/application-debugging.md index a89b0ea4b07ae..1de789c249015 100644 --- a/docs/tutorial/application-debugging.md +++ b/docs/tutorial/application-debugging.md @@ -12,7 +12,7 @@ including instances of `BrowserWindow`, `BrowserView`, and `WebView`. You can open them programmatically by calling the `openDevTools()` API on the `webContents` of the instance: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -26,8 +26,8 @@ of the most powerful utilities in any Electron Developer's tool belt. ## Main Process Debugging the main process is a bit trickier, since you cannot open -developer tools for them. The Chromium Developer Tools can [be used -to debug Electron's main process][node-inspect] thanks to a closer collaboration +developer tools for them. The Chromium Developer Tools can +[be used to debug Electron's main process][node-inspect] thanks to a closer collaboration between Google / Chrome and Node.js, but you might encounter oddities like `require` not being present in the console. diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index 1b17541f2b3f5..734aad1cd961d 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -11,8 +11,8 @@ can either use specialized tooling or manual approaches. ## With tooling There are a couple tools out there that exist to package and distribute your Electron app. -We recommend using [Electron Forge](https://www.electronforge.io). You can check out -its documentation directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md) +We recommend using [Electron Forge](./forge-overview.md). You can check out +its [documentation](https://www.electronforge.io) directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md) part of the Electron tutorial. ## Manual packaging @@ -24,8 +24,8 @@ If you prefer the manual approach, there are 2 ways to distribute your applicati ### With prebuilt binaries -To distribute your app manually, you need to download Electron's [prebuilt -binaries](https://github.com/electron/electron/releases). Next, the folder +To distribute your app manually, you need to download Electron's +[prebuilt binaries](https://github.com/electron/electron/releases). Next, the folder containing your app should be named `app` and placed in Electron's resources directory as shown in the following examples. @@ -55,7 +55,7 @@ will then be your distribution to deliver to users. ### With an app source code archive (asar) Instead of shipping your app by copying all of its source files, you can -package your app into an [asar] archive to improve the performance of reading +package your app into an [asar][] archive to improve the performance of reading files on platforms like Windows, if you are not already using a bundler such as Parcel or Webpack. diff --git a/docs/tutorial/asar-archives.md b/docs/tutorial/asar-archives.md new file mode 100644 index 0000000000000..7752d8fbe2c70 --- /dev/null +++ b/docs/tutorial/asar-archives.md @@ -0,0 +1,174 @@ +--- +title: ASAR Archives +description: What is ASAR archive and how does it affect the application. +slug: asar-archives +hide_title: false +--- + +After creating an [application distribution](application-distribution.md), the +app's source code are usually bundled into an [ASAR archive](https://github.com/electron/asar), +which is a simple extensive archive format designed for Electron apps. By bundling the app +we can mitigate issues around long path names on Windows, speed up `require` and conceal your source +code from cursory inspection. + +The bundled app runs in a virtual file system and most APIs would just work +normally, but for some cases you might want to work on ASAR archives explicitly +due to a few caveats. + +## Using ASAR Archives + +In Electron there are two sets of APIs: Node APIs provided by Node.js and Web +APIs provided by Chromium. Both APIs support reading files from ASAR archives. + +### Node API + +With special patches in Electron, Node APIs like `fs.readFile` and `require` +treat ASAR archives as virtual directories, and the files in it as normal +files in the filesystem. + +For example, suppose we have an `example.asar` archive under `/path/to`: + +```sh +$ asar list /path/to/example.asar +/app.js +/file.txt +/dir/module.js +/static/index.html +/static/main.css +/static/jquery.min.js +``` + +Read a file in the ASAR archive: + +```js +const fs = require('node:fs') +fs.readFileSync('/path/to/example.asar/file.txt') +``` + +List all files under the root of the archive: + +```js +const fs = require('node:fs') +fs.readdirSync('/path/to/example.asar') +``` + +Use a module from the archive: + +```js @ts-nocheck +require('./path/to/example.asar/dir/module.js') +``` + +You can also display a web page in an ASAR archive with `BrowserWindow`: + +```js +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() + +win.loadURL('file:///path/to/example.asar/static/index.html') +``` + +### Web API + +In a web page, files in an archive can be requested with the `file:` protocol. +Like the Node API, ASAR archives are treated as directories. + +For example, to get a file with `$.get`: + +```html + +``` + +### Treating an ASAR archive as a Normal File + +For some cases like verifying the ASAR archive's checksum, we need to read the +content of an ASAR archive as a file. For this purpose you can use the built-in +`original-fs` module which provides original `fs` APIs without `asar` support: + +```js +const originalFs = require('original-fs') +originalFs.readFileSync('/path/to/example.asar') +``` + +You can also set `process.noAsar` to `true` to disable the support for `asar` in +the `fs` module: + +```js +const fs = require('node:fs') +process.noAsar = true +fs.readFileSync('/path/to/example.asar') +``` + +## Limitations of the Node API + +Even though we tried hard to make ASAR archives in the Node API work like +directories as much as possible, there are still limitations due to the +low-level nature of the Node API. + +### Archives Are Read-only + +The archives can not be modified so all Node APIs that can modify files will not +work with ASAR archives. + +### Working Directory Can Not Be Set to Directories in Archive + +Though ASAR archives are treated as directories, there are no actual +directories in the filesystem, so you can never set the working directory to +directories in ASAR archives. Passing them as the `cwd` option of some APIs +will also cause errors. + +### Extra Unpacking on Some APIs + +Most `fs` APIs can read a file or get a file's information from ASAR archives +without unpacking, but for some APIs that rely on passing the real file path to +underlying system calls, Electron will extract the needed file into a +temporary file and pass the path of the temporary file to the APIs to make them +work. This adds a little overhead for those APIs. + +APIs that requires extra unpacking are: + +* `child_process.execFile` +* `child_process.execFileSync` +* `fs.open` +* `fs.openSync` +* `process.dlopen` - Used by `require` on native modules + +### Fake Stat Information of `fs.stat` + +The `Stats` object returned by `fs.stat` and its friends on files in `asar` +archives is generated by guessing, because those files do not exist on the +filesystem. So you should not trust the `Stats` object except for getting file +size and checking file type. + +### Executing Binaries Inside ASAR archive + +There are Node APIs that can execute binaries like `child_process.exec`, +`child_process.spawn` and `child_process.execFile`, but only `execFile` is +supported to execute binaries inside ASAR archive. + +This is because `exec` and `spawn` accept `command` instead of `file` as input, +and `command`s are executed under shell. There is no reliable way to determine +whether a command uses a file in asar archive, and even if we do, we can not be +sure whether we can replace the path in command without side effects. + +## Adding Unpacked Files to ASAR archives + +As stated above, some Node APIs will unpack the file to the filesystem when +called. Apart from the performance issues, various anti-virus scanners might +be triggered by this behavior. + +As a workaround, you can leave various files unpacked using the `--unpack` option. +In the following example, shared libraries of native Node.js modules will not be +packed: + +```sh +$ asar pack app app.asar --unpack *.node +``` + +After running the command, you will notice that a folder named `app.asar.unpacked` +was created together with the `app.asar` file. It contains the unpacked files +and should be shipped together with the `app.asar` archive. diff --git a/docs/tutorial/asar-integrity.md b/docs/tutorial/asar-integrity.md new file mode 100644 index 0000000000000..fd3c8ba25244f --- /dev/null +++ b/docs/tutorial/asar-integrity.md @@ -0,0 +1,133 @@ +--- +title: 'ASAR Integrity' +description: 'An experimental feature that ensures the validity of ASAR contents at runtime.' +slug: asar-integrity +hide_title: false +--- + +ASAR integrity is an experimental feature that validates the contents of your app's +[ASAR archives](./asar-archives.md) at runtime. + +## Version support + +Currently, ASAR integrity checking is supported on: + +* macOS as of `electron>=16.0.0` +* Windows as of `electron>=30.0.0` + +In order to enable ASAR integrity checking, you also need to ensure that your `app.asar` file +was generated by a version of the `@electron/asar` npm package that supports ASAR integrity. + +Support was introduced in `asar@3.1.0`. Note that this package has since migrated over to `@electron/asar`. +All versions of `@electron/asar` support ASAR integrity. + +## How it works + +Each ASAR archive contains a JSON string header. The header format includes an `integrity` object +that contain a hex encoded hash of the entire archive as well as an array of hex encoded hashes for each +block of `blockSize` bytes. + +```json +{ + "algorithm": "SHA256", + "hash": "...", + "blockSize": 1024, + "blocks": ["...", "..."] +} +``` + +Separately, you need to define a hex encoded hash of the entire ASAR header when packaging your Electron app. + +When ASAR integrity is enabled, your Electron app will verify the header hash of the ASAR archive on runtime. +If no hash is present or if there is a mismatch in the hashes, the app will forcefully terminate. + +## Enabling ASAR integrity in the binary + +ASAR integrity checking is currently disabled by default in Electron and can +be enabled on build time by toggling the `EnableEmbeddedAsarIntegrityValidation` +[Electron fuse](fuses.md). + +When enabling this fuse, you typically also want to enable the `onlyLoadAppFromAsar` fuse. +Otherwise, the validity checking can be bypassed via the Electron app code search path. + +```js @ts-nocheck +const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses') + +flipFuses( + // E.g. /a/b/Foo.app + pathToPackagedApp, + { + version: FuseVersion.V1, + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, + [FuseV1Options.OnlyLoadAppFromAsar]: true + } +) +``` + +:::tip Fuses in Electron Forge + +With Electron Forge, you can configure your app's fuses with +[@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses) +in your Forge configuration file. + +::: + +## Providing the header hash + +ASAR integrity validates the contents of the ASAR archive against the header hash that you provide +on package time. The process of providing this packaged hash is different for macOS and Windows. + +### Using Electron tooling + +Electron Forge and Electron Packager do this setup automatically for you with no additional +configuration. The minimum required versions for ASAR integrity are: + +* `@electron/packager@18.3.1` +* `@electron/forge@7.4.0` + +### Using other build systems + +#### macOS + +When packaging for macOS, you must populate a valid `ElectronAsarIntegrity` dictionary block +in your packaged app's `Info.plist`. An example is included below. + +```xml title='Info.plist' +ElectronAsarIntegrity + + Resources/app.asar + + algorithm + SHA256 + hash + 9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac + + +``` + +Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of the ASAR header using the given algorithm. +The `@electron/asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value +(e.g. using the [`node:crypto`](https://nodejs.org/api/crypto.html) module). + +### Windows + +When packaging for Windows, you must populate a valid [resource](https://learn.microsoft.com/en-us/windows/win32/menurc/resources) +entry of type `Integrity` and name `ElectronAsar`. The value of this resource should be a JSON encoded dictionary +in the form included below: + +```json +[ + { + "file": "resources\\app.asar", + "alg": "sha256", + "value": "9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac" + } +] +``` + +:::info + +For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts) +in the Electron Packager code. + +::: diff --git a/docs/tutorial/automated-testing.md b/docs/tutorial/automated-testing.md index 56ad8282eed4b..d2c565278c53a 100644 --- a/docs/tutorial/automated-testing.md +++ b/docs/tutorial/automated-testing.md @@ -22,34 +22,101 @@ There are a few ways that you can set up testing using WebDriver. Node.js package for testing with WebDriver. Its ecosystem also includes various plugins (e.g. reporter and services) that can help you put together your test setup. -#### Install the testrunner +If you already have an existing WebdriverIO setup, it is recommended to update your dependencies and validate your existing configuration with how it is [outlined in the docs](https://webdriver.io/docs/desktop-testing/electron#configuration). -First you need to run the WebdriverIO starter toolkit in your project root directory: +#### Install the test runner + +If you don't use WebdriverIO in your project yet, you can add it by running the starter toolkit in your project root directory: ```sh npm2yarn -npx wdio . --yes +npm init wdio@latest ./ ``` -This installs all necessary packages for you and generates a `wdio.conf.js` configuration file. +This starts a configuration wizard that helps you put together the right setup, installs all necessary packages, and generates a `wdio.conf.js` configuration file. Make sure to select _"Desktop Testing - of Electron Applications"_ on one of the first questions asking _"What type of testing would you like to do?"_. #### Connect WDIO to your Electron app -Update the capabilities in your configuration file to point to your Electron app binary: +After running the configuration wizard, your `wdio.conf.js` should include roughly the following content: -```javascript title='wdio.conf.js' -export.config = { +```js title='wdio.conf.js' @ts-nocheck +export const config = { // ... + services: ['electron'], capabilities: [{ - browserName: 'chrome', - 'goog:chromeOptions': { - binary: '/path/to/your/electron/binary', // Path to your Electron binary. - args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/ + browserName: 'electron', + 'wdio:electronServiceOptions': { + // WebdriverIO can automatically find your bundled application + // if you use Electron Forge or electron-builder, otherwise you + // can define it here, e.g.: + // appBinaryPath: './path/to/bundled/application.exe', + appArgs: ['foo', 'bar=baz'] } }] // ... } ``` +#### Write your tests + +Use the [WebdriverIO API](https://webdriver.io/docs/api) to interact with elements on the screen. The framework provides custom "matchers" that make asserting the state of your application easy, e.g.: + +```js @ts-nocheck +import { browser, $, expect } from '@wdio/globals' + +describe('keyboard input', () => { + it('should detect keyboard input', async () => { + await browser.keys(['y', 'o']) + await expect($('keypress-count')).toHaveText('YO') + }) +}) +``` + +Furthermore, WebdriverIO allows you to access Electron APIs to get static information about your application: + +```js @ts-nocheck +import { browser, $, expect } from '@wdio/globals' + +describe('when the make smaller button is clicked', () => { + it('should decrease the window height and width by 10 pixels', async () => { + const boundsBefore = await browser.electron.browserWindow('getBounds') + expect(boundsBefore.width).toEqual(210) + expect(boundsBefore.height).toEqual(310) + + await $('.make-smaller').click() + const boundsAfter = await browser.electron.browserWindow('getBounds') + expect(boundsAfter.width).toEqual(200) + expect(boundsAfter.height).toEqual(300) + }) +}) +``` + +or to retrieve other Electron process information: + +```js @ts-nocheck +import fs from 'node:fs' +import path from 'node:path' +import { browser, expect } from '@wdio/globals' + +const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), { encoding: 'utf-8' })) +const { name, version } = packageJson + +describe('electron APIs', () => { + it('should retrieve app metadata through the electron API', async () => { + const appName = await browser.electron.app('getName') + expect(appName).toEqual(name) + const appVersion = await browser.electron.app('getVersion') + expect(appVersion).toEqual(version) + }) + + it('should pass args through to the launched application', async () => { + // custom args are set in the wdio.conf.js file as they need to be set before WDIO starts + const argv = await browser.electron.mainProcess('argv') + expect(argv).toContain('--foo') + expect(argv).toContain('--bar=baz') + }) +}) +``` + #### Run your tests To run your tests: @@ -58,6 +125,12 @@ To run your tests: $ npx wdio run wdio.conf.js ``` +WebdriverIO helps launch and shut down the application for you. + +#### More documentation + +Find more documentation on Mocking Electron APIs and other useful resources in the [official WebdriverIO documentation](https://webdriver.io/docs/desktop-testing/electron). + ### With Selenium [Selenium](https://www.selenium.dev/) is a web automation framework that @@ -90,7 +163,7 @@ Usage of `selenium-webdriver` with Electron is the same as with normal websites, except that you have to manually specify how to connect ChromeDriver and where to find the binary of your Electron app: -```js title='test.js' +```js title='test.js' @ts-expect-error=[1] const webdriver = require('selenium-webdriver') const driver = new webdriver.Builder() // The "9515" is the port opened by ChromeDriver. @@ -103,7 +176,7 @@ const driver = new webdriver.Builder() }) .forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0 .build() -driver.get('http://www.google.com') +driver.get('https://www.google.com') driver.findElement(webdriver.By.name('q')).sendKeys('webdriver') driver.findElement(webdriver.By.name('btnG')).click() driver.wait(() => { @@ -117,47 +190,33 @@ driver.quit() ## Using Playwright [Microsoft Playwright](https://playwright.dev) is an end-to-end testing framework built -using browser-specific remote debugging protocols, similar to the [Puppeteer] headless +using browser-specific remote debugging protocols, similar to the [Puppeteer][] headless Node.js API but geared towards end-to-end testing. Playwright has experimental Electron -support via Electron's support for the [Chrome DevTools Protocol] (CDP). +support via Electron's support for the [Chrome DevTools Protocol][] (CDP). ### Install dependencies -You can install Playwright through your preferred Node.js package manager. The Playwright team -recommends using the `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` environment variable to avoid -unnecessary browser downloads when testing an Electron app. - -```sh npm2yarn -PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright -``` - -Playwright also comes with its own test runner, Playwright Test, which is built for end-to-end -testing. You can also install it as a dev dependency in your project: +You can install Playwright through your preferred Node.js package manager. It comes with its +own [test runner][playwright-intro], which is built for end-to-end testing: ```sh npm2yarn npm install --save-dev @playwright/test ``` :::caution Dependencies -This tutorial was written `playwright@1.16.3` and `@playwright/test@1.16.3`. Check out +This tutorial was written with `@playwright/test@1.41.1`. Check out [Playwright's releases][playwright-releases] page to learn about changes that might affect the code below. ::: -:::info Using third-party test runners -If you're interested in using an alternative test runner (e.g. Jest or Mocha), check out -Playwright's [Third-Party Test Runner][playwright-test-runners] guide. -::: - ### Write your tests Playwright launches your app in development mode through the `_electron.launch` API. To point this API to your Electron app, you can pass the path to your main process entry point (here, it is `main.js`). -```js {5} -const { _electron: electron } = require('playwright') -const { test } = require('@playwright/test') +```js {5} @ts-nocheck +const { test, _electron: electron } = require('@playwright/test') test('launch app', async () => { const electronApp = await electron.launch({ args: ['main.js'] }) @@ -169,9 +228,8 @@ test('launch app', async () => { After that, you will access to an instance of Playwright's `ElectronApp` class. This is a powerful class that has access to main process modules for example: -```js {6-11} -const { _electron: electron } = require('playwright') -const { test } = require('@playwright/test') +```js {5-10} @ts-nocheck +const { test, _electron: electron } = require('@playwright/test') test('get isPackaged', async () => { const electronApp = await electron.launch({ args: ['main.js'] }) @@ -189,9 +247,8 @@ test('get isPackaged', async () => { It can also create individual [Page][playwright-page] objects from Electron BrowserWindow instances. For example, to grab the first BrowserWindow and save a screenshot: -```js {6-7} -const { _electron: electron } = require('playwright') -const { test } = require('@playwright/test') +```js {6-7} @ts-nocheck +const { test, _electron: electron } = require('@playwright/test') test('save screenshot', async () => { const electronApp = await electron.launch({ args: ['main.js'] }) @@ -202,22 +259,21 @@ test('save screenshot', async () => { }) ``` -Putting all this together using the PlayWright Test runner, let's create a `example.spec.js` +Putting all this together using the Playwright test-runner, let's create a `example.spec.js` test file with a single test and assertion: -```js title='example.spec.js' -const { _electron: electron } = require('playwright') -const { test, expect } = require('@playwright/test') +```js title='example.spec.js' @ts-nocheck +const { test, expect, _electron: electron } = require('@playwright/test') test('example test', async () => { const electronApp = await electron.launch({ args: ['.'] }) const isPackaged = await electronApp.evaluate(async ({ app }) => { // This runs in Electron's main process, parameter here is always // the result of the require('electron') in the main app script. - return app.isPackaged; - }); + return app.isPackaged + }) - expect(isPackaged).toBe(false); + expect(isPackaged).toBe(false) // Wait for the first BrowserWindow to open // and return its Page object @@ -226,7 +282,7 @@ test('example test', async () => { // close app await electronApp.close() -}); +}) ``` Then, run Playwright Test using `npx playwright test`. You should see the test pass in your @@ -243,6 +299,7 @@ Running 1 test using 1 worker :::info Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex. You can customize this match in the [Playwright Test configuration options][playwright-test-config]. +It also works with TypeScript out of the box. ::: :::tip Further reading @@ -259,8 +316,8 @@ expose custom methods to your test suite. To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol: -```js title='testDriver.js' -const childProcess = require('child_process') +```js title='testDriver.js' @ts-nocheck +const childProcess = require('node:child_process') const electronPath = require('electron') // spawn the process @@ -296,7 +353,7 @@ For convenience, you may want to wrap `appProcess` in a driver object that provi high-level functions. Here is an example of how you can do this. Let's start by creating a `TestDriver` class: -```js title='testDriver.js' +```js title='testDriver.js' @ts-nocheck class TestDriver { constructor ({ path, args, env }) { this.rpcCalls = [] @@ -338,7 +395,7 @@ class TestDriver { } } -module.exports = { TestDriver }; +module.exports = { TestDriver } ``` In your app code, can then write a simple handler to receive RPC calls: @@ -378,7 +435,7 @@ framework of your choosing. The following example uses [`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest or Mocha would work as well: -```js title='test.js' +```js title='test.js' @ts-nocheck const test = require('ava') const electronPath = require('electron') const { TestDriver } = require('./testDriver') @@ -400,10 +457,10 @@ test.after.always('cleanup', async t => { [chrome-driver]: https://sites.google.com/chromium.org/driver/ [Puppeteer]: https://github.com/puppeteer/puppeteer +[playwright-intro]: https://playwright.dev/docs/intro [playwright-electron]: https://playwright.dev/docs/api/class-electron/ [playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication [playwright-page]: https://playwright.dev/docs/api/class-page -[playwright-releases]: https://github.com/microsoft/playwright/releases +[playwright-releases]: https://playwright.dev/docs/release-notes [playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match -[playwright-test-runners]: https://playwright.dev/docs/test-runners/ [Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/ diff --git a/docs/tutorial/boilerplates-and-clis.md b/docs/tutorial/boilerplates-and-clis.md index 304254285180e..254f8887cb9ba 100644 --- a/docs/tutorial/boilerplates-and-clis.md +++ b/docs/tutorial/boilerplates-and-clis.md @@ -21,18 +21,16 @@ can clone and customize to your heart's content. A command line tool on the other hand continues to support you throughout the development and release. They are more helpful and supportive but enforce -guidelines on how your code should be structured and built. *Especially for -beginners, using a command line tool is likely to be helpful*. +guidelines on how your code should be structured and built. _Especially for +beginners, using a command line tool is likely to be helpful_. -## electron-forge +## Electron Forge -A "complete tool for building modern Electron applications". Electron Forge -unifies the existing (and well maintained) build tools for Electron development -into a cohesive package so that anyone can jump right in to Electron -development. +Electron Forge is a tool for packaging and publishing Electron applications. It unifies Electron's tooling ecosystem +into a single extensible interface so that anyone can jump right into making Electron apps. Forge comes with [a ready-to-use template](https://electronforge.io/templates) using Webpack as a bundler. It includes an example typescript configuration and provides two configuration files to enable easy customization. It uses the same core modules used by the -greater Electron community (like [`electron-packager`](https://github.com/electron/electron-packager)) – +greater Electron community (like [`@electron/packager`](https://github.com/electron/packager)) – changes made by Electron maintainers (like Slack) benefit Forge's users, too. You can find more information and documentation on [electronforge.io](https://electronforge.io/). @@ -54,7 +52,7 @@ You can find more information and documentation in [the repository](https://gith ## electron-react-boilerplate If you don't want any tools but only a solid boilerplate to build from, -CT Lin's [`electron-react-boilerplate`](https://github.com/chentsulin/electron-react-boilerplate) might be worth +CT Lin's [`electron-react-boilerplate`](https://github.com/electron-react-boilerplate/electron-react-boilerplate) might be worth a look. It's quite popular in the community and uses `electron-builder` internally. diff --git a/docs/tutorial/code-signing.md b/docs/tutorial/code-signing.md index a035b480cd57e..880b36f16f53e 100644 --- a/docs/tutorial/code-signing.md +++ b/docs/tutorial/code-signing.md @@ -5,34 +5,24 @@ slug: code-signing hide_title: false --- -Code signing is a security technology that you use to certify that an app was -created by you. You should sign your application so it does not trigger any -operating system security checks. +Code signing is a security technology to certify that an app was created by you. +You should sign your application so it does not trigger any operating system +security warnings. -On macOS, the system can detect any change to the app, whether the change is -introduced accidentally or by malicious code. +![macOS Sonoma Gatekeeper warning: The app is damaged](../images/gatekeeper.png) -On Windows, the system assigns a trust level to your code signing certificate -which if you don't have, or if your trust level is low, will cause security -dialogs to appear when users start using your application. Trust level builds -over time so it's better to start code signing as early as possible. - -While it is possible to distribute unsigned apps, it is not recommended. Both -Windows and macOS will, by default, prevent either the download or the execution -of unsigned applications. Starting with macOS Catalina (version 10.15), users -have to go through multiple manual steps to open unsigned applications. - -![macOS Catalina Gatekeeper warning: The app cannot be opened because the developer cannot be verified](../images/gatekeeper.png) - -As you can see, users get two options: Move the app straight to the trash or -cancel running it. You don't want your users to see that dialog. +Both Windows and macOS prevent users from running unsigned applications. It is +possible to distribute applications without codesigning them - but in order to +run them, users need to go through multiple advanced and manual steps. If you are building an Electron app that you intend to package and distribute, -it should be code signed. +it should be code signed. The Electron ecosystem tooling makes codesigning your +apps straightforward - this documentation explains how sign your apps on both +Windows and macOS. ## Signing & notarizing macOS builds -Properly preparing macOS applications for release requires two steps. First, the +Preparing macOS applications for release requires two steps: First, the app needs to be code signed. Then, the app needs to be uploaded to Apple for a process called **notarization**, where automated systems will further verify that your app isn't doing anything to endanger its users. @@ -40,9 +30,9 @@ your app isn't doing anything to endanger its users. To start the process, ensure that you fulfill the requirements for signing and notarizing your app: -1. Enroll in the [Apple Developer Program] (requires an annual fee) -2. Download and install [Xcode] - this requires a computer running macOS -3. Generate, download, and install [signing certificates] +1. Enroll in the [Apple Developer Program][] (requires an annual fee) +2. Download and install [Xcode][] - this requires a computer running macOS +3. Generate, download, and install [signing certificates][] Electron's ecosystem favors configuration and freedom, so there are multiple ways to get your application signed and notarized. @@ -51,106 +41,30 @@ ways to get your application signed and notarized. If you're using Electron's favorite build tool, getting your application signed and notarized requires a few additions to your configuration. [Forge](https://electronforge.io) is a -collection of the official Electron tools, using [`electron-packager`], -[`electron-osx-sign`], and [`electron-notarize`] under the hood. - -Let's take a look at an example `package.json` configuration with all required fields. Not all of them are -required: the tools will be clever enough to automatically find a suitable `identity`, for instance, -but we recommend that you are explicit. - -```json title="package.json" {7} -{ - "name": "my-app", - "version": "0.0.1", - "config": { - "forge": { - "packagerConfig": { - "osxSign": { - "identity": "Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)", - "hardened-runtime": true, - "entitlements": "entitlements.plist", - "entitlements-inherit": "entitlements.plist", - "signature-flags": "library" - }, - "osxNotarize": { - "appleId": "felix@felix.fun", - "appleIdPassword": "my-apple-id-password" - } - } - } - } -} -``` - -The `entitlements.plist` file referenced here needs the following macOS-specific entitlements -to assure the Apple security mechanisms that your app is doing these things -without meaning any harm: - -```xml title="entitlements.plist" - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.debugger - - - -``` - -Note that up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required -as well. However, it should not be used anymore if it can be avoided. +collection of the official Electron tools, using [`@electron/packager`][], +[`@electron/osx-sign`][], and [`@electron/notarize`][] under the hood. -To see all of this in action, check out Electron Fiddle's source code, -[especially its `electron-forge` configuration -file](https://github.com/electron/fiddle/blob/master/forge.config.js). - -If you plan to access the microphone or camera within your app using Electron's APIs, you'll also -need to add the following entitlements: - -```xml title="entitlements.plist" -com.apple.security.device.audio-input - -com.apple.security.device.camera - -``` - -If these are not present in your app's entitlements when you invoke, for example: - -```js title="main.js" -const { systemPreferences } = require('electron') -const microphone = systemPreferences.askForMediaAccess('microphone') -``` - -Your app may crash. See the Resource Access section in [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) for more information and entitlements you may need. - -### Using Electron Builder - -Electron Builder comes with a custom solution for signing your application. You -can find [its documentation here](https://www.electron.build/code-signing). +Detailed instructions on how to configure your application can be found in the +[Signing macOS Apps](https://www.electronforge.io/guides/code-signing/code-signing-macos) guide in +the Electron Forge docs. ### Using Electron Packager -If you're not using an integrated build pipeline like Forge or Builder, you -are likely using [`electron-packager`], which includes [`electron-osx-sign`] and -[`electron-notarize`]. +If you're not using an integrated build pipeline like Forge, you +are likely using [`@electron/packager`][], which includes [`@electron/osx-sign`][] and +[`@electron/notarize`][]. -If you're using Packager's API, you can pass [in configuration that both signs -and notarizes your application](https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html). +If you're using Packager's API, you can pass +[in configuration that both signs and notarizes your application](https://electron.github.io/packager/main/modules.html). +If the example below does not meet your needs, please see [`@electron/osx-sign`][] and +[`@electron/notarize`][] for the many possible configuration options. -```js -const packager = require('electron-packager') +```js @ts-nocheck +const packager = require('@electron/packager') packager({ dir: '/path/to/my/app', - osxSign: { - identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)', - 'hardened-runtime': true, - entitlements: 'entitlements.plist', - 'entitlements-inherit': 'entitlements.plist', - 'signature-flags': 'library' - }, + osxSign: {}, osxNotarize: { appleId: 'felix@felix.fun', appleIdPassword: 'my-apple-id-password' @@ -158,92 +72,89 @@ packager({ }) ``` -The `entitlements.plist` file referenced here needs the following macOS-specific entitlements -to assure the Apple security mechanisms that your app is doing these things -without meaning any harm: - -```xml title="entitlements.plist" - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.debugger - - - -``` - -Up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required -as well. However, it should not be used anymore if it can be avoided. - ### Signing Mac App Store applications -See the [Mac App Store Guide]. +See the [Mac App Store Guide][]. ## Signing Windows builds -Before signing Windows builds, you must do the following: +Before you can code sign your application, you need to acquire a code signing +certificate. Unlike Apple, Microsoft allows developers to purchase those +certificates on the open market. They are usually sold by the same companies +also offering HTTPS certificates. Prices vary, so it may be worth your time to +shop around. Popular resellers include: + +- [Certum EV code signing certificate](https://shop.certum.eu/data-safety/code-signing-certificates/certum-ev-code-sigining.html) +- [DigiCert EV code signing certificate](https://www.digicert.com/signing/code-signing-certificates) +- [Entrust EV code signing certificate](https://www.entrustdatacard.com/products/digital-signing-certificates/code-signing-certificates) +- [GlobalSign EV code signing certificate](https://www.globalsign.com/en/code-signing-certificate/ev-code-signing-certificates) +- [IdenTrust EV code signing certificate](https://www.identrust.com/digital-certificates/trustid-ev-code-signing) +- [Sectigo (formerly Comodo) EV code signing certificate](https://sectigo.com/ssl-certificates-tls/code-signing) +- [SSL.com EV code signing certificate](https://www.ssl.com/certificates/ev-code-signing/) + +It is important to call out that since June 2023, Microsoft requires software to +be signed with an "extended validation" certificate, also called an "EV code signing +certificate". In the past, developers could sign software with a simpler and cheaper +certificate called "authenticode code signing certificate" or "software-based OV certificate". +These simpler certificates no longer provide benefits: Windows will treat your app as +completely unsigned and display the equivalent warning dialogs. + +The new EV certificates are required to be stored on a hardware storage module +compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent. In other words, +the certificate cannot be simply downloaded onto a CI infrastructure. In practice, +those storage modules look like fancy USB thumb drives. + +Many certificate providers now offer "cloud-based signing" - the entire signing hardware +is in their data center and you can use it to remotely sign code. This approach is +popular with Electron maintainers since it makes signing your applications in CI (like +GitHub Actions, CircleCI, etc) relatively easy. + +At the time of writing, Electron's own apps use [DigiCert KeyLocker](https://docs.digicert.com/en/digicert-keylocker.html), but any provider that provides a command line tool for +signing files will be compatible with Electron's tooling. + +All tools in the Electron ecosystem use [`@electron/windows-sign`][] and typically +expose configuration options through a `windowsSign` property. You can either use it +to sign files directly - or use the same `windowsSign` configuration across Electron +Forge, [`@electron/packager`][], [`electron-winstaller`][], and [`electron-wix-msi`][]. -1. Get a Windows Authenticode code signing certificate (requires an annual fee) -2. Install Visual Studio to get the signing utility (the free [Community - Edition](https://visualstudio.microsoft.com/vs/community/) is enough) +### Using Electron Forge -You can get a code signing certificate from a lot of resellers. Prices vary, so -it may be worth your time to shop around. Popular resellers include: +Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows` +and `WiX MSI` installers. Detailed instructions on how to configure your application can +be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-windows). -- [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm) -- [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing) -- Amongst others, please shop around to find one that suits your needs! 😄 +### Using Electron Packager -:::caution Keep your certificate password private -Your certificate password should be a **secret**. Do not share it publicly or -commit it to your source code. -::: +If you're not using an integrated build pipeline like Forge, you +are likely using [`@electron/packager`][], which includes [`@electron/windows-sign`][]. -### Using Electron Forge +If you're using Packager's API, you can pass +[in configuration that signs your application](https://electron.github.io/packager/main/modules.html). +If the example below does not meet your needs, please see [`@electron/windows-sign`][] +for the many possible configuration options. -Once you have a code signing certificate file (`.pfx`), you can sign -[Squirrel.Windows][maker-squirrel] and [MSI][maker-msi] installers in Electron Forge -with the `certificateFile` and `certificatePassword` fields in their respective -configuration objects. - -For example, if you keep your Forge config in your `package.json` file and are -creating a Squirrel.Windows installer: - -```json {9-15} title='package.json' -{ - "name": "my-app", - "version": "0.0.1", - //... - "config": { - "forge": { - "packagerConfig": {}, - "makers": [ - { - "name": "@electron-forge/maker-squirrel", - "config": { - "certificateFile": "./cert.pfx", - "certificatePassword": "this-is-a-secret" - } - } - ] - } +```js @ts-nocheck +const packager = require('@electron/packager') + +packager({ + dir: '/path/to/my/app', + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' } - //... -} +}) ``` ### Using electron-winstaller (Squirrel.Windows) -[`electron-winstaller`] is a package that can generate Squirrel.Windows installers for your +[`electron-winstaller`][] is a package that can generate Squirrel.Windows installers for your Electron app. This is the tool used under the hood by Electron Forge's -[Squirrel.Windows Maker][maker-squirrel]. If you're not using Electron Forge and want to use -`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration -options when creating your installer. +[Squirrel.Windows Maker][maker-squirrel]. Just like `@electron/packager`, it uses +[`@electron/windows-sign`][] under the hood and supports the same `windowsSign` +options. -```js {10-11} +```js {10-11} @ts-nocheck const electronInstaller = require('electron-winstaller') // NB: Use this syntax within an async function, Node does not have support for // top-level await as of Node 12. @@ -253,8 +164,11 @@ try { outputDirectory: '/tmp/build/installer64', authors: 'My App Inc.', exe: 'myapp.exe', - certificateFile: './cert.pfx', - certificatePassword: 'this-is-a-secret', + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' + } }) console.log('It worked!') } catch (e) { @@ -262,18 +176,16 @@ try { } ``` -For full configuration options, check out the [`electron-winstaller`] repository! +For full configuration options, check out the [`electron-winstaller`][] repository! ### Using electron-wix-msi (WiX MSI) -[`electron-wix-msi`] is a package that can generate MSI installers for your +[`electron-wix-msi`][] is a package that can generate MSI installers for your Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi]. +Just like `@electron/packager`, it uses [`@electron/windows-sign`][] under the hood +and supports the same `windowsSign` options. -If you're not using Electron Forge and want to use `electron-wix-msi` directly, use the -`certificateFile` and `certificatePassword` configuration options -or pass in parameters directly to [SignTool.exe] with the `signWithParams` option. - -```js {12-13} +```js {12-13} @ts-nocheck import { MSICreator } from 'electron-wix-msi' // Step 1: Instantiate the MSICreator @@ -285,8 +197,11 @@ const msiCreator = new MSICreator({ manufacturer: 'Kitten Technologies', version: '1.1.2', outputDirectory: '/path/to/output/folder', - certificateFile: './cert.pfx', - certificatePassword: 'this-is-a-secret', + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' + } }) // Step 2: Create a .wxs template file @@ -294,17 +209,17 @@ const supportBinaries = await msiCreator.create() // 🆕 Step 2a: optionally sign support binaries if you // sign you binaries as part of of your packaging script -supportBinaries.forEach(async (binary) => { +for (const binary of supportBinaries) { // Binaries are the new stub executable and optionally // the Squirrel auto updater. await signFile(binary) -}) +} // Step 3: Compile the template to a .msi file await msiCreator.compile() ``` -For full configuration options, check out the [`electron-wix-msi`] repository! +For full configuration options, check out the [`electron-wix-msi`][] repository! ### Using Electron Builder @@ -313,20 +228,18 @@ can find [its documentation here](https://www.electron.build/code-signing). ### Signing Windows Store applications -See the [Windows Store Guide]. +See the [Windows Store Guide][]. [apple developer program]: https://developer.apple.com/programs/ -[`electron-builder`]: https://github.com/electron-userland/electron-builder -[`electron-forge`]: https://github.com/electron-userland/electron-forge -[`electron-osx-sign`]: https://github.com/electron-userland/electron-osx-sign -[`electron-packager`]: https://github.com/electron/electron-packager -[`electron-notarize`]: https://github.com/electron/electron-notarize +[`@electron/osx-sign`]: https://github.com/electron/osx-sign +[`@electron/packager`]: https://github.com/electron/packager +[`@electron/notarize`]: https://github.com/electron/notarize +[`@electron/windows-sign`]: https://github.com/electron/windows-sign [`electron-winstaller`]: https://github.com/electron/windows-installer -[`electron-wix-msi`]: https://github.com/felixrieseberg/electron-wix-msi +[`electron-wix-msi`]: https://github.com/electron-userland/electron-wix-msi [xcode]: https://developer.apple.com/xcode -[signing certificates]: https://github.com/electron/electron-osx-sign/wiki/1.-Getting-Started#certificates +[signing certificates]: https://developer.apple.com/support/certificates/ [mac app store guide]: ./mac-app-store-submission-guide.md [windows store guide]: ./windows-store-guide.md [maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows [maker-msi]: https://www.electronforge.io/config/makers/wix-msi -[signtool.exe]: https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe diff --git a/docs/tutorial/context-isolation.md b/docs/tutorial/context-isolation.md index 140d9d75726bc..389db0cc9fd27 100644 --- a/docs/tutorial/context-isolation.md +++ b/docs/tutorial/context-isolation.md @@ -16,7 +16,7 @@ Context isolation has been enabled by default since Electron 12, and it is a rec Exposing APIs from your preload script to a loaded website in the renderer process is a common use-case. With context isolation disabled, your preload script would share a common global `window` object with the renderer. You could then attach arbitrary properties to a preload script: -```javascript title='preload.js' +```js title='preload.js' @ts-nocheck // preload with contextIsolation disabled window.myAPI = { doAThing: () => {} @@ -25,7 +25,7 @@ window.myAPI = { The `doAThing()` function could then be used directly in the renderer process: -```javascript title='renderer.js' +```js title='renderer.js' @ts-nocheck // use the exposed API in the renderer window.myAPI.doAThing() ``` @@ -34,7 +34,7 @@ window.myAPI.doAThing() There is a dedicated module in Electron to help you do this in a painless way. The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from your preload script's isolated context to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before. -```javascript title='preload.js' +```js title='preload.js' // preload with contextIsolation enabled const { contextBridge } = require('electron') @@ -43,7 +43,7 @@ contextBridge.exposeInMainWorld('myAPI', { }) ``` -```javascript title='renderer.js' +```js title='renderer.js' @ts-nocheck // use the exposed API in the renderer window.myAPI.doAThing() ``` @@ -54,7 +54,7 @@ Please read the `contextBridge` documentation linked above to fully understand i Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance, this code is **unsafe**. -```javascript title='preload.js' +```js title='preload.js' // ❌ Bad code contextBridge.exposeInMainWorld('myAPI', { send: ipcRenderer.send @@ -63,7 +63,7 @@ contextBridge.exposeInMainWorld('myAPI', { It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages, which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message. -```javascript title='preload.js' +```js title='preload.js' // ✅ Good code contextBridge.exposeInMainWorld('myAPI', { loadPreferences: () => ipcRenderer.invoke('load-prefs') @@ -72,19 +72,19 @@ contextBridge.exposeInMainWorld('myAPI', { ## Usage with TypeScript -If you're building your Electron app with TypeScript, you'll want to add types to your APIs exposed over the context bridge. The renderer's `window` object won't have the correct typings unless you extend the types with a [declaration file]. +If you're building your Electron app with TypeScript, you'll want to add types to your APIs exposed over the context bridge. The renderer's `window` object won't have the correct typings unless you extend the types with a [declaration file][]. For example, given this `preload.ts` script: -```typescript title='preload.ts' +```ts title='preload.ts' contextBridge.exposeInMainWorld('electronAPI', { loadPreferences: () => ipcRenderer.invoke('load-prefs') }) ``` -You can create a `renderer.d.ts` declaration file and globally augment the `Window` interface: +You can create a `interface.d.ts` declaration file and globally augment the `Window` interface: -```typescript title='renderer.d.ts' +```ts title='interface.d.ts' @ts-noisolate export interface IElectronAPI { loadPreferences: () => Promise, } @@ -98,7 +98,7 @@ declare global { Doing so will ensure that the TypeScript compiler will know about the `electronAPI` property on your global `window` object when writing scripts in your renderer process: -```typescript title='renderer.ts' +```ts title='renderer.ts' window.electronAPI.loadPreferences() ``` diff --git a/docs/tutorial/custom-title-bar.md b/docs/tutorial/custom-title-bar.md new file mode 100644 index 0000000000000..9f9966eaf195a --- /dev/null +++ b/docs/tutorial/custom-title-bar.md @@ -0,0 +1,176 @@ +# Custom Title Bar + +## Basic tutorial + +Application windows have a default [chrome][] applied by the OS. Not to be confused +with the Google Chrome browser, window _chrome_ refers to the parts of the window (e.g. +title bar, toolbars, controls) that are not a part of the main web content. While the +default title bar provided by the OS chrome is sufficent for simple use cases, many +applications opt to remove it. Implementing a custom title bar can help your application +feel more modern and consistent across platforms. + +You can follow along with this tutorial by opening Fiddle with the following starter code. + +```fiddle docs/fiddles/features/window-customization/custom-title-bar/starter-code + +``` + +### Remove the default title bar + +Let’s start by configuring a window with native window controls and a hidden title bar. +To remove the default title bar, set the [`BaseWindowContructorOptions`][] `titleBarStyle` +param in the `BrowserWindow` constructor to `'hidden'`. + +```fiddle docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar + +``` + +### Add native window controls _Windows_ _Linux_ + +On macOS, setting `titleBarStyle: 'hidden'` removes the title bar while keeping the window’s +traffic light controls available in the upper left hand corner. However on Windows and Linux, +you’ll need to add window controls back into your `BrowserWindow` by setting the +[`BaseWindowContructorOptions`][] `titleBarOverlay` param in the `BrowserWindow` constructor. + +```fiddle docs/fiddles/features/window-customization/custom-title-bar/native-window-controls + +``` + +Setting `titleBarOverlay: true` is the simplest way to expose window controls back into +your `BrowserWindow`. If you’re interested in customizing the window controls further, +check out the sections [Custom traffic lights][] and [Custom window controls][] that cover +this in more detail. + +### Create a custom title bar + +Now, let’s implement a simple custom title bar in the `webContents` of our `BrowserWindow`. +There’s nothing fancy here, just HTML and CSS! + +```fiddle docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar + +``` + +Currently our application window can’t be moved. Since we’ve removed the default title bar, +the application needs to tell Electron which regions are draggable. We’ll do this by adding +the CSS style `app-region: drag` to the custom title bar. Now we can drag the custom title +bar to reposition our app window! + +```fiddle docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region + +``` + +For more information around how to manage drag regions defined by your electron application, +see the [Custom draggable regions][] section below. + +Congratulations, you've just implemented a basic custom title bar! + +## Advanced window customization + +### Custom traffic lights _macOS_ + +#### Customize the look of your traffic lights _macOS_ + +The `customButtonsOnHover` title bar style will hide the traffic lights until you hover +over them. This is useful if you want to create custom traffic lights in your HTML but still +use the native UI to control the window. + +```js +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' }) +``` + +#### Customize the traffic light position _macOS_ + +To modify the position of the traffic light window controls, there are two configuration +options available. + +Applying `hiddenInset` title bar style will shift the vertical inset of the traffic lights +by a fixed amount. + +```js title='main.js' +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' }) +``` + +If you need more granular control over the positioning of the traffic lights, you can pass +a set of coordinates to the `trafficLightPosition` option in the `BrowserWindow` +constructor. + +```js title='main.js' +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ + titleBarStyle: 'hidden', + trafficLightPosition: { x: 10, y: 10 } +}) +``` + +#### Show and hide the traffic lights programmatically _macOS_ + +You can also show and hide the traffic lights programmatically from the main process. +The `win.setWindowButtonVisibility` forces traffic lights to be show or hidden depending +on the value of its boolean parameter. + +```js title='main.js' +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() +// hides the traffic lights +win.setWindowButtonVisibility(false) +``` + +:::note +Given the number of APIs available, there are many ways of achieving this. For instance, +combining `frame: false` with `win.setWindowButtonVisibility(true)` will yield the same +layout outcome as setting `titleBarStyle: 'hidden'`. +::: + +#### Custom window controls + +The [Window Controls Overlay API][] is a web standard that gives web apps the ability to +customize their title bar region when installed on desktop. Electron exposes this API +through the `titleBarOverlay` option in the `BrowserWindow` constructor. When `titleBarOverlay` +is enabled, the window controls become exposed in their default position, and DOM elements +cannot use the area underneath this region. + +:::note +`titleBarOverlay` requires the `titleBarStyle` param in the `BrowserWindow` constructor +to have a value other than `default`. +::: + +The custom title bar tutorial covers a [basic example][Add native window controls] of exposing +window controls by setting `titleBarOverlay: true`. The height, color (_Windows_ _Linux_), and +symbol colors (_Windows_) of the window controls can be customized further by setting +`titleBarOverlay` to an object. + +The value passed to the `height` property must be an integer. The `color` and `symbolColor` +properties accept `rgba()`, `hsla()`, and `#RRGGBBAA` color formats and support transparency. +If a color option is not specified, the color will default to its system color for the window +control buttons. Similarly, if the height option is not specified, the window controls will +default to the standard system height: + +```js title='main.js' +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ + titleBarStyle: 'hidden', + titleBarOverlay: { + color: '#2f3241', + symbolColor: '#74b1be', + height: 60 + } +}) +``` + +:::note +Once your title bar overlay is enabled from the main process, you can access the overlay's +color and dimension values from a renderer using a set of readonly +[JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. +::: + +[Add native window controls]: #add-native-window-controls-windows-linux +[`BaseWindowContructorOptions`]: ../api/structures/base-window-options.md +[chrome]: https://developer.mozilla.org/en-US/docs/Glossary/Chrome +[Custom draggable regions]: ./custom-window-interactions.md#custom-draggable-regions +[Custom traffic lights]: #custom-traffic-lights-macos +[Custom window controls]: #custom-window-controls +[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables +[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis +[Window Controls Overlay API]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md diff --git a/docs/tutorial/custom-window-interactions.md b/docs/tutorial/custom-window-interactions.md new file mode 100644 index 0000000000000..6801594b94444 --- /dev/null +++ b/docs/tutorial/custom-window-interactions.md @@ -0,0 +1,107 @@ +# Custom Window Interactions + +## Custom draggable regions + +By default, windows are dragged using the title bar provided by the OS chrome. Apps +that remove the default title bar need to use the `app-region` CSS property to define +specific areas that can be used to drag the window. Setting `app-region: drag` marks +a rectagular area as draggable. + +It is important to note that draggable areas ignore all pointer events. For example, +a button element that overlaps a draggable region will not emit mouse clicks or mouse +enter/exit events within that overlapping area. Setting `app-region: no-drag` reenables +pointer events by excluding a rectagular area from a draggable region. + +To make the whole window draggable, you can add `app-region: drag` as +`body`'s style: + +```css title='styles.css' +body { + app-region: drag; +} +``` + +And note that if you have made the whole window draggable, you must also mark +buttons as non-draggable, otherwise it would be impossible for users to click on +them: + +```css title='styles.css' +button { + app-region: no-drag; +} +``` + +If you're only setting a custom title bar as draggable, you also need to make all +buttons in title bar non-draggable. + +### Tip: disable text selection + +When creating a draggable region, the dragging behavior may conflict with text selection. +For example, when you drag the title bar, you may accidentally select its text contents. +To prevent this, you need to disable text selection within a draggable area like this: + +```css +.titlebar { + user-select: none; + app-region: drag; +} +``` + +### Tip: disable context menus + +On some platforms, the draggable area will be treated as a non-client frame, so +when you right click on it, a system menu will pop up. To make the context menu +behave correctly on all platforms, you should never use a custom context menu on +draggable areas. + +## Click-through windows + +To create a click-through window, i.e. making the window ignore all mouse +events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events] +API: + +```js title='main.js' +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() +win.setIgnoreMouseEvents(true) +``` + +### Forward mouse events _macOS_ _Windows_ + +Ignoring mouse messages makes the web contents oblivious to mouse movement, +meaning that mouse movement events will not be emitted. On Windows and macOS, an +optional parameter can be used to forward mouse move messages to the web page, +allowing events such as `mouseleave` to be emitted: + +```js title='main.js' +const { BrowserWindow, ipcMain } = require('electron') +const path = require('node:path') + +const win = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } +}) + +ipcMain.on('set-ignore-mouse-events', (event, ignore, options) => { + const win = BrowserWindow.fromWebContents(event.sender) + win.setIgnoreMouseEvents(ignore, options) +}) +``` + +```js title='preload.js' +window.addEventListener('DOMContentLoaded', () => { + const el = document.getElementById('clickThroughElement') + el.addEventListener('mouseenter', () => { + ipcRenderer.send('set-ignore-mouse-events', true, { forward: true }) + }) + el.addEventListener('mouseleave', () => { + ipcRenderer.send('set-ignore-mouse-events', false) + }) +}) +``` + +This makes the web page click-through when over the `#clickThroughElement` element, +and returns to normal outside it. + +[ignore-mouse-events]: ../api/browser-window.md#winsetignoremouseeventsignore-options diff --git a/docs/tutorial/custom-window-styles.md b/docs/tutorial/custom-window-styles.md new file mode 100644 index 0000000000000..0dd641ce6162c --- /dev/null +++ b/docs/tutorial/custom-window-styles.md @@ -0,0 +1,49 @@ +# Custom Window Styles + +## Frameless windows + +![Frameless Window](../images/frameless-window.png) + +A frameless window removes all [chrome][] applied by the OS, including window controls. + +To create a frameless window, set the [`BaseWindowContructorOptions`][] `frame` param in the `BrowserWindow` constructor to `false`. + +```fiddle docs/fiddles/features/window-customization/custom-window-styles/frameless-windows + +``` + +## Transparent windows + +![Transparent Window](../images/transparent-window.png) +![Transparent Window in macOS Mission Control](../images/transparent-window-mission-control.png) + +To create a fully transparent window, set the [`BaseWindowContructorOptions`][] `transparent` param in the `BrowserWindow` constructor to `true`. + +The following fiddle takes advantage of a tranparent window and CSS styling to create +the illusion of a circular window. + +```fiddle docs/fiddles/features/window-customization/custom-window-styles/transparent-windows + +``` + +### Limitations + +* You cannot click through the transparent area. See + [#1335](https://github.com/electron/electron/issues/1335) for details. +* Transparent windows are not resizable. Setting `resizable` to `true` may make + a transparent window stop working on some platforms. +* The CSS [`blur()`][] filter only applies to the window's web contents, so there is + no way to apply blur effect to the content below the window (i.e. other applications + open on the user's system). +* The window will not be transparent when DevTools is opened. +* On _Windows_: + * Transparent windows will not work when DWM is disabled. + * Transparent windows can not be maximized using the Windows system menu or by double + clicking the title bar. The reasoning behind this can be seen on + PR [#28207](https://github.com/electron/electron/pull/28207). +* On _macOS_: + * The native window shadow will not be shown on a transparent window. + +[`BaseWindowContructorOptions`]: ../api/structures/base-window-options.md +[`blur()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur() +[chrome]: https://developer.mozilla.org/en-US/docs/Glossary/Chrome diff --git a/docs/tutorial/dark-mode.md b/docs/tutorial/dark-mode.md index bf16303e4ecb1..d069ed8b5dadf 100644 --- a/docs/tutorial/dark-mode.md +++ b/docs/tutorial/dark-mode.md @@ -13,7 +13,7 @@ from the OS. If your app has its own dark mode, you should toggle it on and off in sync with the system's dark mode setting. You can do this by using the -[prefer-color-scheme] CSS media query. +[prefers-color-scheme][] CSS media query. ### Manually update your own interfaces @@ -50,7 +50,7 @@ of this theming, due to the use of the macOS 10.14 SDK. This example demonstrates an Electron application that derives its theme colors from the `nativeTheme`. Additionally, it provides theme toggle and reset controls using IPC channels. -```javascript fiddle='docs/fiddles/features/macos-dark-mode' +```fiddle docs/fiddles/features/dark-mode ``` @@ -75,7 +75,6 @@ Starting with the `index.html` file: - ``` @@ -116,7 +115,7 @@ Now the renderer process can communicate with the main process securely and perf The `renderer.js` file is responsible for controlling the ` + + diff --git a/spec/fixtures/crash-cases/webview-remove-on-wc-close/index.js b/spec/fixtures/crash-cases/webview-remove-on-wc-close/index.js new file mode 100644 index 0000000000000..de6313d8d9452 --- /dev/null +++ b/spec/fixtures/crash-cases/webview-remove-on-wc-close/index.js @@ -0,0 +1,29 @@ +const { app, BrowserWindow } = require('electron'); + +app.whenReady().then(() => { + const win = new BrowserWindow({ + webPreferences: { + webviewTag: true + } + }); + + win.loadFile('index.html'); + + win.webContents.on('did-attach-webview', (event, contents) => { + contents.on('render-process-gone', () => { + process.exit(1); + }); + + contents.on('destroyed', () => { + process.exit(0); + }); + + contents.on('did-finish-load', () => { + win.webContents.executeJavaScript('closeBtn.click()'); + }); + + contents.on('will-prevent-unload', event => { + event.preventDefault(); + }); + }); +}); diff --git a/spec/fixtures/crash-cases/webview-remove-on-wc-close/webview.html b/spec/fixtures/crash-cases/webview-remove-on-wc-close/webview.html new file mode 100644 index 0000000000000..aacd50364a10d --- /dev/null +++ b/spec/fixtures/crash-cases/webview-remove-on-wc-close/webview.html @@ -0,0 +1,6 @@ +

webview page

+ diff --git a/spec/fixtures/crash-cases/worker-multiple-destroy/index.html b/spec/fixtures/crash-cases/worker-multiple-destroy/index.html new file mode 100644 index 0000000000000..131b48850d179 --- /dev/null +++ b/spec/fixtures/crash-cases/worker-multiple-destroy/index.html @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/spec/fixtures/crash-cases/worker-multiple-destroy/index.js b/spec/fixtures/crash-cases/worker-multiple-destroy/index.js new file mode 100644 index 0000000000000..382212f918d67 --- /dev/null +++ b/spec/fixtures/crash-cases/worker-multiple-destroy/index.js @@ -0,0 +1,38 @@ +const { app, BrowserWindow } = require('electron'); + +async function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegrationInWorker: true + } + }); + + let loads = 1; + mainWindow.webContents.on('did-finish-load', async () => { + if (loads === 2) { + process.exit(0); + } else { + loads++; + await mainWindow.webContents.executeJavaScript('addPaintWorklet()'); + await mainWindow.webContents.executeJavaScript('location.reload()'); + } + }); + + mainWindow.webContents.on('render-process-gone', () => { + process.exit(1); + }); + + await mainWindow.loadFile('index.html'); +} + +app.whenReady().then(() => { + createWindow(); + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit(); +}); diff --git a/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js b/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js new file mode 100644 index 0000000000000..3277dd5b70ded --- /dev/null +++ b/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js @@ -0,0 +1,20 @@ +/* global registerPaint */ + +class CheckerboardPainter { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + paint (ctx, geom, properties) { + const colors = ['red', 'green', 'blue']; + const size = 32; + for (let y = 0; y < (geom.height / size); y++) { + for (let x = 0; x < (geom.width / size); x++) { + const color = colors[(x + y) % colors.length]; + ctx.beginPath(); + ctx.fillStyle = color; + ctx.rect(x * size, y * size, size, size); + ctx.fill(); + } + } + } +} + +registerPaint('checkerboard', CheckerboardPainter); diff --git a/spec-main/fixtures/devtools-extensions/bad-manifest/manifest.json b/spec/fixtures/devtools-extensions/bad-manifest/manifest.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/bad-manifest/manifest.json rename to spec/fixtures/devtools-extensions/bad-manifest/manifest.json diff --git a/spec-main/fixtures/devtools-extensions/foo/_locales/en/messages.json b/spec/fixtures/devtools-extensions/foo/_locales/en/messages.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/_locales/en/messages.json rename to spec/fixtures/devtools-extensions/foo/_locales/en/messages.json diff --git a/spec-main/fixtures/devtools-extensions/foo/devtools.js b/spec/fixtures/devtools-extensions/foo/devtools.js similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/devtools.js rename to spec/fixtures/devtools-extensions/foo/devtools.js diff --git a/spec-main/fixtures/devtools-extensions/foo/foo.html b/spec/fixtures/devtools-extensions/foo/foo.html similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/foo.html rename to spec/fixtures/devtools-extensions/foo/foo.html diff --git a/spec-main/fixtures/devtools-extensions/foo/index.html b/spec/fixtures/devtools-extensions/foo/index.html similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/index.html rename to spec/fixtures/devtools-extensions/foo/index.html diff --git a/spec-main/fixtures/devtools-extensions/foo/manifest.json b/spec/fixtures/devtools-extensions/foo/manifest.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/manifest.json rename to spec/fixtures/devtools-extensions/foo/manifest.json diff --git a/spec-main/fixtures/devtools-extensions/foo/panel.js b/spec/fixtures/devtools-extensions/foo/panel.js similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/panel.js rename to spec/fixtures/devtools-extensions/foo/panel.js diff --git a/spec-main/fixtures/dogs-running.txt b/spec/fixtures/dogs-running.txt similarity index 100% rename from spec-main/fixtures/dogs-running.txt rename to spec/fixtures/dogs-running.txt diff --git a/spec/fixtures/esm/dynamic.mjs b/spec/fixtures/esm/dynamic.mjs new file mode 100644 index 0000000000000..32b6508d70ff7 --- /dev/null +++ b/spec/fixtures/esm/dynamic.mjs @@ -0,0 +1,4 @@ +const { app } = await import('electron'); +const { exitWithApp } = await import('./exit.mjs'); + +exitWithApp(app); diff --git a/spec/fixtures/esm/empty.html b/spec/fixtures/esm/empty.html new file mode 100644 index 0000000000000..40816a2b5a975 --- /dev/null +++ b/spec/fixtures/esm/empty.html @@ -0,0 +1 @@ +Hi \ No newline at end of file diff --git a/spec/fixtures/esm/entrypoint.mjs b/spec/fixtures/esm/entrypoint.mjs new file mode 100644 index 0000000000000..38617204fb28b --- /dev/null +++ b/spec/fixtures/esm/entrypoint.mjs @@ -0,0 +1,4 @@ +import * as electron from 'electron'; + +console.log('ESM Launch, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/esm/exit.mjs b/spec/fixtures/esm/exit.mjs new file mode 100644 index 0000000000000..6812d6df493fa --- /dev/null +++ b/spec/fixtures/esm/exit.mjs @@ -0,0 +1,4 @@ +export function exitWithApp (app) { + console.log('Exit with app, ready:', app.isReady()); + process.exit(0); +} diff --git a/spec/fixtures/esm/import-meta/index.html b/spec/fixtures/esm/import-meta/index.html new file mode 100644 index 0000000000000..6899ed0c0b2ed --- /dev/null +++ b/spec/fixtures/esm/import-meta/index.html @@ -0,0 +1,15 @@ + + + + + + + Hello World! + + +

Hello World!

+ We are using Node.js , + Chromium , + and Electron . + + diff --git a/spec/fixtures/esm/import-meta/main.mjs b/spec/fixtures/esm/import-meta/main.mjs new file mode 100644 index 0000000000000..7eb93c200e9ca --- /dev/null +++ b/spec/fixtures/esm/import-meta/main.mjs @@ -0,0 +1,34 @@ +import { app, BrowserWindow } from 'electron'; + +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +async function createWindow () { + const mainWindow = new BrowserWindow({ + show: false, + webPreferences: { + preload: fileURLToPath(new URL('preload.mjs', import.meta.url)), + sandbox: false, + contextIsolation: false + } + }); + + await mainWindow.loadFile('index.html'); + + const importMetaPreload = await mainWindow.webContents.executeJavaScript('window.importMetaPath'); + const expected = join(dirname(fileURLToPath(import.meta.url)), 'preload.mjs'); + + process.exit(importMetaPreload === expected ? 0 : 1); +} + +app.whenReady().then(() => { + createWindow(); + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit(); +}); diff --git a/spec/fixtures/esm/import-meta/package.json b/spec/fixtures/esm/import-meta/package.json new file mode 100644 index 0000000000000..13ef5537eb992 --- /dev/null +++ b/spec/fixtures/esm/import-meta/package.json @@ -0,0 +1,4 @@ +{ + "main": "main.mjs", + "type": "module" +} diff --git a/spec/fixtures/esm/import-meta/preload.mjs b/spec/fixtures/esm/import-meta/preload.mjs new file mode 100644 index 0000000000000..365d09c7135fe --- /dev/null +++ b/spec/fixtures/esm/import-meta/preload.mjs @@ -0,0 +1,3 @@ +import { fileURLToPath } from 'node:url'; + +window.importMetaPath = fileURLToPath(import.meta.url); diff --git a/spec/fixtures/esm/local.mjs b/spec/fixtures/esm/local.mjs new file mode 100644 index 0000000000000..8b6d60c5edc06 --- /dev/null +++ b/spec/fixtures/esm/local.mjs @@ -0,0 +1,3 @@ +export function add (a, b) { + return a + b; +}; diff --git a/spec/fixtures/esm/package/index.mjs b/spec/fixtures/esm/package/index.mjs new file mode 100644 index 0000000000000..08c3109ef016a --- /dev/null +++ b/spec/fixtures/esm/package/index.mjs @@ -0,0 +1,4 @@ +import * as electron from 'electron'; + +console.log('ESM Package Launch, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/esm/package/package.json b/spec/fixtures/esm/package/package.json new file mode 100644 index 0000000000000..84f117c275347 --- /dev/null +++ b/spec/fixtures/esm/package/package.json @@ -0,0 +1,4 @@ +{ + "main": "index.mjs", + "type": "module" +} diff --git a/spec/fixtures/esm/pre-app-ready-apis.mjs b/spec/fixtures/esm/pre-app-ready-apis.mjs new file mode 100644 index 0000000000000..5c815b5c74e9a --- /dev/null +++ b/spec/fixtures/esm/pre-app-ready-apis.mjs @@ -0,0 +1,9 @@ +import * as electron from 'electron'; + +try { + electron.app.disableHardwareAcceleration(); +} catch { + process.exit(1); +} + +process.exit(0); diff --git a/spec/fixtures/esm/top-level-await.mjs b/spec/fixtures/esm/top-level-await.mjs new file mode 100644 index 0000000000000..d18c33fa4560b --- /dev/null +++ b/spec/fixtures/esm/top-level-await.mjs @@ -0,0 +1,7 @@ +import * as electron from 'electron'; + +// Cheeky delay +await new Promise((resolve) => setTimeout(resolve, 500)); + +console.log('Top level await, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/extensions/chrome-action-fail/background.js b/spec/fixtures/extensions/chrome-action-fail/background.js new file mode 100644 index 0000000000000..d662e230555c8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/background.js @@ -0,0 +1,28 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'isEnabled': { + chrome.action.isEnabled(tabId).then(sendResponse); + break; + } + + case 'setIcon': { + chrome.action.setIcon({ tabId, imageData: {} }).then(sendResponse); + break; + } + + case 'getBadgeText': { + chrome.action.getBadgeText({ tabId }).then(sendResponse); + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-action-fail/main.js b/spec/fixtures/extensions/chrome-action-fail/main.js new file mode 100644 index 0000000000000..9c97da1dc34e5 --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/main.js @@ -0,0 +1,30 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const testMap = { + isEnabled () { + chrome.runtime.sendMessage({ method: 'isEnabled' }, response => { + console.log(JSON.stringify(response)); + }); + }, + setIcon () { + chrome.runtime.sendMessage({ method: 'setIcon' }, response => { + console.log(JSON.stringify(response)); + }); + }, + getBadgeText () { + chrome.runtime.sendMessage({ method: 'getBadgeText' }, response => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-action-fail/manifest.json b/spec/fixtures/extensions/chrome-action-fail/manifest.json new file mode 100644 index 0000000000000..d1041d47ac802 --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Action popup demo", + "version": "1.0", + "manifest_version": 3, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "action": { + "default_title": "Click Me", + "default_popup": "popup.html" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-action-fail/popup.html b/spec/fixtures/extensions/chrome-action-fail/popup.html new file mode 100644 index 0000000000000..d5865f3c0cffd --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/popup.html @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/spec-main/fixtures/extensions/chrome-api/background.js b/spec/fixtures/extensions/chrome-api/background.js similarity index 100% rename from spec-main/fixtures/extensions/chrome-api/background.js rename to spec/fixtures/extensions/chrome-api/background.js diff --git a/spec/fixtures/extensions/chrome-api/main.js b/spec/fixtures/extensions/chrome-api/main.js new file mode 100644 index 0000000000000..e24784d9fbeac --- /dev/null +++ b/spec/fixtures/extensions/chrome-api/main.js @@ -0,0 +1,53 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + sendResponse(message); +}); + +const testMap = { + connect () { + let success = false; + try { + chrome.runtime.connect(chrome.runtime.id); + chrome.runtime.connect(chrome.runtime.id, { name: 'content-script' }); + chrome.runtime.connect({ name: 'content-script' }); + success = true; + } finally { + console.log(JSON.stringify(success)); + } + }, + getManifest () { + const manifest = chrome.runtime.getManifest(); + console.log(JSON.stringify(manifest)); + }, + sendMessage (message) { + chrome.runtime.sendMessage({ method: 'sendMessage', args: [message] }, response => { + console.log(JSON.stringify(response)); + }); + }, + executeScript (code) { + chrome.runtime.sendMessage({ method: 'executeScript', args: [code] }, response => { + console.log(JSON.stringify(response)); + }); + }, + connectTab (name) { + chrome.runtime.onConnect.addListener(port => { + port.onMessage.addListener(message => { + console.log([port.name, message].join()); + }); + }); + chrome.runtime.sendMessage({ method: 'connectTab', args: [name] }); + }, + update (tabId, props) { + chrome.runtime.sendMessage({ method: 'update', args: [tabId, props] }, response => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec-main/fixtures/extensions/chrome-api/manifest.json b/spec/fixtures/extensions/chrome-api/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-api/manifest.json rename to spec/fixtures/extensions/chrome-api/manifest.json diff --git a/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json b/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json new file mode 100644 index 0000000000000..5b784b3e25da8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json @@ -0,0 +1,6 @@ +{ + "extName": { + "message": "chrome-i18n", + "description": "Extension name." + } +} diff --git a/spec/fixtures/extensions/chrome-i18n/v2/main.js b/spec/fixtures/extensions/chrome-i18n/v2/main.js new file mode 100644 index 0000000000000..7508b056a2daa --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v2/main.js @@ -0,0 +1,33 @@ +/* global chrome */ + +function evalInMainWorld (fn) { + const script = document.createElement('script'); + script.textContent = `((${fn})())`; + document.documentElement.appendChild(script); +} + +async function exec (name) { + let result; + switch (name) { + case 'getMessage': + result = { + id: chrome.i18n.getMessage('@@extension_id'), + name: chrome.i18n.getMessage('extName') + }; + break; + case 'getAcceptLanguages': + result = await new Promise(resolve => chrome.i18n.getAcceptLanguages(resolve)); + break; + } + + const funcStr = `() => { require('electron').ipcRenderer.send('success', ${JSON.stringify(result)}) }`; + evalInMainWorld(funcStr); +} + +window.addEventListener('message', event => { + exec(event.data.name); +}); + +evalInMainWorld(() => { + window.exec = name => window.postMessage({ name }); +}); diff --git a/spec-main/fixtures/extensions/chrome-i18n/manifest.json b/spec/fixtures/extensions/chrome-i18n/v2/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-i18n/manifest.json rename to spec/fixtures/extensions/chrome-i18n/v2/manifest.json diff --git a/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json b/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json new file mode 100644 index 0000000000000..088a39cc522d8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json @@ -0,0 +1,6 @@ +{ + "extName": { + "message": "Hola mundo!!", + "description": "Nombre de extensión" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-i18n/v3/main.js b/spec/fixtures/extensions/chrome-i18n/v3/main.js new file mode 100644 index 0000000000000..3d0c389d6fdcf --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/main.js @@ -0,0 +1,36 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const map = { + getAcceptLanguages () { + chrome.i18n.getAcceptLanguages().then((languages) => { + console.log(JSON.stringify(languages)); + }); + }, + getMessage () { + const message = chrome.i18n.getMessage('extName'); + console.log(JSON.stringify(message)); + }, + getUILanguage () { + const language = chrome.i18n.getUILanguage(); + console.log(JSON.stringify(language)); + }, + async detectLanguage (texts) { + const result = []; + for (const text of texts) { + const language = await chrome.i18n.detectLanguage(text); + result.push(language); + } + console.log(JSON.stringify(result)); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + map[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-i18n/v3/manifest.json b/spec/fixtures/extensions/chrome-i18n/v3/manifest.json new file mode 100644 index 0000000000000..e7ae09d39b405 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "chrome-i18n", + "version": "1.0", + "default_locale": "es", + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "manifest_version": 3 +} diff --git a/spec-main/fixtures/extensions/chrome-runtime/background.js b/spec/fixtures/extensions/chrome-runtime/background.js similarity index 100% rename from spec-main/fixtures/extensions/chrome-runtime/background.js rename to spec/fixtures/extensions/chrome-runtime/background.js diff --git a/spec/fixtures/extensions/chrome-runtime/main.js b/spec/fixtures/extensions/chrome-runtime/main.js new file mode 100644 index 0000000000000..f1e0f8da9a907 --- /dev/null +++ b/spec/fixtures/extensions/chrome-runtime/main.js @@ -0,0 +1,39 @@ +/* global chrome */ + +function evalInMainWorld (fn) { + const script = document.createElement('script'); + script.textContent = `((${fn})())`; + document.documentElement.appendChild(script); +} + +async function exec (name) { + let result; + switch (name) { + case 'getManifest': + result = chrome.runtime.getManifest(); + break; + case 'id': + result = chrome.runtime.id; + break; + case 'getURL': + result = chrome.runtime.getURL('main.js'); + break; + case 'getPlatformInfo': { + result = await new Promise(resolve => { + chrome.runtime.sendMessage(name, resolve); + }); + break; + } + } + + const funcStr = `() => { require('electron').ipcRenderer.send('success', ${JSON.stringify(result)}) }`; + evalInMainWorld(funcStr); +} + +window.addEventListener('message', event => { + exec(event.data.name); +}); + +evalInMainWorld(() => { + window.exec = name => window.postMessage({ name }); +}); diff --git a/spec-main/fixtures/extensions/chrome-runtime/manifest.json b/spec/fixtures/extensions/chrome-runtime/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-runtime/manifest.json rename to spec/fixtures/extensions/chrome-runtime/manifest.json diff --git a/spec/fixtures/extensions/chrome-scripting/background.js b/spec/fixtures/extensions/chrome-scripting/background.js new file mode 100644 index 0000000000000..53a02b1065d0d --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/background.js @@ -0,0 +1,72 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'executeScript': { + chrome.scripting.executeScript({ + target: { tabId }, + function: () => { + document.title = 'HEY HEY HEY'; + return document.title; + } + }).then(() => { + console.log('success'); + }).catch((err) => { + console.log('error', err); + }); + break; + } + + case 'globalParams' : { + await chrome.scripting.executeScript({ + target: { tabId }, + func: () => { + chrome.scripting.globalParams.changed = true; + }, + world: 'ISOLATED' + }); + + const results = await chrome.scripting.executeScript({ + target: { tabId }, + func: () => JSON.stringify(chrome.scripting.globalParams), + world: 'ISOLATED' + }); + + const result = JSON.parse(results[0].result); + + sendResponse(result); + break; + } + + case 'registerContentScripts': { + await chrome.scripting.registerContentScripts([{ + id: 'session-script', + js: ['content.js'], + persistAcrossSessions: false, + matches: [''], + runAt: 'document_start' + }]); + + chrome.scripting.getRegisteredContentScripts().then(sendResponse); + break; + } + + case 'insertCSS': { + chrome.scripting.insertCSS({ + target: { tabId }, + css: 'body { background-color: red; }' + }).then(() => { + sendResponse({ success: true }); + }); + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/docs/fiddles/media/screenshot/.keep b/spec/fixtures/extensions/chrome-scripting/content.js similarity index 100% rename from docs/fiddles/media/screenshot/.keep rename to spec/fixtures/extensions/chrome-scripting/content.js diff --git a/spec/fixtures/extensions/chrome-scripting/main.js b/spec/fixtures/extensions/chrome-scripting/main.js new file mode 100644 index 0000000000000..9528d572976f5 --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/main.js @@ -0,0 +1,35 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const map = { + executeScript () { + chrome.runtime.sendMessage({ method: 'executeScript' }, response => { + console.log(JSON.stringify(response)); + }); + }, + registerContentScripts () { + chrome.runtime.sendMessage({ method: 'registerContentScripts' }, response => { + console.log(JSON.stringify(response)); + }); + }, + insertCSS () { + chrome.runtime.sendMessage({ method: 'insertCSS' }, response => { + console.log(JSON.stringify(response)); + }); + }, + globalParams () { + chrome.runtime.sendMessage({ method: 'globalParams' }, response => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + map[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-scripting/manifest.json b/spec/fixtures/extensions/chrome-scripting/manifest.json new file mode 100644 index 0000000000000..54620e70b8597 --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "execute-script", + "version": "1.0", + "permissions": [ + "scripting" + ], + "host_permissions": [""], + "content_scripts": [{ + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + }], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-storage/main.js b/spec/fixtures/extensions/chrome-storage/main.js new file mode 100644 index 0000000000000..dbe26e6f0e329 --- /dev/null +++ b/spec/fixtures/extensions/chrome-storage/main.js @@ -0,0 +1,8 @@ +/* global chrome */ +chrome.storage.local.set({ key: 'value' }, () => { + chrome.storage.local.get(['key'], ({ key }) => { + const script = document.createElement('script'); + script.textContent = `require('electron').ipcRenderer.send('storage-success', ${JSON.stringify(key)})`; + document.documentElement.appendChild(script); + }); +}); diff --git a/spec-main/fixtures/extensions/chrome-storage/manifest.json b/spec/fixtures/extensions/chrome-storage/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-storage/manifest.json rename to spec/fixtures/extensions/chrome-storage/manifest.json diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/background.js b/spec/fixtures/extensions/chrome-tabs/api-async/background.js new file mode 100644 index 0000000000000..5b6a0d1b9e822 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/background.js @@ -0,0 +1,70 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method, args = [] } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'getZoom': { + chrome.tabs.getZoom(tabId).then(sendResponse); + break; + } + + case 'setZoom': { + const [zoom] = args; + chrome.tabs.setZoom(tabId, zoom).then(async () => { + const updatedZoom = await chrome.tabs.getZoom(tabId); + sendResponse(updatedZoom); + }); + break; + } + + case 'getZoomSettings': { + chrome.tabs.getZoomSettings(tabId).then(sendResponse); + break; + } + + case 'setZoomSettings': { + const [settings] = args; + chrome.tabs.setZoomSettings(tabId, { mode: settings.mode }).then(async () => { + const zoomSettings = await chrome.tabs.getZoomSettings(tabId); + sendResponse(zoomSettings); + }); + break; + } + + case 'get': { + chrome.tabs.get(tabId).then(sendResponse); + break; + } + + case 'query': { + const [params] = args; + chrome.tabs.query(params).then(sendResponse); + break; + } + + case 'reload': { + chrome.tabs.reload(tabId).then(() => { + sendResponse({ status: 'reloaded' }); + }); + break; + } + + case 'update': { + const [params] = args; + try { + const response = await chrome.tabs.update(tabId, params); + sendResponse(response); + } catch (error) { + sendResponse({ error: error.message }); + } + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/main.js b/spec/fixtures/extensions/chrome-tabs/api-async/main.js new file mode 100644 index 0000000000000..91030070bc018 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/main.js @@ -0,0 +1,55 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const testMap = { + getZoomSettings () { + chrome.runtime.sendMessage({ method: 'getZoomSettings' }, response => { + console.log(JSON.stringify(response)); + }); + }, + setZoomSettings (settings) { + chrome.runtime.sendMessage({ method: 'setZoomSettings', args: [settings] }, response => { + console.log(JSON.stringify(response)); + }); + }, + query (params) { + chrome.runtime.sendMessage({ method: 'query', args: [params] }, response => { + console.log(JSON.stringify(response)); + }); + }, + getZoom () { + chrome.runtime.sendMessage({ method: 'getZoom', args: [] }, response => { + console.log(JSON.stringify(response)); + }); + }, + setZoom (zoom) { + chrome.runtime.sendMessage({ method: 'setZoom', args: [zoom] }, response => { + console.log(JSON.stringify(response)); + }); + }, + get () { + chrome.runtime.sendMessage({ method: 'get' }, response => { + console.log(JSON.stringify(response)); + }); + }, + reload () { + chrome.runtime.sendMessage({ method: 'reload' }, response => { + console.log(JSON.stringify(response)); + }); + }, + update (params) { + chrome.runtime.sendMessage({ method: 'update', args: [params] }, response => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json b/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json new file mode 100644 index 0000000000000..d0a208cd06fcf --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json @@ -0,0 +1,16 @@ +{ + "name": "api-async", + "version": "1.0", + "content_scripts": [ + { + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "permissions": ["tabs"], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js b/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js new file mode 100644 index 0000000000000..d586b455a1cc1 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js @@ -0,0 +1,6 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((_request, sender, sendResponse) => { + chrome.tabs.get(sender.tab.id).then(sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js b/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js new file mode 100644 index 0000000000000..cc121154876ff --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js @@ -0,0 +1,11 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +window.addEventListener('message', () => { + chrome.runtime.sendMessage({}, response => { + console.log(JSON.stringify(response)); + }); +}, false); diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json b/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json new file mode 100644 index 0000000000000..f920c8bc0e20a --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "no-privileges", + "version": "1.0", + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-webRequest-wss/background.js b/spec/fixtures/extensions/chrome-webRequest-wss/background.js new file mode 100644 index 0000000000000..80c92dde34290 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest-wss/background.js @@ -0,0 +1,12 @@ +/* global chrome */ + +chrome.webRequest.onBeforeSendHeaders.addListener( + (details) => { + if (details.requestHeaders) { + details.requestHeaders.foo = 'bar'; + } + return { cancel: false, requestHeaders: details.requestHeaders }; + }, + { urls: ['*://127.0.0.1:*/'] }, + ['blocking'] +); diff --git a/spec-main/fixtures/extensions/chrome-webRequest-wss/manifest.json b/spec/fixtures/extensions/chrome-webRequest-wss/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-webRequest-wss/manifest.json rename to spec/fixtures/extensions/chrome-webRequest-wss/manifest.json diff --git a/spec/fixtures/extensions/chrome-webRequest/background.js b/spec/fixtures/extensions/chrome-webRequest/background.js new file mode 100644 index 0000000000000..fb2d2a472a5f7 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest/background.js @@ -0,0 +1,10 @@ +/* global chrome */ + +chrome.webRequest.onBeforeRequest.addListener( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (details) => { + return { cancel: true }; + }, + { urls: ['*://127.0.0.1:*/'] }, + ['blocking'] +); diff --git a/spec-main/fixtures/extensions/chrome-webRequest/manifest.json b/spec/fixtures/extensions/chrome-webRequest/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-webRequest/manifest.json rename to spec/fixtures/extensions/chrome-webRequest/manifest.json diff --git a/spec-main/fixtures/extensions/content-script-document-end/end.js b/spec/fixtures/extensions/content-script-document-end/end.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-end/end.js rename to spec/fixtures/extensions/content-script-document-end/end.js diff --git a/spec/fixtures/extensions/content-script-document-end/manifest.json b/spec/fixtures/extensions/content-script-document-end/manifest.json new file mode 100644 index 0000000000000..cd2ce51be9d7b --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-end/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-end", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["end.js"], + "run_at": "document_end" + } + ], + "manifest_version": 2 +} diff --git a/spec-main/fixtures/extensions/content-script-document-idle/idle.js b/spec/fixtures/extensions/content-script-document-idle/idle.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-idle/idle.js rename to spec/fixtures/extensions/content-script-document-idle/idle.js diff --git a/spec/fixtures/extensions/content-script-document-idle/manifest.json b/spec/fixtures/extensions/content-script-document-idle/manifest.json new file mode 100644 index 0000000000000..bd2bb5fcebca3 --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-idle/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-idle", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["idle.js"], + "run_at": "document_idle" + } + ], + "manifest_version": 2 +} diff --git a/spec/fixtures/extensions/content-script-document-start/manifest.json b/spec/fixtures/extensions/content-script-document-start/manifest.json new file mode 100644 index 0000000000000..9b58263d1fe6d --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-start/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-start", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["start.js"], + "run_at": "document_start" + } + ], + "manifest_version": 2 +} diff --git a/spec-main/fixtures/extensions/content-script-document-start/start.js b/spec/fixtures/extensions/content-script-document-start/start.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-start/start.js rename to spec/fixtures/extensions/content-script-document-start/start.js diff --git a/spec-main/fixtures/extensions/content-script/all_frames-disabled.css b/spec/fixtures/extensions/content-script/all_frames-disabled.css similarity index 100% rename from spec-main/fixtures/extensions/content-script/all_frames-disabled.css rename to spec/fixtures/extensions/content-script/all_frames-disabled.css diff --git a/spec-main/fixtures/extensions/content-script/all_frames-enabled.css b/spec/fixtures/extensions/content-script/all_frames-enabled.css similarity index 100% rename from spec-main/fixtures/extensions/content-script/all_frames-enabled.css rename to spec/fixtures/extensions/content-script/all_frames-enabled.css diff --git a/spec-main/fixtures/extensions/content-script/all_frames-preload.js b/spec/fixtures/extensions/content-script/all_frames-preload.js similarity index 100% rename from spec-main/fixtures/extensions/content-script/all_frames-preload.js rename to spec/fixtures/extensions/content-script/all_frames-preload.js diff --git a/spec-main/fixtures/extensions/content-script/frame-with-frame.html b/spec/fixtures/extensions/content-script/frame-with-frame.html similarity index 100% rename from spec-main/fixtures/extensions/content-script/frame-with-frame.html rename to spec/fixtures/extensions/content-script/frame-with-frame.html diff --git a/spec-main/fixtures/extensions/content-script/frame.html b/spec/fixtures/extensions/content-script/frame.html similarity index 100% rename from spec-main/fixtures/extensions/content-script/frame.html rename to spec/fixtures/extensions/content-script/frame.html diff --git a/spec-main/fixtures/extensions/content-script/manifest.json b/spec/fixtures/extensions/content-script/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/content-script/manifest.json rename to spec/fixtures/extensions/content-script/manifest.json diff --git a/spec-main/fixtures/extensions/devtools-extension/foo.html b/spec/fixtures/extensions/devtools-extension/foo.html similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/foo.html rename to spec/fixtures/extensions/devtools-extension/foo.html diff --git a/spec/fixtures/extensions/devtools-extension/foo.js b/spec/fixtures/extensions/devtools-extension/foo.js new file mode 100644 index 0000000000000..30ba014abc5ca --- /dev/null +++ b/spec/fixtures/extensions/devtools-extension/foo.js @@ -0,0 +1,2 @@ +/* global chrome */ +chrome.devtools.panels.create('Foo', 'icon.png', 'index.html'); diff --git a/spec-main/fixtures/extensions/devtools-extension/index.html b/spec/fixtures/extensions/devtools-extension/index.html similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/index.html rename to spec/fixtures/extensions/devtools-extension/index.html diff --git a/spec/fixtures/extensions/devtools-extension/index.js b/spec/fixtures/extensions/devtools-extension/index.js new file mode 100644 index 0000000000000..ff0c1cb69c457 --- /dev/null +++ b/spec/fixtures/extensions/devtools-extension/index.js @@ -0,0 +1,4 @@ +/* global chrome */ +chrome.devtools.inspectedWindow.eval('require("electron").ipcRenderer.send("winning")', (result, exc) => { + console.log(result, exc); +}); diff --git a/spec-main/fixtures/extensions/devtools-extension/manifest.json b/spec/fixtures/extensions/devtools-extension/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/manifest.json rename to spec/fixtures/extensions/devtools-extension/manifest.json diff --git a/spec/fixtures/extensions/host-permissions/malformed/manifest.json b/spec/fixtures/extensions/host-permissions/malformed/manifest.json new file mode 100644 index 0000000000000..0e4ce8c20271e --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/malformed/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "malformed", + "version": "0.1", + "manifest_version": 3, + "description": "Extension with invalid host_permissions", + "host_permissions": [ + "malformed_host" + ] +} \ No newline at end of file diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js b/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js new file mode 100644 index 0000000000000..7725abe038b66 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js @@ -0,0 +1,6 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((_request, _sender, sendResponse) => { + chrome.tabs.query({}).then(sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js b/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js new file mode 100644 index 0000000000000..2e9cd5b5d9d91 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js @@ -0,0 +1,11 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { + sendResponse(request); +}); + +window.addEventListener('message', () => { + chrome.runtime.sendMessage({ method: 'query' }, response => { + console.log(JSON.stringify(response)); + }); +}, false); diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json b/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json new file mode 100644 index 0000000000000..55dfe2696d740 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "privileged-tab-info", + "version": "0.1", + "manifest_version": 3, + "content_scripts": [{ + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + }], + "host_permissions": ["http://*/*"], + "background": { + "service_worker": "background.js" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/lazy-background-page/background.js b/spec/fixtures/extensions/lazy-background-page/background.js new file mode 100644 index 0000000000000..a954e7fa882e0 --- /dev/null +++ b/spec/fixtures/extensions/lazy-background-page/background.js @@ -0,0 +1,5 @@ +/* global chrome */ +chrome.runtime.onMessage.addListener((message, sender, reply) => { + window.receivedMessage = message; + reply({ message, sender }); +}); diff --git a/spec-main/fixtures/extensions/lazy-background-page/content_script.js b/spec/fixtures/extensions/lazy-background-page/content_script.js similarity index 90% rename from spec-main/fixtures/extensions/lazy-background-page/content_script.js rename to spec/fixtures/extensions/lazy-background-page/content_script.js index f8f0bf6f8a510..938c908e44a2b 100644 --- a/spec-main/fixtures/extensions/lazy-background-page/content_script.js +++ b/spec/fixtures/extensions/lazy-background-page/content_script.js @@ -1,4 +1,4 @@ -/* eslint-disable no-undef */ +/* global chrome */ chrome.runtime.sendMessage({ some: 'message' }, (response) => { const script = document.createElement('script'); script.textContent = `require('electron').ipcRenderer.send('bg-page-message-response', ${JSON.stringify(response)})`; diff --git a/spec-main/fixtures/extensions/lazy-background-page/get-background-page.js b/spec/fixtures/extensions/lazy-background-page/get-background-page.js similarity index 77% rename from spec-main/fixtures/extensions/lazy-background-page/get-background-page.js rename to spec/fixtures/extensions/lazy-background-page/get-background-page.js index a54c8391f513e..10aeab0cdfca4 100644 --- a/spec-main/fixtures/extensions/lazy-background-page/get-background-page.js +++ b/spec/fixtures/extensions/lazy-background-page/get-background-page.js @@ -2,6 +2,6 @@ window.completionPromise = new Promise((resolve) => { window.completionPromiseResolve = resolve; }); -chrome.runtime.sendMessage({ some: 'message' }, (response) => { +chrome.runtime.sendMessage({ some: 'message' }, () => { window.completionPromiseResolve(chrome.extension.getBackgroundPage().receivedMessage); }); diff --git a/spec-main/fixtures/extensions/lazy-background-page/manifest.json b/spec/fixtures/extensions/lazy-background-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/manifest.json rename to spec/fixtures/extensions/lazy-background-page/manifest.json diff --git a/spec-main/fixtures/extensions/lazy-background-page/page-get-background.html b/spec/fixtures/extensions/lazy-background-page/page-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/page-get-background.html rename to spec/fixtures/extensions/lazy-background-page/page-get-background.html diff --git a/spec-main/fixtures/extensions/lazy-background-page/page-runtime-get-background.html b/spec/fixtures/extensions/lazy-background-page/page-runtime-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/page-runtime-get-background.html rename to spec/fixtures/extensions/lazy-background-page/page-runtime-get-background.html diff --git a/spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js b/spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js similarity index 79% rename from spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js rename to spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js index 59716d5501dd4..199476999c64a 100644 --- a/spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js +++ b/spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js @@ -2,7 +2,7 @@ window.completionPromise = new Promise((resolve) => { window.completionPromiseResolve = resolve; }); -chrome.runtime.sendMessage({ some: 'message' }, (response) => { +chrome.runtime.sendMessage({ some: 'message' }, () => { chrome.runtime.getBackgroundPage((bgPage) => { window.completionPromiseResolve(bgPage.receivedMessage); }); diff --git a/spec-main/fixtures/extensions/load-error/manifest.json b/spec/fixtures/extensions/load-error/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/load-error/manifest.json rename to spec/fixtures/extensions/load-error/manifest.json diff --git a/spec/fixtures/extensions/minimum-chrome-version/main.js b/spec/fixtures/extensions/minimum-chrome-version/main.js new file mode 100644 index 0000000000000..d58117c501c1e --- /dev/null +++ b/spec/fixtures/extensions/minimum-chrome-version/main.js @@ -0,0 +1 @@ +document.documentElement.style.backgroundColor = 'blue'; diff --git a/spec/fixtures/extensions/minimum-chrome-version/manifest.json b/spec/fixtures/extensions/minimum-chrome-version/manifest.json new file mode 100644 index 0000000000000..c65bced2f5f38 --- /dev/null +++ b/spec/fixtures/extensions/minimum-chrome-version/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "chrome-too-low-version", + "version": "1.0", + "minimum_chrome_version": "999", + "content_scripts": [ + { + "matches": [""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "permissions": ["storage"], + "manifest_version": 3 +} diff --git a/spec-main/fixtures/extensions/missing-manifest/main.js b/spec/fixtures/extensions/missing-manifest/main.js similarity index 100% rename from spec-main/fixtures/extensions/missing-manifest/main.js rename to spec/fixtures/extensions/missing-manifest/main.js diff --git a/spec/fixtures/extensions/mv3-service-worker/background.js b/spec/fixtures/extensions/mv3-service-worker/background.js new file mode 100644 index 0000000000000..411f03f8fbbb4 --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/background.js @@ -0,0 +1,7 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message === 'fetch-confirmation') { + sendResponse({ message: 'Hello from background.js' }); + } +}); diff --git a/spec/fixtures/extensions/mv3-service-worker/main.js b/spec/fixtures/extensions/mv3-service-worker/main.js new file mode 100644 index 0000000000000..c7a37cd155bbf --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/main.js @@ -0,0 +1,13 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + sendResponse(message); +}); + +window.addEventListener('message', (event) => { + if (event.data === 'fetch-confirmation') { + chrome.runtime.sendMessage('fetch-confirmation', response => { + console.log(JSON.stringify(response)); + }); + } +}, false); diff --git a/spec/fixtures/extensions/mv3-service-worker/manifest.json b/spec/fixtures/extensions/mv3-service-worker/manifest.json new file mode 100644 index 0000000000000..e18a207e45cb9 --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/manifest.json @@ -0,0 +1,20 @@ +{ + "name": "MV3 Service Worker", + "description": "Test for extension service worker support.", + "version": "1.0", + "manifest_version": 3, + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "background": { + "service_worker": "background.js" + } +} diff --git a/docs/fiddles/menus/customize-menus/.keep b/spec/fixtures/extensions/persistent-background-page/background.js similarity index 100% rename from docs/fiddles/menus/customize-menus/.keep rename to spec/fixtures/extensions/persistent-background-page/background.js diff --git a/spec-main/fixtures/extensions/persistent-background-page/manifest.json b/spec/fixtures/extensions/persistent-background-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/persistent-background-page/manifest.json rename to spec/fixtures/extensions/persistent-background-page/manifest.json diff --git a/spec-main/fixtures/extensions/red-bg/main.js b/spec/fixtures/extensions/red-bg/main.js similarity index 100% rename from spec-main/fixtures/extensions/red-bg/main.js rename to spec/fixtures/extensions/red-bg/main.js diff --git a/spec-main/fixtures/extensions/red-bg/manifest.json b/spec/fixtures/extensions/red-bg/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/red-bg/manifest.json rename to spec/fixtures/extensions/red-bg/manifest.json diff --git a/spec-main/fixtures/extensions/ui-page/bare-page.html b/spec/fixtures/extensions/ui-page/bare-page.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/bare-page.html rename to spec/fixtures/extensions/ui-page/bare-page.html diff --git a/spec-main/fixtures/extensions/ui-page/manifest.json b/spec/fixtures/extensions/ui-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/ui-page/manifest.json rename to spec/fixtures/extensions/ui-page/manifest.json diff --git a/spec-main/fixtures/extensions/ui-page/page-get-background.html b/spec/fixtures/extensions/ui-page/page-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/page-get-background.html rename to spec/fixtures/extensions/ui-page/page-get-background.html diff --git a/spec-main/fixtures/extensions/ui-page/page-script-load.html b/spec/fixtures/extensions/ui-page/page-script-load.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/page-script-load.html rename to spec/fixtures/extensions/ui-page/page-script-load.html diff --git a/spec-main/fixtures/extensions/ui-page/script.js b/spec/fixtures/extensions/ui-page/script.js similarity index 100% rename from spec-main/fixtures/extensions/ui-page/script.js rename to spec/fixtures/extensions/ui-page/script.js diff --git a/spec/fixtures/file-system/test-writable.html b/spec/fixtures/file-system/test-writable.html new file mode 100644 index 0000000000000..6d7012192b143 --- /dev/null +++ b/spec/fixtures/file-system/test-writable.html @@ -0,0 +1,26 @@ + + + + + + Hello World! + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/file-system/test.txt b/spec/fixtures/file-system/test.txt new file mode 100644 index 0000000000000..95d09f2b10159 --- /dev/null +++ b/spec/fixtures/file-system/test.txt @@ -0,0 +1 @@ +hello world \ No newline at end of file diff --git a/spec/fixtures/hello.txt b/spec/fixtures/hello.txt new file mode 100644 index 0000000000000..3b18e512dba79 --- /dev/null +++ b/spec/fixtures/hello.txt @@ -0,0 +1 @@ +hello world diff --git a/spec/fixtures/module/asar.js b/spec/fixtures/module/asar.js index 6a973ad386045..7b196e533943f 100644 --- a/spec/fixtures/module/asar.js +++ b/spec/fixtures/module/asar.js @@ -1,4 +1,5 @@ -const fs = require('fs'); +const fs = require('node:fs'); + process.on('message', function (file) { process.send(fs.readFileSync(file).toString()); }); diff --git a/spec/fixtures/module/check-arguments.js b/spec/fixtures/module/check-arguments.js index 8a5ef8dde197d..dccbe2d314b04 100644 --- a/spec/fixtures/module/check-arguments.js +++ b/spec/fixtures/module/check-arguments.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + window.onload = function () { ipcRenderer.send('answer', process.argv); }; diff --git a/spec/fixtures/module/create_socket.js b/spec/fixtures/module/create_socket.js index d5eca125a541e..abcc0e66be20d 100644 --- a/spec/fixtures/module/create_socket.js +++ b/spec/fixtures/module/create_socket.js @@ -1,4 +1,5 @@ -const net = require('net'); +const net = require('node:net'); + const server = net.createServer(function () {}); server.listen(process.argv[2]); process.exit(0); diff --git a/spec-main/fixtures/module/declare-buffer.js b/spec/fixtures/module/declare-buffer.js similarity index 100% rename from spec-main/fixtures/module/declare-buffer.js rename to spec/fixtures/module/declare-buffer.js diff --git a/spec-main/fixtures/module/declare-global.js b/spec/fixtures/module/declare-global.js similarity index 100% rename from spec-main/fixtures/module/declare-global.js rename to spec/fixtures/module/declare-global.js diff --git a/spec-main/fixtures/module/declare-process.js b/spec/fixtures/module/declare-process.js similarity index 100% rename from spec-main/fixtures/module/declare-process.js rename to spec/fixtures/module/declare-process.js diff --git a/spec-main/fixtures/module/echo-renamed.js b/spec/fixtures/module/echo-renamed.js similarity index 87% rename from spec-main/fixtures/module/echo-renamed.js rename to spec/fixtures/module/echo-renamed.js index 6dfa05f914a3c..d81f922c21f67 100644 --- a/spec-main/fixtures/module/echo-renamed.js +++ b/spec/fixtures/module/echo-renamed.js @@ -1,7 +1,7 @@ let echo; try { echo = require('@electron-ci/echo'); -} catch (e) { +} catch { process.exit(1); } process.exit(echo(0)); diff --git a/spec-main/fixtures/module/echo.js b/spec/fixtures/module/echo.js similarity index 99% rename from spec-main/fixtures/module/echo.js rename to spec/fixtures/module/echo.js index ae1b31dd9bed9..56ba812a0d994 100644 --- a/spec-main/fixtures/module/echo.js +++ b/spec/fixtures/module/echo.js @@ -3,4 +3,5 @@ process.on('uncaughtException', function (err) { }); const echo = require('@electron-ci/echo'); + process.send(echo('ok')); diff --git a/spec/fixtures/module/fork_ping.js b/spec/fixtures/module/fork_ping.js index e9b28bde1d61c..857211280d23c 100644 --- a/spec/fixtures/module/fork_ping.js +++ b/spec/fixtures/module/fork_ping.js @@ -1,10 +1,12 @@ -const path = require('path'); +const childProcess = require('node:child_process'); +const path = require('node:path'); process.on('uncaughtException', function (error) { process.send(error.stack); }); -const child = require('child_process').fork(path.join(__dirname, '/ping.js')); +const child = childProcess.fork(path.join(__dirname, '/ping.js')); + process.on('message', function (msg) { child.send(msg); }); diff --git a/spec/fixtures/module/inspector-binding.js b/spec/fixtures/module/inspector-binding.js index 64a5986e8c75a..4c4aa708ae0cb 100644 --- a/spec/fixtures/module/inspector-binding.js +++ b/spec/fixtures/module/inspector-binding.js @@ -1,6 +1,6 @@ -const inspector = require('inspector'); -const path = require('path'); -const { pathToFileURL } = require('url'); +const inspector = require('node:inspector'); +const path = require('node:path'); +const { pathToFileURL } = require('node:url'); // This test case will set a breakpoint 4 lines below function debuggedFunction () { diff --git a/spec/fixtures/module/isolated-ping.js b/spec/fixtures/module/isolated-ping.js index 90392e46fe4de..e7d5980d53566 100644 --- a/spec/fixtures/module/isolated-ping.js +++ b/spec/fixtures/module/isolated-ping.js @@ -1,2 +1,3 @@ const { ipcRenderer } = require('electron'); + ipcRenderer.send('pong'); diff --git a/spec/fixtures/module/module-paths.js b/spec/fixtures/module/module-paths.js new file mode 100644 index 0000000000000..fc5d6cb1ca91b --- /dev/null +++ b/spec/fixtures/module/module-paths.js @@ -0,0 +1,3 @@ +const Module = require('node:module'); + +process.send(Module._nodeModulePaths(process.resourcesPath + '/test.js')); diff --git a/spec/fixtures/module/no-asar.js b/spec/fixtures/module/no-asar.js index 8835a22c42d1e..0835fea403b01 100644 --- a/spec/fixtures/module/no-asar.js +++ b/spec/fixtures/module/no-asar.js @@ -1,5 +1,5 @@ -const fs = require('fs'); -const path = require('path'); +const fs = require('node:fs'); +const path = require('node:path'); const stats = fs.statSync(path.join(__dirname, '..', 'test.asar', 'a.asar')); diff --git a/spec/fixtures/module/preload-context.js b/spec/fixtures/module/preload-context.js index 4dbc3a9a58d3b..cdbee53986943 100644 --- a/spec/fixtures/module/preload-context.js +++ b/spec/fixtures/module/preload-context.js @@ -1,4 +1,4 @@ -var test = 'test' // eslint-disable-line +var test = 'test'; // eslint-disable-line no-var,@typescript-eslint/no-unused-vars const types = { require: typeof require, diff --git a/spec/fixtures/module/preload-eventemitter.js b/spec/fixtures/module/preload-eventemitter.js new file mode 100644 index 0000000000000..e0c74a97b7bcc --- /dev/null +++ b/spec/fixtures/module/preload-eventemitter.js @@ -0,0 +1,11 @@ +(function () { + const { EventEmitter } = require('node:events'); + const emitter = new EventEmitter(); + const rendererEventEmitterProperties = []; + let currentObj = emitter; + do { + rendererEventEmitterProperties.push(...Object.getOwnPropertyNames(currentObj)); + } while ((currentObj = Object.getPrototypeOf(currentObj))); + const { ipcRenderer } = require('electron'); + ipcRenderer.send('answer', rendererEventEmitterProperties); +})(); diff --git a/spec/fixtures/module/preload-ipc-ping-pong.js b/spec/fixtures/module/preload-ipc-ping-pong.js deleted file mode 100644 index 41d4c75382230..0000000000000 --- a/spec/fixtures/module/preload-ipc-ping-pong.js +++ /dev/null @@ -1,9 +0,0 @@ -const { ipcRenderer } = require('electron'); - -ipcRenderer.on('ping', function (event, payload) { - ipcRenderer.sendTo(event.senderId, 'pong', payload); -}); - -ipcRenderer.on('ping-æøåü', function (event, payload) { - ipcRenderer.sendTo(event.senderId, 'pong-æøåü', payload); -}); diff --git a/spec/fixtures/module/preload-ipc.js b/spec/fixtures/module/preload-ipc.js index 390fa920dfa09..465b7152edeee 100644 --- a/spec/fixtures/module/preload-ipc.js +++ b/spec/fixtures/module/preload-ipc.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + ipcRenderer.on('ping', function (event, message) { ipcRenderer.sendToHost('pong', message); }); diff --git a/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js deleted file mode 100644 index e72a4a4058db4..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ipcRenderer } = require('electron'); - -document.addEventListener('DOMContentLoaded', (event) => { - const outerFrame = document.querySelector('#outer-frame'); - if (outerFrame) { - outerFrame.onload = function () { - const pdframe = outerFrame.contentWindow.document.getElementById('pdf-frame'); - if (pdframe) { - pdframe.contentWindow.addEventListener('pdf-loaded', (event) => { - ipcRenderer.send('pdf-loaded', event.detail); - }); - } - }; - } -}); diff --git a/spec/fixtures/module/preload-pdf-loaded-in-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-subframe.js deleted file mode 100644 index dd7a7aaa42d6d..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded-in-subframe.js +++ /dev/null @@ -1,10 +0,0 @@ -const { ipcRenderer } = require('electron'); - -document.addEventListener('DOMContentLoaded', (event) => { - const subframe = document.querySelector('#pdf-frame'); - if (subframe) { - subframe.contentWindow.addEventListener('pdf-loaded', (event) => { - ipcRenderer.send('pdf-loaded', event.detail); - }); - } -}); diff --git a/spec/fixtures/module/preload-pdf-loaded.js b/spec/fixtures/module/preload-pdf-loaded.js deleted file mode 100644 index aa5c8fb4ffac6..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded.js +++ /dev/null @@ -1,5 +0,0 @@ -const { ipcRenderer } = require('electron'); - -window.addEventListener('pdf-loaded', function (event) { - ipcRenderer.send('pdf-loaded', event.detail); -}); diff --git a/spec-main/fixtures/module/preload-sandbox.js b/spec/fixtures/module/preload-sandbox.js similarity index 77% rename from spec-main/fixtures/module/preload-sandbox.js rename to spec/fixtures/module/preload-sandbox.js index d774c54301f31..ce0b0d3d816a2 100644 --- a/spec-main/fixtures/module/preload-sandbox.js +++ b/spec/fixtures/module/preload-sandbox.js @@ -1,5 +1,5 @@ (function () { - const { setImmediate } = require('timers'); + const { setImmediate } = require('node:timers'); const { ipcRenderer } = require('electron'); window.ipcRenderer = ipcRenderer; window.setImmediate = setImmediate; @@ -32,8 +32,13 @@ systemMemoryInfo: invoke(() => process.getSystemMemoryInfo()), systemVersion: invoke(() => process.getSystemVersion()), cpuUsage: invoke(() => process.getCPUUsage()), - ioCounters: invoke(() => process.getIOCounters()), uptime: invoke(() => process.uptime()), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeEvents: invoke(() => require('events') === require('node:events')), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeTimers: invoke(() => require('timers') === require('node:timers')), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeUrl: invoke(() => require('url') === require('node:url')), env: process.env, execPath: process.execPath, pid: process.pid, @@ -52,7 +57,8 @@ ipcRenderer.on('touch-the-opener', () => { let errorMessage = null; try { - const openerDoc = opener.document; // eslint-disable-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const openerDoc = opener.document; } catch (error) { errorMessage = error.message; } diff --git a/spec/fixtures/module/preload.js b/spec/fixtures/module/preload.js index aa7bba4cae8f0..3db67d9bde9b1 100644 --- a/spec/fixtures/module/preload.js +++ b/spec/fixtures/module/preload.js @@ -1,6 +1,7 @@ const types = { require: typeof require, module: typeof module, + exports: typeof exports, process: typeof process, Buffer: typeof Buffer }; diff --git a/spec-main/fixtures/module/print-crash-parameters.js b/spec/fixtures/module/print-crash-parameters.js similarity index 100% rename from spec-main/fixtures/module/print-crash-parameters.js rename to spec/fixtures/module/print-crash-parameters.js diff --git a/spec/fixtures/module/send-later.js b/spec/fixtures/module/send-later.js index 5b4a22097275c..feef5d903aeff 100644 --- a/spec/fixtures/module/send-later.js +++ b/spec/fixtures/module/send-later.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + window.onload = function () { ipcRenderer.send('answer', typeof window.process, typeof window.Buffer); }; diff --git a/spec-main/fixtures/module/test.coffee b/spec/fixtures/module/test.coffee similarity index 100% rename from spec-main/fixtures/module/test.coffee rename to spec/fixtures/module/test.coffee diff --git a/spec-main/fixtures/module/uv-dlopen.js b/spec/fixtures/module/uv-dlopen.js similarity index 100% rename from spec-main/fixtures/module/uv-dlopen.js rename to spec/fixtures/module/uv-dlopen.js diff --git a/spec-main/fixtures/native-addon/echo/binding.cc b/spec/fixtures/native-addon/echo/binding.cc similarity index 100% rename from spec-main/fixtures/native-addon/echo/binding.cc rename to spec/fixtures/native-addon/echo/binding.cc diff --git a/spec-main/fixtures/native-addon/echo/binding.gyp b/spec/fixtures/native-addon/echo/binding.gyp similarity index 100% rename from spec-main/fixtures/native-addon/echo/binding.gyp rename to spec/fixtures/native-addon/echo/binding.gyp diff --git a/spec-main/fixtures/native-addon/echo/lib/echo.js b/spec/fixtures/native-addon/echo/lib/echo.js similarity index 100% rename from spec-main/fixtures/native-addon/echo/lib/echo.js rename to spec/fixtures/native-addon/echo/lib/echo.js diff --git a/spec-main/fixtures/native-addon/echo/package.json b/spec/fixtures/native-addon/echo/package.json similarity index 100% rename from spec-main/fixtures/native-addon/echo/package.json rename to spec/fixtures/native-addon/echo/package.json diff --git a/spec/fixtures/native-addon/external-ab/binding.cc b/spec/fixtures/native-addon/external-ab/binding.cc new file mode 100644 index 0000000000000..df1d52546c22b --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/binding.cc @@ -0,0 +1,49 @@ +#include +#include +#include + +namespace { + +napi_value CreateBuffer(napi_env env, napi_callback_info info) { + v8::Isolate* isolate = v8::Isolate::TryGetCurrent(); + if (isolate == nullptr) { + return NULL; + } + + const size_t length = 4; + + uint8_t* data = new uint8_t[length]; + for (size_t i = 0; i < 4; i++) { + data[i] = static_cast(length); + } + + auto finalizer = [](char* data, void* hint) { + delete[] static_cast(reinterpret_cast(data)); + }; + + // NOTE: Buffer API is invoked directly rather than + // napi version to trigger the FATAL error from V8. + v8::MaybeLocal maybe = node::Buffer::New( + isolate, static_cast(reinterpret_cast(data)), length, + finalizer, nullptr); + + return reinterpret_cast(*maybe.ToLocalChecked()); +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = {{"createBuffer", NULL, CreateBuffer, + NULL, NULL, NULL, napi_default, + NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/fixtures/native-addon/external-ab/binding.gyp b/spec/fixtures/native-addon/external-ab/binding.gyp new file mode 100644 index 0000000000000..d8c4884bb9fef --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "external_ab", + "sources": [ + "binding.cc" + ] + } + ] +} diff --git a/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js b/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js new file mode 100644 index 0000000000000..ff2c1a8e72106 --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js @@ -0,0 +1,5 @@ +'use strict'; + +const binding = require('../build/Release/external_ab.node'); + +binding.createBuffer(); diff --git a/spec/fixtures/native-addon/external-ab/package.json b/spec/fixtures/native-addon/external-ab/package.json new file mode 100644 index 0000000000000..1ab30a4dc32d1 --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/package.json @@ -0,0 +1,5 @@ +{ + "main": "./lib/test-array-buffer.js", + "name": "@electron-ci/external-ab", + "version": "0.0.1" +} diff --git a/spec/fixtures/native-addon/osr-gpu/binding.gyp b/spec/fixtures/native-addon/osr-gpu/binding.gyp new file mode 100644 index 0000000000000..21e840d0929e6 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/binding.gyp @@ -0,0 +1,16 @@ +{ + "targets": [ + { + "target_name": "osr-gpu", + "sources": ['napi_utils.h'], + "conditions": [ + ['OS=="win"', { + 'sources': ['binding_win.cc'], + 'link_settings': { + 'libraries': ['dxgi.lib', 'd3d11.lib', 'dxguid.lib'], + } + }], + ], + } + ] +} diff --git a/spec/fixtures/native-addon/osr-gpu/binding_win.cc b/spec/fixtures/native-addon/osr-gpu/binding_win.cc new file mode 100644 index 0000000000000..2545aade52156 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/binding_win.cc @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "napi_utils.h" + +namespace { + +Microsoft::WRL::ComPtr device = nullptr; +Microsoft::WRL::ComPtr device1 = nullptr; +Microsoft::WRL::ComPtr context = nullptr; + +UINT cached_width = 0; +UINT cached_height = 0; +Microsoft::WRL::ComPtr cached_staging_texture = nullptr; + +napi_value ExtractPixels(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + if (status != napi_ok) + return nullptr; + + if (argc != 1) { + napi_throw_error(env, nullptr, + "Wrong number of arguments, expected textureInfo"); + } + + auto textureInfo = args[0]; + + auto widgetType = NAPI_GET_PROPERTY_VALUE_STRING(textureInfo, "widgetType"); + auto pixelFormat = NAPI_GET_PROPERTY_VALUE_STRING(textureInfo, "pixelFormat"); + auto sharedTextureHandle = + NAPI_GET_PROPERTY_VALUE(textureInfo, "sharedTextureHandle"); + + size_t handleBufferSize; + uint8_t* handleBufferData; + napi_get_buffer_info(env, sharedTextureHandle, + reinterpret_cast(&handleBufferData), + &handleBufferSize); + + auto handle = *reinterpret_cast(handleBufferData); + std::cout << "ExtractPixels widgetType=" << widgetType + << " pixelFormat=" << pixelFormat + << " sharedTextureHandle=" << handle << std::endl; + + Microsoft::WRL::ComPtr shared_texture = nullptr; + HRESULT hr = + device1->OpenSharedResource1(handle, IID_PPV_ARGS(&shared_texture)); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to open shared texture resource"); + return nullptr; + } + + // Extract the texture description + D3D11_TEXTURE2D_DESC desc; + shared_texture->GetDesc(&desc); + + // Cache the staging texture if it does not exist or size has changed + if (!cached_staging_texture || cached_width != desc.Width || + cached_height != desc.Height) { + if (cached_staging_texture) { + cached_staging_texture->Release(); + } + + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.MiscFlags = 0; + + std::cout << "Create staging Texture2D width=" << desc.Width + << " height=" << desc.Height << std::endl; + hr = device->CreateTexture2D(&desc, nullptr, &cached_staging_texture); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to create staging texture"); + return nullptr; + } + + cached_width = desc.Width; + cached_height = desc.Height; + } + + // Copy the shared texture to the staging texture + context->CopyResource(cached_staging_texture.Get(), shared_texture.Get()); + + // Calculate the size of the buffer needed to hold the pixel data + // 4 bytes per pixel + size_t bufferSize = desc.Width * desc.Height * 4; + + // Create a NAPI buffer to hold the pixel data + napi_value result; + void* resultData; + status = napi_create_buffer(env, bufferSize, &resultData, &result); + if (status != napi_ok) { + napi_throw_error(env, "osr-gpu", "Failed to create buffer"); + return nullptr; + } + + // Map the staging texture to read the pixel data + D3D11_MAPPED_SUBRESOURCE mappedResource; + hr = context->Map(cached_staging_texture.Get(), 0, D3D11_MAP_READ, 0, + &mappedResource); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to map the staging texture"); + return nullptr; + } + + // Copy the pixel data from the mapped resource to the NAPI buffer + const uint8_t* srcData = static_cast(mappedResource.pData); + uint8_t* destData = static_cast(resultData); + for (UINT row = 0; row < desc.Height; ++row) { + memcpy(destData + row * desc.Width * 4, + srcData + row * mappedResource.RowPitch, desc.Width * 4); + } + + // Unmap the staging texture + context->Unmap(cached_staging_texture.Get(), 0); + return result; +} + +napi_value InitializeGpu(napi_env env, napi_callback_info info) { + HRESULT hr; + + // Feature levels supported + D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1}; + UINT num_feature_levels = ARRAYSIZE(feature_levels); + D3D_FEATURE_LEVEL feature_level; + + // This flag adds support for surfaces with a different color channel ordering + // than the default. It is required for compatibility with Direct2D. + UINT creation_flags = + D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG; + + // We need dxgi to share texture + Microsoft::WRL::ComPtr dxgi_factory = nullptr; + Microsoft::WRL::ComPtr adapter = nullptr; + hr = CreateDXGIFactory(IID_IDXGIFactory2, (void**)&dxgi_factory); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "CreateDXGIFactory failed"); + return nullptr; + } + + hr = dxgi_factory->EnumAdapters(0, &adapter); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "EnumAdapters failed"); + return nullptr; + } + + DXGI_ADAPTER_DESC adapter_desc; + adapter->GetDesc(&adapter_desc); + std::wcout << "Initializing DirectX with adapter: " + << adapter_desc.Description << std::endl; + + hr = D3D11CreateDevice(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, + creation_flags, feature_levels, num_feature_levels, + D3D11_SDK_VERSION, &device, &feature_level, &context); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "D3D11CreateDevice failed"); + return nullptr; + } + + hr = device->QueryInterface(IID_PPV_ARGS(&device1)); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to open d3d11_1 device"); + return nullptr; + } + + return nullptr; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = { + {"ExtractPixels", NULL, ExtractPixels, NULL, NULL, NULL, napi_default, + NULL}, + {"InitializeGpu", NULL, InitializeGpu, NULL, NULL, NULL, napi_default, + NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + std::cout << "Initialized osr-gpu native module" << std::endl; + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js b/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js new file mode 100644 index 0000000000000..4f4ea51a8bec5 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js @@ -0,0 +1 @@ +module.exports = require('../build/Release/osr-gpu.node'); diff --git a/spec/fixtures/native-addon/osr-gpu/napi_utils.h b/spec/fixtures/native-addon/osr-gpu/napi_utils.h new file mode 100644 index 0000000000000..40bcce30d9ad5 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/napi_utils.h @@ -0,0 +1,33 @@ +#define NAPI_CREATE_STRING(str) \ + [&]() { \ + napi_value value; \ + napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value); \ + return value; \ + }() + +#define NAPI_GET_PROPERTY_VALUE(obj, field) \ + [&]() { \ + napi_value value; \ + napi_get_property(env, obj, NAPI_CREATE_STRING(field), &value); \ + return value; \ + }() + +#define NAPI_GET_PROPERTY_VALUE_STRING(obj, field) \ + [&]() { \ + auto val = NAPI_GET_PROPERTY_VALUE(obj, field); \ + size_t size; \ + napi_get_value_string_utf8(env, val, nullptr, 0, &size); \ + char* buffer = new char[size + 1]; \ + napi_get_value_string_utf8(env, val, buffer, size + 1, &size); \ + return std::string(buffer); \ + }() + +#define NAPI_GET_PROPERTY_VALUE_BUFFER(obj, field) \ + [&]() { \ + auto val = NAPI_GET_PROPERTY_VALUE(obj, field); \ + size_t size; \ + napi_create_buffer(env, val, nullptr, 0, &size); \ + char* buffer = new char[size + 1]; \ + napi_get_value_string_utf8(env, val, buffer, size + 1, &size); \ + return std::string(buffer); \ + }() \ No newline at end of file diff --git a/spec/fixtures/native-addon/osr-gpu/package.json b/spec/fixtures/native-addon/osr-gpu/package.json new file mode 100644 index 0000000000000..13f78a53bae20 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/package.json @@ -0,0 +1,5 @@ +{ + "main": "./lib/osr-gpu.js", + "name": "@electron-ci/osr-gpu", + "version": "0.0.1" +} diff --git a/spec-main/fixtures/native-addon/uv-dlopen/binding.gyp b/spec/fixtures/native-addon/uv-dlopen/binding.gyp similarity index 100% rename from spec-main/fixtures/native-addon/uv-dlopen/binding.gyp rename to spec/fixtures/native-addon/uv-dlopen/binding.gyp diff --git a/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp b/spec/fixtures/native-addon/uv-dlopen/foo.cpp similarity index 100% rename from spec-main/fixtures/native-addon/uv-dlopen/foo.cpp rename to spec/fixtures/native-addon/uv-dlopen/foo.cpp diff --git a/spec/fixtures/native-addon/uv-dlopen/index.js b/spec/fixtures/native-addon/uv-dlopen/index.js new file mode 100644 index 0000000000000..c2761afc41578 --- /dev/null +++ b/spec/fixtures/native-addon/uv-dlopen/index.js @@ -0,0 +1,18 @@ +const path = require('node:path'); + +const testLoadLibrary = require('./build/Release/test_module'); + +const lib = (() => { + switch (process.platform) { + case 'linux': + return path.resolve(__dirname, 'build/Release/foo.so'); + case 'darwin': + return path.resolve(__dirname, 'build/Release/foo.dylib'); + case 'win32': + return path.resolve(__dirname, 'build/Release/libfoo.dll'); + default: + throw new Error('unsupported os'); + } +})(); + +testLoadLibrary(lib); diff --git a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp b/spec/fixtures/native-addon/uv-dlopen/main.cpp similarity index 100% rename from spec-main/fixtures/native-addon/uv-dlopen/main.cpp rename to spec/fixtures/native-addon/uv-dlopen/main.cpp diff --git a/spec-main/fixtures/native-addon/uv-dlopen/package.json b/spec/fixtures/native-addon/uv-dlopen/package.json similarity index 100% rename from spec-main/fixtures/native-addon/uv-dlopen/package.json rename to spec/fixtures/native-addon/uv-dlopen/package.json diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index c3453a829cfac..9c8dbdde74dbf 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -5,7 +5,8 @@ // that does include proprietary codecs. const { app, BrowserWindow, ipcMain } = require('electron'); -const path = require('path'); + +const path = require('node:path'); const MEDIA_ERR_SRC_NOT_SUPPORTED = 4; const FIVE_MINUTES = 5 * 60 * 1000; @@ -21,8 +22,8 @@ app.whenReady().then(() => { } }); - window.webContents.on('crashed', (event, killed) => { - console.log(`WebContents crashed (killed=${killed})`); + window.webContents.on('render-process-gone', (event, details) => { + console.log(`WebContents crashed ${JSON.stringify(details)}`); app.exit(1); }); diff --git a/spec/fixtures/pages/button.html b/spec/fixtures/pages/button.html new file mode 100644 index 0000000000000..79e2c06f56f71 --- /dev/null +++ b/spec/fixtures/pages/button.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/css-transparent.html b/spec/fixtures/pages/css-transparent.html new file mode 100644 index 0000000000000..48e406c884108 --- /dev/null +++ b/spec/fixtures/pages/css-transparent.html @@ -0,0 +1,31 @@ + + + + + test-color-window + + + + + + diff --git a/spec/fixtures/pages/datalist-text.html b/spec/fixtures/pages/datalist-text.html new file mode 100644 index 0000000000000..fc1d2c2801687 --- /dev/null +++ b/spec/fixtures/pages/datalist-text.html @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/datalist-time.html b/spec/fixtures/pages/datalist-time.html new file mode 100644 index 0000000000000..f38766eb83bf7 --- /dev/null +++ b/spec/fixtures/pages/datalist-time.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/draggable-page.html b/spec/fixtures/pages/draggable-page.html new file mode 100644 index 0000000000000..7b106e5cea0ad --- /dev/null +++ b/spec/fixtures/pages/draggable-page.html @@ -0,0 +1,22 @@ + + + + + + Draggable Page + + + + +
+ + + diff --git a/spec-main/fixtures/pages/fetch.html b/spec/fixtures/pages/fetch.html similarity index 100% rename from spec-main/fixtures/pages/fetch.html rename to spec/fixtures/pages/fetch.html diff --git a/spec/fixtures/pages/file-input.html b/spec/fixtures/pages/file-input.html new file mode 100644 index 0000000000000..db3ffef5bdc29 --- /dev/null +++ b/spec/fixtures/pages/file-input.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/flex-webview.html b/spec/fixtures/pages/flex-webview.html new file mode 100644 index 0000000000000..7d5369946c684 --- /dev/null +++ b/spec/fixtures/pages/flex-webview.html @@ -0,0 +1,15 @@ + diff --git a/spec-main/fixtures/pages/half-background-color.html b/spec/fixtures/pages/half-background-color.html similarity index 100% rename from spec-main/fixtures/pages/half-background-color.html rename to spec/fixtures/pages/half-background-color.html diff --git a/spec/fixtures/pages/iframe-protocol.html b/spec/fixtures/pages/iframe-protocol.html new file mode 100644 index 0000000000000..a283115b19382 --- /dev/null +++ b/spec/fixtures/pages/iframe-protocol.html @@ -0,0 +1,11 @@ + + + + diff --git a/spec-main/fixtures/pages/jquery-3.6.0.min.js b/spec/fixtures/pages/jquery-3.6.0.min.js similarity index 100% rename from spec-main/fixtures/pages/jquery-3.6.0.min.js rename to spec/fixtures/pages/jquery-3.6.0.min.js diff --git a/spec-main/fixtures/pages/jquery.html b/spec/fixtures/pages/jquery.html similarity index 100% rename from spec-main/fixtures/pages/jquery.html rename to spec/fixtures/pages/jquery.html diff --git a/spec/fixtures/pages/key-events.html b/spec/fixtures/pages/key-events.html index 7402daf5e999f..c16c98bac2ed1 100644 --- a/spec/fixtures/pages/key-events.html +++ b/spec/fixtures/pages/key-events.html @@ -1,11 +1,17 @@ + diff --git a/spec/fixtures/pages/modal.html b/spec/fixtures/pages/modal.html new file mode 100644 index 0000000000000..28b9e6b2c95e2 --- /dev/null +++ b/spec/fixtures/pages/modal.html @@ -0,0 +1,26 @@ + + + + + + +

+ +

+
+ + +
+ +
+ + + \ No newline at end of file diff --git a/spec/fixtures/pages/native-module.html b/spec/fixtures/pages/native-module.html index 922a09aeeddfe..685b15d57d3c4 100644 --- a/spec/fixtures/pages/native-module.html +++ b/spec/fixtures/pages/native-module.html @@ -1,8 +1,8 @@ diff --git a/spec/fixtures/pages/navigate_in_page_and_wait.html b/spec/fixtures/pages/navigate_in_page_and_wait.html new file mode 100644 index 0000000000000..f582af55a5835 --- /dev/null +++ b/spec/fixtures/pages/navigate_in_page_and_wait.html @@ -0,0 +1,15 @@ + +
+ +
+ + + diff --git a/spec-main/fixtures/pages/overlay.html b/spec/fixtures/pages/overlay.html similarity index 98% rename from spec-main/fixtures/pages/overlay.html rename to spec/fixtures/pages/overlay.html index e866725574d55..7ee96f59fd03e 100644 --- a/spec-main/fixtures/pages/overlay.html +++ b/spec/fixtures/pages/overlay.html @@ -55,7 +55,7 @@ const {x, y, width, height} = navigator.windowControlsOverlay.getTitlebarAreaRect(); ipcRenderer.send('geometrychange', {x, y, width, height}); }; - +
Title goes here @@ -76,7 +76,7 @@ } function getJSOverlayProperties() { - const {x, y, width, height} = navigator.windowControlsOverlay.getTitlebarAreaRect(); + const {x, y, width, height} = navigator.windowControlsOverlay.getTitlebarAreaRect(); return {x, y, width, height}; } diff --git a/spec-main/fixtures/pages/pdf-in-iframe.html b/spec/fixtures/pages/pdf-in-iframe.html similarity index 100% rename from spec-main/fixtures/pages/pdf-in-iframe.html rename to spec/fixtures/pages/pdf-in-iframe.html diff --git a/spec/fixtures/pages/send-after-node.html b/spec/fixtures/pages/send-after-node.html index 68f5a40b6707b..7a1ffa727cd9f 100644 --- a/spec/fixtures/pages/send-after-node.html +++ b/spec/fixtures/pages/send-after-node.html @@ -1,7 +1,7 @@ diff --git a/spec/fixtures/pages/service-worker/badge-index.html b/spec/fixtures/pages/service-worker/badge-index.html index 480a60a9aee88..06df4b230387b 100644 --- a/spec/fixtures/pages/service-worker/badge-index.html +++ b/spec/fixtures/pages/service-worker/badge-index.html @@ -1,6 +1,6 @@ - - diff --git a/spec/fixtures/pages/target-name.html b/spec/fixtures/pages/target-name.html deleted file mode 100644 index 0dc760d233f59..0000000000000 --- a/spec/fixtures/pages/target-name.html +++ /dev/null @@ -1,13 +0,0 @@ - - -link - - - diff --git a/spec/fixtures/pages/visibilitychange.html b/spec/fixtures/pages/visibilitychange.html index 0d4f07c46f933..3814475b5bdb5 100644 --- a/spec/fixtures/pages/visibilitychange.html +++ b/spec/fixtures/pages/visibilitychange.html @@ -3,10 +3,8 @@ diff --git a/spec-main/fixtures/pages/webview-devtools.html b/spec/fixtures/pages/webview-devtools.html similarity index 100% rename from spec-main/fixtures/pages/webview-devtools.html rename to spec/fixtures/pages/webview-devtools.html diff --git a/spec/fixtures/pages/webview-will-navigate-in-frame.html b/spec/fixtures/pages/webview-will-navigate-in-frame.html new file mode 100644 index 0000000000000..63f921e724278 --- /dev/null +++ b/spec/fixtures/pages/webview-will-navigate-in-frame.html @@ -0,0 +1,12 @@ + + + + + diff --git a/spec/fixtures/pages/webview-zoom-change-persist-host.html b/spec/fixtures/pages/webview-zoom-change-persist-host.html new file mode 100644 index 0000000000000..6dd7787a6b9ca --- /dev/null +++ b/spec/fixtures/pages/webview-zoom-change-persist-host.html @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/window-opener-targetOrigin.html b/spec/fixtures/pages/window-opener-targetOrigin.html index daa51a48cff1d..9a52296ca22a8 100644 --- a/spec/fixtures/pages/window-opener-targetOrigin.html +++ b/spec/fixtures/pages/window-opener-targetOrigin.html @@ -1,7 +1,7 @@ + + diff --git a/spec/fixtures/pages/zoom-factor.html b/spec/fixtures/pages/zoom-factor.html index c27b5ea495a4e..4c490bceeac69 100644 --- a/spec/fixtures/pages/zoom-factor.html +++ b/spec/fixtures/pages/zoom-factor.html @@ -1,8 +1,10 @@ diff --git a/spec-main/fixtures/preload-expose-ipc.js b/spec/fixtures/preload-expose-ipc.js similarity index 100% rename from spec-main/fixtures/preload-expose-ipc.js rename to spec/fixtures/preload-expose-ipc.js diff --git a/spec/fixtures/recursive-asar/a.asar b/spec/fixtures/recursive-asar/a.asar new file mode 100644 index 0000000000000..852f460b6d548 Binary files /dev/null and b/spec/fixtures/recursive-asar/a.asar differ diff --git a/spec/fixtures/recursive-asar/nested/hello.txt b/spec/fixtures/recursive-asar/nested/hello.txt new file mode 100644 index 0000000000000..ec68ffb2b629c --- /dev/null +++ b/spec/fixtures/recursive-asar/nested/hello.txt @@ -0,0 +1 @@ +goodbye! \ No newline at end of file diff --git a/spec/fixtures/recursive-asar/test.txt b/spec/fixtures/recursive-asar/test.txt new file mode 100644 index 0000000000000..05a682bd4e7c7 --- /dev/null +++ b/spec/fixtures/recursive-asar/test.txt @@ -0,0 +1 @@ +Hello! \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa b/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa new file mode 100644 index 0000000000000..21e88cd9e01bf --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/029127a8b6f7c511fca4612748ad5b50e43aadaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2717","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"80e2d0edebd07c0cf53916bf23fee37544d3eb301e1a65595fff37115a465eae\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B2AD:4558739:66ECF364","x-ratelimit-limit":"60","x-ratelimit-remaining":"50","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"10","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39745","id":1504592750,"node_id":"PR_kwDOAI8xS85ZrkNu","html_url":"https://github.com/electron/electron/pull/39745","diff_url":"https://github.com/electron/electron/pull/39745.diff","patch_url":"https://github.com/electron/electron/pull/39745.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39745","number":39745,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5993.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5993.0.\n\nSee [all changes in 118.0.5991.0..118.0.5993.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5991.0..118.0.5993.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5993.0.","created_at":"2023-09-06T13:00:33Z","updated_at":"2023-09-06T23:28:42Z","closed_at":"2023-09-06T23:27:26Z","merged_at":"2023-09-06T23:27:26Z","merge_commit_sha":"029127a8b6f7c511fca4612748ad5b50e43aadaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1243058793,"node_id":"MDU6TGFiZWwxMjQzMDU4Nzkz","url":"https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1","name":"new-pr 🌱","color":"8af297","default":false,"description":"PR opened in the last 24 hours"},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39745/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39745/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39745/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"7ba0be830a247d916c05d2471c5ce214d2598476","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"34b79c15c2f2de2fa514538b7ccb4b3c473808ae","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39745"},"html":{"href":"https://github.com/electron/electron/pull/39745"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39745"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39745/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 b/spec/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 rename to spec/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 b/spec/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 rename to spec/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 b/spec/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 rename to spec/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 b/spec/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 rename to spec/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 b/spec/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 rename to spec/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 b/spec/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 rename to spec/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e b/spec/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e rename to spec/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f b/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f new file mode 100644 index 0000000000000..ef8d9b637caed --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/8f7a48879ef8633a76279803637cdee7f7c6cd4f/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"fc25a1c4edee51c7c227cdb578189b0196dfeea4976c22509630ee1fc0b75919\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","transfer-encoding":"chunked","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B7DF:45590F1:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"43","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"17","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/40076","id":1539965204,"node_id":"PR_kwDOAI8xS85bygEU","html_url":"https://github.com/electron/electron/pull/40076","diff_url":"https://github.com/electron/electron/pull/40076.diff","patch_url":"https://github.com/electron/electron/pull/40076.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","number":40076,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6045.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6045.0.\r\n\r\nSee [all changes in 119.0.6043.0..119.0.6045.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6043.0..119.0.6045.0?n=10000&pretty=fuller)\r\n\r\n\r\n\r\nNotes: Updated Chromium to 119.0.6045.0.","created_at":"2023-10-03T13:00:35Z","updated_at":"2023-10-06T00:56:09Z","closed_at":"2023-10-05T23:59:40Z","merged_at":"2023-10-05T23:59:40Z","merge_commit_sha":"8f7a48879ef8633a76279803637cdee7f7c6cd4f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40076/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40076/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40076/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6a695f015bac8388dc450b46f548288bff58a433","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"3392d9a2e74973960ca516adc1c1684e03f78414","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40076"},"html":{"href":"https://github.com/electron/electron/pull/40076"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40076"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40076/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa b/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa new file mode 100644 index 0000000000000..eb9fbc660d103 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2667","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"1467bf4bc68e3bbb5c598d01f59d72ae71f38c1e45f7a20c7397ada84fbbb80c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B4A7:4558AB7:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"48","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"12","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/40045","id":1535161486,"node_id":"PR_kwDOAI8xS85bgLSO","html_url":"https://github.com/electron/electron/pull/40045","diff_url":"https://github.com/electron/electron/pull/40045.diff","patch_url":"https://github.com/electron/electron/pull/40045.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","number":40045,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6043.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6043.0.\n\nSee [all changes in 119.0.6029.0..119.0.6043.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6029.0..119.0.6043.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6043.0.","created_at":"2023-09-29T05:27:06Z","updated_at":"2023-10-02T22:01:11Z","closed_at":"2023-10-02T22:01:07Z","merged_at":"2023-10-02T22:01:07Z","merge_commit_sha":"9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40045/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40045/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40045/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"503ae86ab216406485bf437969da8c56266c3346","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40045"},"html":{"href":"https://github.com/electron/electron/pull/40045"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40045"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40045/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b b/spec/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b rename to spec/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 b/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 new file mode 100644 index 0000000000000..a8852cb648f68 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2656","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"b1a96400c9529932fb835905524621cae9010fe39a87e5b4720587f8f5f1bf99\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B56F:4558C56:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"47","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"13","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39944","id":1524826900,"node_id":"PR_kwDOAI8xS85a4wMU","html_url":"https://github.com/electron/electron/pull/39944","diff_url":"https://github.com/electron/electron/pull/39944.diff","patch_url":"https://github.com/electron/electron/pull/39944.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","number":39944,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6029.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6029.0.\n\nSee [all changes in 119.0.6019.2..119.0.6029.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6019.2..119.0.6029.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6029.0.","created_at":"2023-09-21T13:00:39Z","updated_at":"2023-09-29T05:26:44Z","closed_at":"2023-09-29T05:26:41Z","merged_at":"2023-09-29T05:26:41Z","merge_commit_sha":"d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39944/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39944/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39944/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"bcb310340b17faa47fa68eae5db91d908995ffe0","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"dd7395ebedf0cfef3129697f9585035a4ddbde63","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39944"},"html":{"href":"https://github.com/electron/electron/pull/39944"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39944"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39944/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 b/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 new file mode 100644 index 0000000000000..d85f99aa2322e --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d9ba26273ad3e7a34c905eccbd5dabda4eb7b402/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2671","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"43d13a3642303cd5f8d90df11c58df1d9952cb3c42dacdfb39e02e1d60d2d54f\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B3BD:4558915:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"49","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"11","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39714","id":1498359807,"node_id":"PR_kwDOAI8xS85ZTyf_","html_url":"https://github.com/electron/electron/pull/39714","diff_url":"https://github.com/electron/electron/pull/39714.diff","patch_url":"https://github.com/electron/electron/pull/39714.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","number":39714,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5991.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5991.0.\n\nSee [all changes in 118.0.5975.0..118.0.5991.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5975.0..118.0.5991.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5991.0.","created_at":"2023-09-01T06:55:20Z","updated_at":"2023-09-06T01:18:00Z","closed_at":"2023-09-06T01:17:57Z","merged_at":"2023-09-06T01:17:57Z","merge_commit_sha":"d9ba26273ad3e7a34c905eccbd5dabda4eb7b402","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39714/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39714/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39714/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6bf3066e43060001074a8a38168024531dbceec3","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"54d8402a6ca8a357d7695c1c6d01d5040e42926a","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39714"},"html":{"href":"https://github.com/electron/electron/pull/39714"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39714"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39714/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-20214-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-20214-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-20214-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-20214-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21497-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21497-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21497-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21497-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21891-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21891-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21891-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21891-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21946-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21946-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21946-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21946-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22750-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22750-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22750-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22750-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22770-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22770-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22770-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22770-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22828-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22828-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22828-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22828-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-25052-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-25052-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-25052-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-25052-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-25216-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-25216-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-25216-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-25216-comments diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments new file mode 100644 index 0000000000000..5770c77857155 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/39714/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"645","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"6fcb725196d33f08ba1ccba10f866b6bc0a51030d157259b2cce6d2758910e24\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B64D:4558DD8:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"46","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"14","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1707509099","html_url":"https://github.com/electron/electron/pull/39714#issuecomment-1707509099","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","id":1707509099,"node_id":"IC_kwDOAI8xS85lxoVr","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-09-06T01:18:00Z","updated_at":"2023-09-06T01:18:00Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 118.0.5991.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1707509099/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments new file mode 100644 index 0000000000000..288d1b4afef5e --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/39944/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"869","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"b34114fbdb2350380ab4adac1c9c48568bebf0e5c0a427ecaa40402f7166456c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B74B:4558FC8:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"44","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"16","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1732251450","html_url":"https://github.com/electron/electron/pull/39944#issuecomment-1732251450","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","id":1732251450,"node_id":"IC_kwDOAI8xS85nQA86","user":{"login":"codebytere","id":2036040,"node_id":"MDQ6VXNlcjIwMzYwNDA=","avatar_url":"https://avatars.githubusercontent.com/u/2036040?v=4","gravatar_id":"","url":"https://api.github.com/users/codebytere","html_url":"https://github.com/codebytere","followers_url":"https://api.github.com/users/codebytere/followers","following_url":"https://api.github.com/users/codebytere/following{/other_user}","gists_url":"https://api.github.com/users/codebytere/gists{/gist_id}","starred_url":"https://api.github.com/users/codebytere/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codebytere/subscriptions","organizations_url":"https://api.github.com/users/codebytere/orgs","repos_url":"https://api.github.com/users/codebytere/repos","events_url":"https://api.github.com/users/codebytere/events{/privacy}","received_events_url":"https://api.github.com/users/codebytere/received_events","type":"User","site_admin":false},"created_at":"2023-09-23T08:19:47Z","updated_at":"2023-09-23T08:19:47Z","author_association":"MEMBER","body":"Needs https://github.com/electron/build-tools/pull/516","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1732251450/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null},{"url":"https://api.github.com/repos/electron/electron/issues/comments/1740333567","html_url":"https://github.com/electron/electron/pull/39944#issuecomment-1740333567","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","id":1740333567,"node_id":"IC_kwDOAI8xS85nu2H_","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-09-29T05:26:44Z","updated_at":"2023-09-29T05:26:44Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6029.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1740333567/reactions","total_count":2,"+1":1,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":1,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments new file mode 100644 index 0000000000000..f7ecc0e3c731b --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/40045/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"645","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"597a0b18dff7544d3742956759f06c9233095b92fdc8e3a1ac78afaf61a42b5c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B6D4:4558ED3:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"45","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"15","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1743831479","html_url":"https://github.com/electron/electron/pull/40045#issuecomment-1743831479","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","id":1743831479,"node_id":"IC_kwDOAI8xS85n8MG3","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-10-02T22:01:11Z","updated_at":"2023-10-02T22:01:11Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6043.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1743831479/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments new file mode 100644 index 0000000000000..411ab60c17767 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/40076/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"894","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"b11c58261437bdbb984540cd6090cfe239f8f4b5b7af801f6f711e7f0bbe5915\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B8AF:4559259:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"42","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"18","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749810095","html_url":"https://github.com/electron/electron/pull/40076#issuecomment-1749810095","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","id":1749810095,"node_id":"IC_kwDOAI8xS85oS_uv","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-10-05T23:59:43Z","updated_at":"2023-10-05T23:59:43Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6045.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749810095/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null},{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749846515","html_url":"https://github.com/electron/electron/pull/40076#issuecomment-1749846515","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","id":1749846515,"node_id":"IC_kwDOAI8xS85oTInz","user":{"login":"ckerr","id":70381,"node_id":"MDQ6VXNlcjcwMzgx","avatar_url":"https://avatars.githubusercontent.com/u/70381?v=4","gravatar_id":"","url":"https://api.github.com/users/ckerr","html_url":"https://github.com/ckerr","followers_url":"https://api.github.com/users/ckerr/followers","following_url":"https://api.github.com/users/ckerr/following{/other_user}","gists_url":"https://api.github.com/users/ckerr/gists{/gist_id}","starred_url":"https://api.github.com/users/ckerr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ckerr/subscriptions","organizations_url":"https://api.github.com/users/ckerr/orgs","repos_url":"https://api.github.com/users/ckerr/repos","events_url":"https://api.github.com/users/ckerr/events{/privacy}","received_events_url":"https://api.github.com/users/ckerr/received_events","type":"User","site_admin":false},"created_at":"2023-10-06T00:56:09Z","updated_at":"2023-10-06T00:56:09Z","author_association":"MEMBER","body":"Ah, merged while I was reading. :sweat_smile: FWIW @jkleinsc here's a tardy :+1: on the glib/gio changes","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749846515/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-20214 b/spec/fixtures/release-notes/cache/electron-electron-pull-20214 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-20214 rename to spec/fixtures/release-notes/cache/electron-electron-pull-20214 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-20620 b/spec/fixtures/release-notes/cache/electron-electron-pull-20620 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-20620 rename to spec/fixtures/release-notes/cache/electron-electron-pull-20620 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21497 b/spec/fixtures/release-notes/cache/electron-electron-pull-21497 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21497 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21497 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21591 b/spec/fixtures/release-notes/cache/electron-electron-pull-21591 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21591 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21591 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21891 b/spec/fixtures/release-notes/cache/electron-electron-pull-21891 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21891 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21891 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21946 b/spec/fixtures/release-notes/cache/electron-electron-pull-21946 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21946 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21946 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22750 b/spec/fixtures/release-notes/cache/electron-electron-pull-22750 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22750 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22750 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22770 b/spec/fixtures/release-notes/cache/electron-electron-pull-22770 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22770 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22770 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22828 b/spec/fixtures/release-notes/cache/electron-electron-pull-22828 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22828 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22828 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-25052 b/spec/fixtures/release-notes/cache/electron-electron-pull-25052 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-25052 rename to spec/fixtures/release-notes/cache/electron-electron-pull-25052 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-25216 b/spec/fixtures/release-notes/cache/electron-electron-pull-25216 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-25216 rename to spec/fixtures/release-notes/cache/electron-electron-pull-25216 diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39714 b/spec/fixtures/release-notes/cache/electron-electron-pull-39714 new file mode 100644 index 0000000000000..e1166b21a3e03 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39714 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d9ba26273ad3e7a34c905eccbd5dabda4eb7b402/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2671","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"43d13a3642303cd5f8d90df11c58df1d9952cb3c42dacdfb39e02e1d60d2d54f\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B3BD:4558915:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"49","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"11","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39714","id":1498359807,"node_id":"PR_kwDOAI8xS85ZTyf_","html_url":"https://github.com/electron/electron/pull/39714","diff_url":"https://github.com/electron/electron/pull/39714.diff","patch_url":"https://github.com/electron/electron/pull/39714.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","number":39714,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5991.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5991.0.\n\nSee [all changes in 118.0.5975.0..118.0.5991.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5975.0..118.0.5991.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5991.0.","created_at":"2023-09-01T06:55:20Z","updated_at":"2023-09-06T01:18:00Z","closed_at":"2023-09-06T01:17:57Z","merged_at":"2023-09-06T01:17:57Z","merge_commit_sha":"d9ba26273ad3e7a34c905eccbd5dabda4eb7b402","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39714/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39714/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39714/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6bf3066e43060001074a8a38168024531dbceec3","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"54d8402a6ca8a357d7695c1c6d01d5040e42926a","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39714"},"html":{"href":"https://github.com/electron/electron/pull/39714"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39714"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39714/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39745 b/spec/fixtures/release-notes/cache/electron-electron-pull-39745 new file mode 100644 index 0000000000000..9bde239b59580 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39745 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/029127a8b6f7c511fca4612748ad5b50e43aadaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2717","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"80e2d0edebd07c0cf53916bf23fee37544d3eb301e1a65595fff37115a465eae\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B2AD:4558739:66ECF364","x-ratelimit-limit":"60","x-ratelimit-remaining":"50","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"10","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39745","id":1504592750,"node_id":"PR_kwDOAI8xS85ZrkNu","html_url":"https://github.com/electron/electron/pull/39745","diff_url":"https://github.com/electron/electron/pull/39745.diff","patch_url":"https://github.com/electron/electron/pull/39745.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39745","number":39745,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5993.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5993.0.\n\nSee [all changes in 118.0.5991.0..118.0.5993.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5991.0..118.0.5993.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5993.0.","created_at":"2023-09-06T13:00:33Z","updated_at":"2023-09-06T23:28:42Z","closed_at":"2023-09-06T23:27:26Z","merged_at":"2023-09-06T23:27:26Z","merge_commit_sha":"029127a8b6f7c511fca4612748ad5b50e43aadaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1243058793,"node_id":"MDU6TGFiZWwxMjQzMDU4Nzkz","url":"https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1","name":"new-pr 🌱","color":"8af297","default":false,"description":"PR opened in the last 24 hours"},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39745/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39745/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39745/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"7ba0be830a247d916c05d2471c5ce214d2598476","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"34b79c15c2f2de2fa514538b7ccb4b3c473808ae","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39745"},"html":{"href":"https://github.com/electron/electron/pull/39745"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39745"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39745/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39944 b/spec/fixtures/release-notes/cache/electron-electron-pull-39944 new file mode 100644 index 0000000000000..374b574670616 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39944 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2656","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"b1a96400c9529932fb835905524621cae9010fe39a87e5b4720587f8f5f1bf99\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B56F:4558C56:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"47","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"13","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39944","id":1524826900,"node_id":"PR_kwDOAI8xS85a4wMU","html_url":"https://github.com/electron/electron/pull/39944","diff_url":"https://github.com/electron/electron/pull/39944.diff","patch_url":"https://github.com/electron/electron/pull/39944.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","number":39944,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6029.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6029.0.\n\nSee [all changes in 119.0.6019.2..119.0.6029.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6019.2..119.0.6029.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6029.0.","created_at":"2023-09-21T13:00:39Z","updated_at":"2023-09-29T05:26:44Z","closed_at":"2023-09-29T05:26:41Z","merged_at":"2023-09-29T05:26:41Z","merge_commit_sha":"d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39944/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39944/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39944/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"bcb310340b17faa47fa68eae5db91d908995ffe0","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"dd7395ebedf0cfef3129697f9585035a4ddbde63","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39944"},"html":{"href":"https://github.com/electron/electron/pull/39944"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39944"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39944/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-40045 b/spec/fixtures/release-notes/cache/electron-electron-pull-40045 new file mode 100644 index 0000000000000..996570b00e337 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-40045 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2667","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"1467bf4bc68e3bbb5c598d01f59d72ae71f38c1e45f7a20c7397ada84fbbb80c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B4A7:4558AB7:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"48","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"12","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/40045","id":1535161486,"node_id":"PR_kwDOAI8xS85bgLSO","html_url":"https://github.com/electron/electron/pull/40045","diff_url":"https://github.com/electron/electron/pull/40045.diff","patch_url":"https://github.com/electron/electron/pull/40045.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","number":40045,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6043.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6043.0.\n\nSee [all changes in 119.0.6029.0..119.0.6043.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6029.0..119.0.6043.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6043.0.","created_at":"2023-09-29T05:27:06Z","updated_at":"2023-10-02T22:01:11Z","closed_at":"2023-10-02T22:01:07Z","merged_at":"2023-10-02T22:01:07Z","merge_commit_sha":"9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40045/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40045/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40045/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"503ae86ab216406485bf437969da8c56266c3346","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40045"},"html":{"href":"https://github.com/electron/electron/pull/40045"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40045"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40045/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-40076 b/spec/fixtures/release-notes/cache/electron-electron-pull-40076 new file mode 100644 index 0000000000000..84bd9002d89ff --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-40076 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/8f7a48879ef8633a76279803637cdee7f7c6cd4f/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"fc25a1c4edee51c7c227cdb578189b0196dfeea4976c22509630ee1fc0b75919\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","transfer-encoding":"chunked","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B7DF:45590F1:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"43","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"17","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/40076","id":1539965204,"node_id":"PR_kwDOAI8xS85bygEU","html_url":"https://github.com/electron/electron/pull/40076","diff_url":"https://github.com/electron/electron/pull/40076.diff","patch_url":"https://github.com/electron/electron/pull/40076.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","number":40076,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6045.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6045.0.\r\n\r\nSee [all changes in 119.0.6043.0..119.0.6045.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6043.0..119.0.6045.0?n=10000&pretty=fuller)\r\n\r\n\r\n\r\nNotes: Updated Chromium to 119.0.6045.0.","created_at":"2023-10-03T13:00:35Z","updated_at":"2023-10-06T00:56:09Z","closed_at":"2023-10-05T23:59:40Z","merged_at":"2023-10-05T23:59:40Z","merge_commit_sha":"8f7a48879ef8633a76279803637cdee7f7c6cd4f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40076/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40076/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40076/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6a695f015bac8388dc450b46f548288bff58a433","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"3392d9a2e74973960ca516adc1c1684e03f78414","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40076"},"html":{"href":"https://github.com/electron/electron/pull/40076"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40076"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40076/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec-main/fixtures/sub-frames/debug-frames.html b/spec/fixtures/sub-frames/debug-frames.html similarity index 100% rename from spec-main/fixtures/sub-frames/debug-frames.html rename to spec/fixtures/sub-frames/debug-frames.html diff --git a/spec-main/fixtures/sub-frames/frame-container-webview.html b/spec/fixtures/sub-frames/frame-container-webview.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-container-webview.html rename to spec/fixtures/sub-frames/frame-container-webview.html diff --git a/spec-main/fixtures/sub-frames/frame-container.html b/spec/fixtures/sub-frames/frame-container.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-container.html rename to spec/fixtures/sub-frames/frame-container.html diff --git a/spec-main/fixtures/sub-frames/frame-with-frame-container-webview.html b/spec/fixtures/sub-frames/frame-with-frame-container-webview.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-with-frame-container-webview.html rename to spec/fixtures/sub-frames/frame-with-frame-container-webview.html diff --git a/spec-main/fixtures/sub-frames/frame-with-frame-container.html b/spec/fixtures/sub-frames/frame-with-frame-container.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-with-frame-container.html rename to spec/fixtures/sub-frames/frame-with-frame-container.html diff --git a/spec-main/fixtures/sub-frames/frame-with-frame.html b/spec/fixtures/sub-frames/frame-with-frame.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-with-frame.html rename to spec/fixtures/sub-frames/frame-with-frame.html diff --git a/spec-main/fixtures/sub-frames/frame.html b/spec/fixtures/sub-frames/frame.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame.html rename to spec/fixtures/sub-frames/frame.html diff --git a/spec/fixtures/sub-frames/preload.js b/spec/fixtures/sub-frames/preload.js new file mode 100644 index 0000000000000..cc36e49e4bed6 --- /dev/null +++ b/spec/fixtures/sub-frames/preload.js @@ -0,0 +1,13 @@ +const { ipcRenderer, webFrame } = require('electron'); + +window.isolatedGlobal = true; + +ipcRenderer.send('preload-ran', window.location.href, webFrame.routingId); + +ipcRenderer.on('preload-ping', () => { + ipcRenderer.send('preload-pong', webFrame.routingId); +}); + +window.addEventListener('unload', () => { + ipcRenderer.send('preload-unload', window.location.href); +}); diff --git a/spec-main/fixtures/sub-frames/test.js b/spec/fixtures/sub-frames/test.js similarity index 100% rename from spec-main/fixtures/sub-frames/test.js rename to spec/fixtures/sub-frames/test.js diff --git a/spec-main/fixtures/sub-frames/webview-iframe-preload.js b/spec/fixtures/sub-frames/webview-iframe-preload.js similarity index 100% rename from spec-main/fixtures/sub-frames/webview-iframe-preload.js rename to spec/fixtures/sub-frames/webview-iframe-preload.js diff --git a/spec/fixtures/test.asar/repack.js b/spec/fixtures/test.asar/repack.js index 1220b595a8ecf..d85dc01e750c0 100644 --- a/spec/fixtures/test.asar/repack.js +++ b/spec/fixtures/test.asar/repack.js @@ -1,10 +1,11 @@ // Use this script to regenerate these fixture files // using a new version of the asar package -const asar = require('asar'); -const fs = require('fs'); -const os = require('os'); -const path = require('path'); +const asar = require('@electron/asar'); + +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); const archives = []; for (const child of fs.readdirSync(__dirname)) { diff --git a/spec/fixtures/testsnap.js b/spec/fixtures/testsnap.js index 3ac89c522a8bb..ab1c3cd696927 100644 --- a/spec/fixtures/testsnap.js +++ b/spec/fixtures/testsnap.js @@ -1,3 +1,4 @@ -// taken from https://chromium.googlesource.com/v8/v8.git/+/HEAD/test/cctest/test-serialize.cc#1127 -function f () { return g() * 2; } // eslint-disable-line no-unused-vars +// taken from https://chromium.googlesource.com/v8/v8.git/+/HEAD/test/cctest/test-serialize.cc +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function f () { return g() * 2; } function g () { return 43; } diff --git a/spec-main/fixtures/webview/fullscreen/frame.html b/spec/fixtures/webview/fullscreen/frame.html similarity index 100% rename from spec-main/fixtures/webview/fullscreen/frame.html rename to spec/fixtures/webview/fullscreen/frame.html diff --git a/spec-main/fixtures/webview/fullscreen/main.html b/spec/fixtures/webview/fullscreen/main.html similarity index 100% rename from spec-main/fixtures/webview/fullscreen/main.html rename to spec/fixtures/webview/fullscreen/main.html diff --git a/spec/fixtures/workers/worker_node_fetch.js b/spec/fixtures/workers/worker_node_fetch.js new file mode 100644 index 0000000000000..0f6ca70f0489c --- /dev/null +++ b/spec/fixtures/workers/worker_node_fetch.js @@ -0,0 +1,7 @@ +self.postMessage([ + typeof fetch, + typeof Response, + typeof Request, + typeof Headers, + typeof FormData +].join(' ')); diff --git a/spec/fixtures/zip/a.zip b/spec/fixtures/zip/a.zip deleted file mode 100644 index 7b3a13209f551..0000000000000 Binary files a/spec/fixtures/zip/a.zip and /dev/null differ diff --git a/spec/fuses-spec.ts b/spec/fuses-spec.ts new file mode 100644 index 0000000000000..29409f7cc05a0 --- /dev/null +++ b/spec/fuses-spec.ts @@ -0,0 +1,38 @@ +import { BrowserWindow } from 'electron'; + +import { expect } from 'chai'; + +import { spawn, spawnSync } from 'node:child_process'; +import { once } from 'node:events'; +import path = require('node:path'); + +import { startRemoteControlApp } from './lib/spec-helpers'; + +describe('fuses', () => { + it('can be enabled by command-line argument during testing', async () => { + const child0 = spawn(process.execPath, ['-v'], { env: { NODE_OPTIONS: '-e 0' } }); + const [code0] = await once(child0, 'exit'); + // Should exit with 9 because -e is not allowed in NODE_OPTIONS + expect(code0).to.equal(9); + const child1 = spawn(process.execPath, ['--set-fuse-node_options=0', '-v'], { env: { NODE_OPTIONS: '-e 0' } }); + const [code1] = await once(child1, 'exit'); + // Should print the version and exit with 0 + expect(code1).to.equal(0); + }); + + it('disables --inspect flag when node_cli_inspect is 0', () => { + const { status, stderr } = spawnSync(process.execPath, ['--set-fuse-node_cli_inspect=0', '--inspect', '-v'], { encoding: 'utf-8' }); + expect(stderr).to.not.include('Debugger listening on ws://'); + // Should print the version and exit with 0 + expect(status).to.equal(0); + }); + + it('disables fetching file:// URLs when grant_file_protocol_extra_privileges is 0', async () => { + const rc = await startRemoteControlApp(['--set-fuse-grant_file_protocol_extra_privileges=0']); + await expect(rc.remotely(async (fixture: string) => { + const bw = new BrowserWindow({ show: false }); + await bw.loadFile(fixture); + return await bw.webContents.executeJavaScript("ajax('file:///etc/passwd')"); + }, path.join(__dirname, 'fixtures', 'pages', 'fetch.html'))).to.eventually.be.rejectedWith('Failed to fetch'); + }); +}); diff --git a/spec/get-files.ts b/spec/get-files.ts new file mode 100644 index 0000000000000..519f694278174 --- /dev/null +++ b/spec/get-files.ts @@ -0,0 +1,11 @@ +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +export async function getFiles ( + dir: string, + test: ((file: string) => boolean) = (_: string) => true // eslint-disable-line @typescript-eslint/no-unused-vars +): Promise { + return fs.promises.readdir(dir) + .then(files => files.map(file => path.join(dir, file))) + .then(files => files.filter(file => test(file))); +} diff --git a/spec/global-paths.js b/spec/global-paths.js deleted file mode 100644 index fdad3fd3dd6f0..0000000000000 --- a/spec/global-paths.js +++ /dev/null @@ -1,13 +0,0 @@ -const Module = require('module'); - -module.exports = (paths) => { - const nodeModulePaths = Module._nodeModulePaths; - Module.ignoreGlobalPathsHack = false; - Module._nodeModulePaths = (from) => { - if (Module.ignoreGlobalPathsHack) { - return nodeModulePaths(from); - } else { - return nodeModulePaths(from).concat(paths); - } - }; -}; diff --git a/spec/guest-window-manager-spec.ts b/spec/guest-window-manager-spec.ts new file mode 100644 index 0000000000000..88daa4cfae2a6 --- /dev/null +++ b/spec/guest-window-manager-spec.ts @@ -0,0 +1,406 @@ +import { BrowserWindow, screen } from 'electron'; + +import { expect, assert } from 'chai'; + +import { once } from 'node:events'; +import * as http from 'node:http'; + +import { HexColors, ScreenCapture, hasCapturableScreen } from './lib/screen-helpers'; +import { ifit, listen } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +describe('webContents.setWindowOpenHandler', () => { + describe('native window', () => { + let browserWindow: BrowserWindow; + beforeEach(async () => { + browserWindow = new BrowserWindow({ show: false }); + await browserWindow.loadURL('about:blank'); + }); + + afterEach(closeAllWindows); + + it('does not fire window creation events if the handler callback throws an error', (done) => { + const error = new Error('oh no'); + const listeners = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + process.on('uncaughtException', (thrown) => { + try { + expect(thrown).to.equal(error); + done(); + } catch (e) { + done(e); + } finally { + process.removeAllListeners('uncaughtException'); + for (const listener of listeners) { + process.on('uncaughtException', listener); + } + } + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + browserWindow.webContents.setWindowOpenHandler(() => { + throw error; + }); + }); + + it('does not fire window creation events if the handler callback returns a bad result', async () => { + const bad = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return [1, 2, 3] as any; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await bad; + }); + + it('does not fire window creation events if an override returns action: deny', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await denied; + }); + + it('is called when clicking on a target=_blank link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + await browserWindow.webContents.loadURL('data:text/html,link'); + browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1 }); + browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1 }); + + await denied; + }); + + it('is called when shift-clicking on a link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + await browserWindow.webContents.loadURL('data:text/html,link'); + browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); + browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); + + await denied; + }); + + it('fires handler with correct params', async () => { + const testFrameName = 'test-frame-name'; + const testFeatures = 'top=10&left=10&something-unknown&show=no'; + const testUrl = 'app://does-not-exist/'; + const details = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; + }); + + browserWindow.webContents.executeJavaScript(`window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true`); + }); + const { url, frameName, features, disposition, referrer } = details; + expect(url).to.equal(testUrl); + expect(frameName).to.equal(testFrameName); + expect(features).to.equal(testFeatures); + expect(disposition).to.equal('new-window'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + }); + + it('includes post body', async () => { + const details = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; + }); + + browserWindow.webContents.loadURL(`data:text/html,${encodeURIComponent(` +
+ +
+ + `)}`); + }); + const { url, frameName, features, disposition, referrer, postBody } = details; + expect(url).to.equal('http://example.com/'); + expect(frameName).to.equal(''); + expect(features).to.deep.equal(''); + expect(disposition).to.equal('foreground-tab'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + expect(postBody).to.deep.equal({ + contentType: 'application/x-www-form-urlencoded', + data: [{ + type: 'rawData', + bytes: Buffer.from('key=value') + }] + }); + }); + + it('does fire window creation events if an override returns action: allow', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + + setImmediate(() => { + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + await once(browserWindow.webContents, 'did-create-window'); + }); + + it('can change webPreferences of child windows', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } })); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window') as Promise<[BrowserWindow, Electron.DidCreateWindowDetails]>; + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + const [childWindow] = await didCreateWindow; + + await childWindow.webContents.executeJavaScript("document.write('hello')"); + const size = await childWindow.webContents.executeJavaScript("getComputedStyle(document.querySelector('body')).fontSize"); + expect(size).to.equal('30px'); + }); + + it('does not hang parent window when denying window.open', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' })); + browserWindow.webContents.executeJavaScript("window.open('https://127.0.0.1')"); + expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42); + }); + + ifit(hasCapturableScreen())('should not make child window background transparent', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + const didCreateWindow = once(browserWindow.webContents, 'did-create-window'); + browserWindow.webContents.executeJavaScript("window.open('about:blank') && true"); + const [childWindow] = await didCreateWindow; + const display = screen.getPrimaryDisplay(); + childWindow.setBounds(display.bounds); + await childWindow.webContents.executeJavaScript("const meta = document.createElement('meta'); meta.name = 'color-scheme'; meta.content = 'dark'; document.head.appendChild(meta); true;"); + const screenCapture = new ScreenCapture(display); + // color-scheme is set to dark so background should not be white + await screenCapture.expectColorAtCenterDoesNotMatch(HexColors.WHITE); + }); + }); + + describe('custom window', () => { + let browserWindow: BrowserWindow; + + let server: http.Server; + let url: string; + + before(async () => { + server = http.createServer((request, response) => { + switch (request.url) { + case '/index': + response.statusCode = 200; + response.end('Index page'); + break; + case '/child': + response.statusCode = 200; + response.end('Child page'); + break; + case '/test': + response.statusCode = 200; + response.end('Test page'); + break; + default: + throw new Error(`Unsupported endpoint: ${request.url}`); + } + }); + + url = (await listen(server)).url; + }); + + after(() => { + server.close(); + }); + + beforeEach(async () => { + browserWindow = new BrowserWindow({ show: false }); + await browserWindow.loadURL(`${url}/index`); + }); + + afterEach(closeAllWindows); + + it('throws error when created window uses invalid webcontents', async () => { + const listeners = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + const uncaughtExceptionEmitted = new Promise((resolve, reject) => { + process.on('uncaughtException', (thrown) => { + try { + expect(thrown.message).to.equal('Invalid webContents. Created window should be connected to webContents passed with options object.'); + resolve(); + } catch (e) { + reject(e); + } finally { + process.removeAllListeners('uncaughtException'); + listeners.forEach((listener) => process.on('uncaughtException', listener)); + } + }); + }); + + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: () => { + const childWindow = new BrowserWindow({ title: 'New window' }); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await uncaughtExceptionEmitted; + }); + + it('spawns browser window when createWindow is provided', async () => { + const browserWindowTitle = 'Child browser window'; + + const childWindow = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow({ ...options, title: browserWindowTitle }); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + expect(childWindow.title).to.equal(browserWindowTitle); + }); + + it('should be able to access the child window document when createWindow is provided', async () => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const child = new BrowserWindow(options); + return child.webContents; + } + }; + }); + + const aboutBlankTitle = await browserWindow.webContents.executeJavaScript(` + const win1 = window.open('about:blank', '', 'show=no'); + win1.document.title = 'about-blank-title'; + win1.document.title; + `); + expect(aboutBlankTitle).to.equal('about-blank-title'); + + const serverPageTitle = await browserWindow.webContents.executeJavaScript(` + const win2 = window.open('${url}/child', '', 'show=no'); + win2.document.title = 'server-page-title'; + win2.document.title; + `); + expect(serverPageTitle).to.equal('server-page-title'); + }); + + it('spawns browser window with overridden options', async () => { + const childWindow = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + overrideBrowserWindowOptions: { + width: 640, + height: 480 + }, + createWindow: (options) => { + expect(options.width).to.equal(640); + expect(options.height).to.equal(480); + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + const size = childWindow.getSize(); + expect(size[0]).to.equal(640); + expect(size[1]).to.equal(480); + }); + + it('spawns browser window with access to opener property', async () => { + const childWindow = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript(`window.open('${url}/child', '', 'show=no') && true`); + }); + + await once(childWindow.webContents, 'ready-to-show'); + const childWindowOpenerTitle = await childWindow.webContents.executeJavaScript('window.opener.document.title'); + expect(childWindowOpenerTitle).to.equal(browserWindow.title); + }); + + it('spawns browser window without access to opener property because of noopener attribute ', async () => { + const childWindow = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + browserWindow.webContents.executeJavaScript(`window.open('${url}/child', '', 'noopener,show=no') && true`); + }); + + await once(childWindow.webContents, 'ready-to-show'); + await expect(childWindow.webContents.executeJavaScript('window.opener.document.title')).to.be.rejectedWith('Script failed to execute, this normally means an error was thrown. Check the renderer console for the error.'); + }); + }); +}); diff --git a/spec/index.js b/spec/index.js new file mode 100644 index 0000000000000..b31dc76824280 --- /dev/null +++ b/spec/index.js @@ -0,0 +1,196 @@ +const { app, protocol } = require('electron'); + +const fs = require('node:fs'); +const path = require('node:path'); +const v8 = require('node:v8'); + +const FAILURE_STATUS_KEY = 'Electron_Spec_Runner_Failures'; + +// We want to terminate on errors, not throw up a dialog +process.on('uncaughtException', (err) => { + console.error('Unhandled exception in main spec runner:', err); + process.exit(1); +}); + +// Tell ts-node which tsconfig to use +process.env.TS_NODE_PROJECT = path.resolve(__dirname, '../tsconfig.spec.json'); +process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'; + +// Some Linux machines have broken hardware acceleration support. +if (process.env.ELECTRON_TEST_DISABLE_HARDWARE_ACCELERATION) { + app.disableHardwareAcceleration(); +} + +v8.setFlagsFromString('--expose_gc'); +app.commandLine.appendSwitch('js-flags', '--expose_gc'); +// Prevent the spec runner quitting when the first window closes +app.on('window-all-closed', () => null); + +// Use fake device for Media Stream to replace actual camera and microphone. +app.commandLine.appendSwitch('use-fake-device-for-media-stream'); +app.commandLine.appendSwitch('host-rules', 'MAP localhost2 127.0.0.1'); +app.commandLine.appendSwitch('host-resolver-rules', [ + 'MAP ipv4.localhost2 10.0.0.1', + 'MAP ipv6.localhost2 [::1]', + 'MAP notfound.localhost2 ~NOTFOUND' +].join(', ')); + +// Enable features required by tests. +app.commandLine.appendSwitch('enable-features', [ + // spec/api-web-frame-main-spec.ts + 'DocumentPolicyIncludeJSCallStacksInCrashReports' +].join(',')); + +global.standardScheme = 'app'; +global.zoomScheme = 'zoom'; +global.serviceWorkerScheme = 'sw'; +protocol.registerSchemesAsPrivileged([ + { scheme: global.standardScheme, privileges: { standard: true, secure: true, stream: false } }, + { scheme: global.zoomScheme, privileges: { standard: true, secure: true } }, + { scheme: global.serviceWorkerScheme, privileges: { allowServiceWorkers: true, standard: true, secure: true } }, + { scheme: 'http-like', privileges: { standard: true, secure: true, corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'no-cors', privileges: { supportFetchAPI: true } }, + { scheme: 'no-fetch', privileges: { corsEnabled: true } }, + { scheme: 'stream', privileges: { standard: true, stream: true } }, + { scheme: 'foo', privileges: { standard: true } }, + { scheme: 'bar', privileges: { standard: true } } +]); + +app.whenReady().then(async () => { + require('ts-node/register'); + + const argv = require('yargs') + .boolean('ci') + .array('files') + .string('g').alias('g', 'grep') + .boolean('i').alias('i', 'invert') + .argv; + + const Mocha = require('mocha'); + const mochaOptions = { + forbidOnly: process.env.CI + }; + if (process.env.CI) { + mochaOptions.retries = 3; + } + if (process.env.MOCHA_REPORTER) { + mochaOptions.reporter = process.env.MOCHA_REPORTER; + } + if (process.env.MOCHA_MULTI_REPORTERS) { + mochaOptions.reporterOptions = { + reporterEnabled: process.env.MOCHA_MULTI_REPORTERS + }; + } + // The MOCHA_GREP and MOCHA_INVERT are used in some vendor builds for sharding + // tests. + if (process.env.MOCHA_GREP) { + mochaOptions.grep = process.env.MOCHA_GREP; + } + if (process.env.MOCHA_INVERT) { + mochaOptions.invert = process.env.MOCHA_INVERT === 'true'; + } + const mocha = new Mocha(mochaOptions); + + // Add a root hook on mocha to skip any tests that are disabled + const disabledTests = new Set( + JSON.parse( + fs.readFileSync(path.join(__dirname, 'disabled-tests.json'), 'utf8') + ) + ); + mocha.suite.beforeEach(function () { + // TODO(clavin): add support for disabling *suites* by title, not just tests + if (disabledTests.has(this.currentTest?.fullTitle())) { + this.skip(); + } + }); + + // The cleanup method is registered this way rather than through an + // `afterEach` at the top level so that it can run before other `afterEach` + // methods. + // + // The order of events is: + // 1. test completes, + // 2. `defer()`-ed methods run, in reverse order, + // 3. regular `afterEach` hooks run. + const { runCleanupFunctions } = require('./lib/spec-helpers'); + mocha.suite.on('suite', function attach (suite) { + suite.afterEach('cleanup', runCleanupFunctions); + suite.on('suite', attach); + }); + + if (!process.env.MOCHA_REPORTER) { + mocha.ui('bdd').reporter('tap'); + } + const mochaTimeout = process.env.MOCHA_TIMEOUT || 30000; + mocha.timeout(mochaTimeout); + + if (argv.grep) mocha.grep(argv.grep); + if (argv.invert) mocha.invert(); + + const baseElectronDir = path.resolve(__dirname, '..'); + const validTestPaths = argv.files && argv.files.map(file => + path.isAbsolute(file) + ? path.relative(baseElectronDir, file) + : path.normalize(file)); + const filter = (file) => { + if (!/-spec\.[tj]s$/.test(file)) { + return false; + } + + // This allows you to run specific modules only: + // npm run test -match=menu + const moduleMatch = process.env.npm_config_match + ? new RegExp(process.env.npm_config_match, 'g') + : null; + if (moduleMatch && !moduleMatch.test(file)) { + return false; + } + + if (validTestPaths && !validTestPaths.includes(path.relative(baseElectronDir, file))) { + return false; + } + + return true; + }; + + const { getFiles } = require('./get-files'); + const testFiles = await getFiles(__dirname, filter); + for (const file of testFiles.sort()) { + mocha.addFile(file); + } + + if (validTestPaths && validTestPaths.length > 0 && testFiles.length === 0) { + console.error('Test files were provided, but they did not match any searched files'); + console.error('provided file paths (relative to electron/):', validTestPaths); + process.exit(1); + } + + const cb = () => { + // Ensure the callback is called after runner is defined + process.nextTick(() => { + if (process.env.ELECTRON_FORCE_TEST_SUITE_EXIT === 'true') { + console.log(`${FAILURE_STATUS_KEY}: ${runner.failures}`); + process.kill(process.pid); + } else { + process.exit(runner.failures); + } + }); + }; + + // Set up chai in the correct order + const chai = require('chai'); + chai.use(require('chai-as-promised')); + chai.use(require('dirty-chai')); + + // Show full object diff + // https://github.com/chaijs/chai/issues/469 + chai.config.truncateThreshold = 0; + + const runner = mocha.run(cb); +}).catch((err) => { + console.error('An error occurred while running the spec runner'); + console.error(err); + process.exit(1); +}); diff --git a/spec/is-valid-window/.gitignore b/spec/is-valid-window/.gitignore new file mode 100644 index 0000000000000..41912cdec36b3 --- /dev/null +++ b/spec/is-valid-window/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/build +*.swp +*.log +*~ +.node-version +package-lock.json diff --git a/spec/is-valid-window/README.md b/spec/is-valid-window/README.md new file mode 100644 index 0000000000000..6727360b6adb0 --- /dev/null +++ b/spec/is-valid-window/README.md @@ -0,0 +1,8 @@ +# is-valid-window + +Validates if a pointer to window is valid. Used by Electron to validate the +result of `TopLevelWindow.getNativeWindowHandle`. + +## License + +Public domain. diff --git a/spec/is-valid-window/binding.gyp b/spec/is-valid-window/binding.gyp new file mode 100644 index 0000000000000..0de7c1f9d1719 --- /dev/null +++ b/spec/is-valid-window/binding.gyp @@ -0,0 +1,41 @@ +{ + 'target_defaults': { + 'conditions': [ + ['OS=="win"', { + 'msvs_disabled_warnings': [ + 4530, # C++ exception handler used, but unwind semantics are not enabled + 4506, # no definition for inline function + ], + }], + ], + }, + 'targets': [ + { + 'target_name': 'is_valid_window', + 'sources': [ + 'src/impl.h', + 'src/main.cc', + ], + 'conditions': [ + ['OS=="win"', { + 'sources': [ + 'src/impl_win.cc', + ], + }], + ['OS=="mac"', { + 'sources': [ + 'src/impl_darwin.mm', + ], + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', + ], + }], + ['OS not in ["mac", "win"]', { + 'sources': [ + 'src/impl_posix.cc', + ], + }], + ], + } + ] +} diff --git a/spec/is-valid-window/lib/is-valid-window.js b/spec/is-valid-window/lib/is-valid-window.js new file mode 100644 index 0000000000000..e3154cbc3015f --- /dev/null +++ b/spec/is-valid-window/lib/is-valid-window.js @@ -0,0 +1 @@ +module.exports = require('../build/Release/is_valid_window.node').isValidWindow; diff --git a/spec/is-valid-window/package.json b/spec/is-valid-window/package.json new file mode 100644 index 0000000000000..40e5c921451ea --- /dev/null +++ b/spec/is-valid-window/package.json @@ -0,0 +1,9 @@ +{ + "main": "./lib/is-valid-window.js", + "name": "is-valid-window", + "version": "0.0.5", + "licenses": "Public Domain", + "dependencies": { + "nan": "2.x" + } +} diff --git a/spec/is-valid-window/src/impl.h b/spec/is-valid-window/src/impl.h new file mode 100644 index 0000000000000..b211ff05dc5d5 --- /dev/null +++ b/spec/is-valid-window/src/impl.h @@ -0,0 +1,12 @@ +#ifndef SRC_IMPL_H_ +#define SRC_IMPL_H_ + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size); + +} // namespace impl + +#endif // SRC_IMPL_H_ diff --git a/spec/is-valid-window/src/impl_darwin.mm b/spec/is-valid-window/src/impl_darwin.mm new file mode 100644 index 0000000000000..ef71aed16258d --- /dev/null +++ b/spec/is-valid-window/src/impl_darwin.mm @@ -0,0 +1,14 @@ +#include "impl.h" + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + if (size != sizeof(NSView*)) + return false; + NSView* view = *reinterpret_cast(handle); + return [view isKindOfClass:[NSView class]]; +} + +} // namespace impl diff --git a/spec/is-valid-window/src/impl_posix.cc b/spec/is-valid-window/src/impl_posix.cc new file mode 100644 index 0000000000000..6c582b6ffb95f --- /dev/null +++ b/spec/is-valid-window/src/impl_posix.cc @@ -0,0 +1,9 @@ +#include "impl.h" + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + return true; +} + +} // namespace impl diff --git a/spec/is-valid-window/src/impl_win.cc b/spec/is-valid-window/src/impl_win.cc new file mode 100644 index 0000000000000..91d272bdc5db1 --- /dev/null +++ b/spec/is-valid-window/src/impl_win.cc @@ -0,0 +1,14 @@ +#include "impl.h" + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + if (size != sizeof(HWND)) + return false; + HWND window = *reinterpret_cast(handle); + return ::IsWindow(window); +} + +} // namespace impl diff --git a/spec/is-valid-window/src/main.cc b/spec/is-valid-window/src/main.cc new file mode 100644 index 0000000000000..b14e38b7d3d60 --- /dev/null +++ b/spec/is-valid-window/src/main.cc @@ -0,0 +1,56 @@ +#include +#include + +#include "impl.h" + +namespace { + +napi_value IsValidWindow(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1], result; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + if (status != napi_ok) + return NULL; + + bool is_buffer; + status = napi_is_buffer(env, args[0], &is_buffer); + if (status != napi_ok) + return NULL; + + if (!is_buffer) { + napi_throw_error(env, NULL, "First argument must be Buffer"); + return NULL; + } + + char* data; + size_t length; + status = napi_get_buffer_info(env, args[0], (void**)&data, &length); + if (status != napi_ok) + return NULL; + + status = napi_get_boolean(env, impl::IsValidWindow(data, length), &result); + if (status != napi_ok) + return NULL; + + return result; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = {{"isValidWindow", NULL, + IsValidWindow, NULL, NULL, NULL, + napi_default, NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/lib/artifacts.ts b/spec/lib/artifacts.ts new file mode 100644 index 0000000000000..433a119507e7d --- /dev/null +++ b/spec/lib/artifacts.ts @@ -0,0 +1,36 @@ +import { randomBytes } from 'node:crypto'; +import fs = require('node:fs/promises'); +import path = require('node:path'); + +const IS_CI = !!process.env.CI; +const ARTIFACT_DIR = path.join(__dirname, '..', 'artifacts'); + +async function ensureArtifactDir (): Promise { + if (!IS_CI) { + return; + } + + await fs.mkdir(ARTIFACT_DIR, { recursive: true }); +} + +export async function createArtifact ( + fileName: string, + data: Buffer +): Promise { + if (!IS_CI) { + return; + } + + await ensureArtifactDir(); + await fs.writeFile(path.join(ARTIFACT_DIR, fileName), data); +} + +export async function createArtifactWithRandomId ( + makeFileName: (id: string) => string, + data: Buffer +): Promise { + const randomId = randomBytes(12).toString('hex'); + const fileName = makeFileName(randomId); + await createArtifact(fileName, data); + return fileName; +} diff --git a/spec/lib/codesign-helpers.ts b/spec/lib/codesign-helpers.ts new file mode 100644 index 0000000000000..9e43f482192a6 --- /dev/null +++ b/spec/lib/codesign-helpers.ts @@ -0,0 +1,83 @@ +import { expect } from 'chai'; + +import * as cp from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +const features = process._linkedBinding('electron_common_features'); +const fixturesPath = path.resolve(__dirname, '..', 'fixtures'); + +export const shouldRunCodesignTests = + process.platform === 'darwin' && + !(process.env.CI && process.arch === 'arm64') && + !process.mas && + !features.isComponentBuild(); + +let identity: string | null; + +export function getCodesignIdentity () { + if (identity === undefined) { + const result = cp.spawnSync(path.resolve(__dirname, '../../script/codesign/get-trusted-identity.sh')); + if (result.status !== 0 || result.stdout.toString().trim().length === 0) { + identity = null; + } else { + identity = result.stdout.toString().trim(); + } + } + return identity; +} + +export async function copyMacOSFixtureApp (newDir: string, fixture: string | null = 'initial') { + const appBundlePath = path.resolve(process.execPath, '../../..'); + const newPath = path.resolve(newDir, 'Electron.app'); + cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]); + if (fixture) { + const appDir = path.resolve(newPath, 'Contents/Resources/app'); + await fs.promises.mkdir(appDir, { recursive: true }); + await fs.promises.cp(path.resolve(fixturesPath, 'auto-update', fixture), appDir, { recursive: true }); + } + const plistPath = path.resolve(newPath, 'Contents', 'Info.plist'); + await fs.promises.writeFile( + plistPath, + (await fs.promises.readFile(plistPath, 'utf8')).replace('BuildMachineOSBuild', `NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + + BuildMachineOSBuild`) + ); + return newPath; +}; + +export function spawn (cmd: string, args: string[], opts: any = {}) { + let out = ''; + const child = cp.spawn(cmd, args, opts); + child.stdout.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + child.stderr.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + return new Promise<{ code: number, out: string }>((resolve) => { + child.on('exit', (code, signal) => { + expect(signal).to.equal(null); + resolve({ + code: code!, + out + }); + }); + }); +}; + +export function signApp (appPath: string, identity: string) { + return spawn('codesign', ['-s', identity, '--deep', '--force', appPath]); +}; diff --git a/spec/lib/deprecate-helpers.ts b/spec/lib/deprecate-helpers.ts new file mode 100644 index 0000000000000..524e656dd56d9 --- /dev/null +++ b/spec/lib/deprecate-helpers.ts @@ -0,0 +1,26 @@ +import { expect } from 'chai'; + +export async function expectDeprecationMessages (func: () => any, ...expected: string[]) { + const messages: string[] = []; + + const originalWarn = console.warn; + console.warn = (message) => { + messages.push(message); + }; + + const warningListener = (error: Error) => { + messages.push(error.message); + }; + + process.on('warning', warningListener); + + try { + return await func(); + } finally { + // process.emitWarning seems to need us to wait a tick + await new Promise(process.nextTick); + console.warn = originalWarn; + process.off('warning' as any, warningListener); + expect(messages).to.deep.equal(expected); + } +} diff --git a/spec/lib/events-helpers.ts b/spec/lib/events-helpers.ts new file mode 100644 index 0000000000000..ead2cb55391cf --- /dev/null +++ b/spec/lib/events-helpers.ts @@ -0,0 +1,24 @@ +/** + * @fileoverview A set of helper functions to make it easier to work + * with events in async/await manner. + */ + +import { on } from 'node:events'; + +export const emittedNTimes = async (emitter: NodeJS.EventEmitter, eventName: string, times: number, trigger?: () => void) => { + const events: any[][] = []; + const iter = on(emitter, eventName); + if (trigger) await Promise.resolve(trigger()); + for await (const args of iter) { + events.push(args); + if (events.length === times) { break; } + } + return events; +}; + +export const emittedUntil = async (emitter: NodeJS.EventEmitter, eventName: string, untilFn: Function) => { + for await (const args of on(emitter, eventName)) { + if (untilFn(...args)) { return args; } + } + return []; +}; diff --git a/spec/lib/fs-helpers.ts b/spec/lib/fs-helpers.ts new file mode 100644 index 0000000000000..58e67f0b276c7 --- /dev/null +++ b/spec/lib/fs-helpers.ts @@ -0,0 +1,40 @@ +import * as fs from 'original-fs'; + +import * as cp from 'node:child_process'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +export async function copyApp (targetDir: string): Promise { + // On macOS we can just copy the app bundle, easier too because of symlinks + if (process.platform === 'darwin') { + const appBundlePath = path.resolve(process.execPath, '../../..'); + const newPath = path.resolve(targetDir, 'Electron.app'); + cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]); + return newPath; + } + + // On windows and linux we should read the zip manifest files and then copy each of those files + // one by one + const baseDir = path.dirname(process.execPath); + const zipManifestPath = path.resolve(__dirname, '..', '..', 'script', 'zip_manifests', `dist_zip.${process.platform === 'win32' ? 'win' : 'linux'}.${process.arch === 'ia32' ? 'x86' : process.arch}.manifest`); + const filesToCopy = (fs.readFileSync(zipManifestPath, 'utf-8')).split('\n').filter(f => f !== 'LICENSE' && f !== 'LICENSES.chromium.html' && f !== 'version' && f.trim()); + await Promise.all( + filesToCopy.map(async rel => { + await fs.promises.mkdir(path.dirname(path.resolve(targetDir, rel)), { recursive: true }); + fs.copyFileSync(path.resolve(baseDir, rel), path.resolve(targetDir, rel)); + }) + ); + + return path.resolve(targetDir, path.basename(process.execPath)); +} + +export async function withTempDirectory (fn: (dir: string) => Promise, autoCleanUp = true) { + const dir = await fs.promises.mkdtemp(path.resolve(os.tmpdir(), 'electron-update-spec-')); + try { + await fn(dir); + } finally { + if (autoCleanUp) { + cp.spawnSync('rm', ['-r', dir]); + } + } +}; diff --git a/spec/lib/net-helpers.ts b/spec/lib/net-helpers.ts new file mode 100644 index 0000000000000..7500ac755e052 --- /dev/null +++ b/spec/lib/net-helpers.ts @@ -0,0 +1,110 @@ +import { expect } from 'chai'; + +import * as dns from 'node:dns'; +import * as http from 'node:http'; +import { Socket } from 'node:net'; + +import { defer, listen } from './spec-helpers'; + +// See https://github.com/nodejs/node/issues/40702. +dns.setDefaultResultOrder('ipv4first'); + +export const kOneKiloByte = 1024; +export const kOneMegaByte = kOneKiloByte * kOneKiloByte; + +export function randomBuffer (size: number, start: number = 0, end: number = 255) { + const range = 1 + end - start; + const buffer = Buffer.allocUnsafe(size); + for (let i = 0; i < size; ++i) { + buffer[i] = start + Math.floor(Math.random() * range); + } + return buffer; +} + +export function randomString (length: number) { + const buffer = randomBuffer(length, '0'.charCodeAt(0), 'z'.charCodeAt(0)); + return buffer.toString(); +} + +export async function getResponse (urlRequest: Electron.ClientRequest) { + return new Promise((resolve, reject) => { + urlRequest.on('error', reject); + urlRequest.on('abort', reject); + urlRequest.on('response', (response) => resolve(response)); + urlRequest.end(); + }); +} + +export async function collectStreamBody (response: Electron.IncomingMessage | http.IncomingMessage) { + return (await collectStreamBodyBuffer(response)).toString(); +} + +export function collectStreamBodyBuffer (response: Electron.IncomingMessage | http.IncomingMessage) { + return new Promise((resolve, reject) => { + response.on('error', reject); + (response as NodeJS.EventEmitter).on('aborted', reject); + const data: Buffer[] = []; + response.on('data', (chunk) => data.push(chunk)); + response.on('end', (chunk?: Buffer) => { + if (chunk) data.push(chunk); + resolve(Buffer.concat(data)); + }); + }); +} + +export async function respondNTimes (fn: http.RequestListener, n: number): Promise { + const server = http.createServer((request, response) => { + fn(request, response); + // don't close if a redirect was returned + if ((response.statusCode < 300 || response.statusCode >= 399) && n <= 0) { + n--; + server.close(); + } + }); + const sockets: Socket[] = []; + server.on('connection', s => sockets.push(s)); + defer(() => { + server.close(); + for (const socket of sockets) { + socket.destroy(); + } + }); + return (await listen(server)).url; +} + +export function respondOnce (fn: http.RequestListener) { + return respondNTimes(fn, 1); +} + +respondNTimes.routeFailure = false; + +respondNTimes.toRoutes = (routes: Record, n: number) => { + return respondNTimes((request, response) => { + if (Object.hasOwn(routes, request.url || '')) { + (async () => { + await Promise.resolve(routes[request.url || ''](request, response)); + })().catch((err) => { + respondNTimes.routeFailure = true; + console.error('Route handler failed, this is probably why your test failed', err); + response.statusCode = 500; + response.end(); + }); + } else { + response.statusCode = 500; + response.end(); + expect.fail(`Unexpected URL: ${request.url}`); + } + }, n); +}; +respondOnce.toRoutes = (routes: Record) => respondNTimes.toRoutes(routes, 1); + +respondNTimes.toURL = (url: string, fn: http.RequestListener, n: number) => { + return respondNTimes.toRoutes({ [url]: fn }, n); +}; +respondOnce.toURL = (url: string, fn: http.RequestListener) => respondNTimes.toURL(url, fn, 1); + +respondNTimes.toSingleURL = (fn: http.RequestListener, n: number) => { + const requestUrl = '/requestUrl'; + return respondNTimes.toURL(requestUrl, fn, n).then(url => `${url}${requestUrl}`); +}; +respondOnce.toSingleURL = (fn: http.RequestListener) => respondNTimes.toSingleURL(fn, 1); diff --git a/spec/lib/screen-helpers.ts b/spec/lib/screen-helpers.ts new file mode 100644 index 0000000000000..0fb3128611ddb --- /dev/null +++ b/spec/lib/screen-helpers.ts @@ -0,0 +1,206 @@ +import { screen, desktopCapturer, NativeImage } from 'electron'; + +import { AssertionError } from 'chai'; + +import { createArtifactWithRandomId } from './artifacts'; + +export enum HexColors { + GREEN = '#00b140', + PURPLE = '#6a0dad', + RED = '#ff0000', + BLUE = '#0000ff', + WHITE = '#ffffff', +} + +function hexToRgba ( + hexColor: string +): [number, number, number, number] | undefined { + const match = hexColor.match(/^#([0-9a-fA-F]{6,8})$/); + if (!match) return; + + const colorStr = match[1]; + return [ + parseInt(colorStr.substring(0, 2), 16), + parseInt(colorStr.substring(2, 4), 16), + parseInt(colorStr.substring(4, 6), 16), + parseInt(colorStr.substring(6, 8), 16) || 0xff + ]; +} + +function formatHexByte (val: number): string { + const str = val.toString(16); + return str.length === 2 ? str : `0${str}`; +} + +/** + * Get the hex color at the given pixel coordinate in an image. + */ +function getPixelColor ( + image: Electron.NativeImage, + point: Electron.Point +): string { + // image.crop crashes if point is fractional, so round to prevent that crash + const pixel = image.crop({ + x: Math.round(point.x), + y: Math.round(point.y), + width: 1, + height: 1 + }); + // TODO(samuelmaddock): NativeImage.toBitmap() should return the raw pixel + // color, but it sometimes differs. Why is that? + const [b, g, r] = pixel.toBitmap(); + return `#${formatHexByte(r)}${formatHexByte(g)}${formatHexByte(b)}`; +} + +/** Calculate euclidean distance between colors. */ +function colorDistance (hexColorA: string, hexColorB: string): number { + const colorA = hexToRgba(hexColorA); + const colorB = hexToRgba(hexColorB); + if (!colorA || !colorB) return -1; + return Math.sqrt( + Math.pow(colorB[0] - colorA[0], 2) + + Math.pow(colorB[1] - colorA[1], 2) + + Math.pow(colorB[2] - colorA[2], 2) + ); +} + +/** + * Determine if colors are similar based on distance. This can be useful when + * comparing colors which may differ based on lossy compression. + */ +function areColorsSimilar ( + hexColorA: string, + hexColorB: string, + distanceThreshold = 90 +): boolean { + const distance = colorDistance(hexColorA, hexColorB); + return distance <= distanceThreshold; +} + +function displayCenter (display: Electron.Display): Electron.Point { + return { + x: display.size.width / 2, + y: display.size.height / 2 + }; +} + +/** Resolve when approx. one frame has passed (30FPS) */ +export async function nextFrameTime (): Promise { + return await new Promise((resolve) => { + setTimeout(resolve, 1000 / 30); + }); +} + +/** + * Utilities for creating and inspecting a screen capture. + * + * Set `PAUSE_CAPTURE_TESTS` env var to briefly pause during screen + * capture for easier inspection. + * + * NOTE: Not yet supported on Linux in CI due to empty sources list. + */ +export class ScreenCapture { + /** Timeout to wait for expected color to match. */ + static TIMEOUT = 3000; + + constructor (display?: Electron.Display) { + this.display = display || screen.getPrimaryDisplay(); + } + + public async expectColorAtCenterMatches (hexColor: string) { + return this._expectImpl(displayCenter(this.display), hexColor, true); + } + + public async expectColorAtCenterDoesNotMatch (hexColor: string) { + return this._expectImpl(displayCenter(this.display), hexColor, false); + } + + public async expectColorAtPointOnDisplayMatches ( + hexColor: string, + findPoint: (displaySize: Electron.Size) => Electron.Point + ) { + return this._expectImpl(findPoint(this.display.size), hexColor, true); + } + + private async captureFrame (): Promise { + const sources = await desktopCapturer.getSources({ + types: ['screen'], + thumbnailSize: this.display.size + }); + + const captureSource = sources.find( + (source) => source.display_id === this.display.id.toString() + ); + if (captureSource === undefined) { + const displayIds = sources.map((source) => source.display_id).join(', '); + throw new Error( + `Unable to find screen capture for display '${this.display.id}'\n\tAvailable displays: ${displayIds}` + ); + } + + if (process.env.PAUSE_CAPTURE_TESTS) { + await new Promise((resolve) => setTimeout(resolve, 1e3)); + } + + return captureSource.thumbnail; + } + + private async _expectImpl ( + point: Electron.Point, + expectedColor: string, + matchIsExpected: boolean + ) { + let frame: Electron.NativeImage; + let actualColor: string; + let gotExpectedResult: boolean = false; + const expiration = Date.now() + ScreenCapture.TIMEOUT; + + // Continuously capture frames until we either see the expected result or + // reach a timeout. This helps avoid flaky tests in which a short waiting + // period is required for the expected result. + do { + frame = await this.captureFrame(); + actualColor = getPixelColor(frame, point); + const colorsMatch = areColorsSimilar(expectedColor, actualColor); + gotExpectedResult = matchIsExpected ? colorsMatch : !colorsMatch; + if (gotExpectedResult) break; + + await nextFrameTime(); // limit framerate + } while (Date.now() < expiration); + + if (!gotExpectedResult) { + // Limit image to 720p to save on storage space + if (process.env.CI) { + const width = Math.floor(Math.min(frame.getSize().width, 720)); + frame = frame.resize({ width }); + } + + // Save the image as an artifact for better debugging + const artifactName = await createArtifactWithRandomId( + (id) => `color-mismatch-${id}.png`, + frame.toPNG() + ); + + throw new AssertionError( + `Expected color at (${point.x}, ${point.y}) to ${ + matchIsExpected ? 'match' : '*not* match' + } '${expectedColor}', but got '${actualColor}'. See the artifact '${artifactName}' for more information.` + ); + } + } + + private display: Electron.Display; +} + +/** + * Whether the current VM has a valid screen which can be used to capture. + * + * This is specific to Electron's CI test runners. + * - Linux: virtual screen display is 0x0 + * - Win32 arm64 (WOA): virtual screen display is 0x0 + * - Win32 ia32: skipped + * - Win32 x64: virtual screen display is 0x0 + */ +export const hasCapturableScreen = () => { + return process.env.CI ? process.platform === 'darwin' : true; +}; diff --git a/spec/lib/spec-helpers.ts b/spec/lib/spec-helpers.ts new file mode 100644 index 0000000000000..85a31ddd3bf0b --- /dev/null +++ b/spec/lib/spec-helpers.ts @@ -0,0 +1,229 @@ +import { BrowserWindow } from 'electron/main'; + +import { AssertionError } from 'chai'; +import { SuiteFunction, TestFunction } from 'mocha'; + +import * as childProcess from 'node:child_process'; +import * as http from 'node:http'; +import * as http2 from 'node:http2'; +import * as https from 'node:https'; +import * as net from 'node:net'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; +import * as url from 'node:url'; +import * as v8 from 'node:v8'; + +const addOnly = (fn: Function): T => { + const wrapped = (...args: any[]) => { + return fn(...args); + }; + (wrapped as any).only = wrapped; + (wrapped as any).skip = wrapped; + return wrapped as any; +}; + +export const ifit = (condition: boolean) => (condition ? it : addOnly(it.skip)); +export const ifdescribe = (condition: boolean) => (condition ? describe : addOnly(describe.skip)); + +type CleanupFunction = (() => void) | (() => Promise) +const cleanupFunctions: CleanupFunction[] = []; +export async function runCleanupFunctions () { + for (const cleanup of cleanupFunctions) { + const r = cleanup(); + if (r instanceof Promise) { await r; } + } + cleanupFunctions.length = 0; +} + +export function defer (f: CleanupFunction) { + cleanupFunctions.unshift(f); +} + +class RemoteControlApp { + process: childProcess.ChildProcess; + port: number; + + constructor (proc: childProcess.ChildProcess, port: number) { + this.process = proc; + this.port = port; + } + + remoteEval = (js: string): Promise => { + return new Promise((resolve, reject) => { + const req = http.request({ + host: '127.0.0.1', + port: this.port, + method: 'POST' + }, res => { + const chunks = [] as Buffer[]; + res.on('data', chunk => { chunks.push(chunk); }); + res.on('end', () => { + const ret = v8.deserialize(Buffer.concat(chunks)); + if (Object.hasOwn(ret, 'error')) { + reject(new Error(`remote error: ${ret.error}\n\nTriggered at:`)); + } else { + resolve(ret.result); + } + }); + }); + req.write(js); + req.end(); + }); + }; + + remotely = (script: Function, ...args: any[]): Promise => { + return this.remoteEval(`(${script})(...${JSON.stringify(args)})`); + }; +} + +export async function startRemoteControlApp (extraArgs: string[] = [], options?: childProcess.SpawnOptionsWithoutStdio) { + const appPath = path.join(__dirname, '..', 'fixtures', 'apps', 'remote-control'); + const appProcess = childProcess.spawn(process.execPath, [appPath, ...extraArgs], options); + appProcess.stderr.on('data', d => { + process.stderr.write(d); + }); + const port = await new Promise(resolve => { + appProcess.stdout.on('data', d => { + const m = /Listening: (\d+)/.exec(d.toString()); + if (m && m[1] != null) { + resolve(Number(m[1])); + } + }); + }); + defer(() => { appProcess.kill('SIGINT'); }); + return new RemoteControlApp(appProcess, port); +} + +export function waitUntil ( + callback: () => boolean|Promise, + opts: { rate?: number, timeout?: number } = {} +) { + const { rate = 10, timeout = 10000 } = opts; + return (async () => { + const ac = new AbortController(); + const signal = ac.signal; + let checkCompleted = false; + let timedOut = false; + + const check = async () => { + let result; + + try { + result = await callback(); + } catch (e) { + ac.abort(); + throw e; + } + + return result; + }; + + setTimeout(timeout, { signal }) + .then(() => { + timedOut = true; + checkCompleted = true; + }); + + while (checkCompleted === false) { + const checkSatisfied = await check(); + if (checkSatisfied === true) { + ac.abort(); + checkCompleted = true; + return; + } else { + await setTimeout(rate); + } + } + + if (timedOut) { + throw new Error(`waitUntil timed out after ${timeout}ms`); + } + })(); +} + +export async function repeatedly ( + fn: () => Promise, + opts?: { until?: (x: T) => boolean, timeLimit?: number } +) { + const { until = (x: T) => !!x, timeLimit = 10000 } = opts ?? {}; + const begin = Date.now(); + while (true) { + const ret = await fn(); + if (until(ret)) { return ret; } + if (Date.now() - begin > timeLimit) { throw new Error(`repeatedly timed out (limit=${timeLimit})`); } + } +} + +async function makeRemoteContext (opts?: any) { + const { webPreferences, setup, url = 'about:blank', ...rest } = opts ?? {}; + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false, ...webPreferences }, ...rest }); + await w.loadURL(url.toString()); + if (setup) await w.webContents.executeJavaScript(setup); + return w; +} + +const remoteContext: BrowserWindow[] = []; +export async function getRemoteContext () { + if (remoteContext.length) { return remoteContext[0]; } + const w = await makeRemoteContext(); + defer(() => w.close()); + return w; +} + +export function useRemoteContext (opts?: any) { + before(async () => { + remoteContext.unshift(await makeRemoteContext(opts)); + }); + after(() => { + const w = remoteContext.shift(); + w!.close(); + }); +} + +async function runRemote (type: 'skip' | 'none' | 'only', name: string, fn: Function, args?: any[]) { + const wrapped = async () => { + const w = await getRemoteContext(); + const { ok, message } = await w.webContents.executeJavaScript(`(async () => { + try { + const chai_1 = require('chai') + const promises_1 = require('node:timers/promises') + chai_1.use(require('chai-as-promised')) + chai_1.use(require('dirty-chai')) + await (${fn})(...${JSON.stringify(args ?? [])}) + return {ok: true}; + } catch (e) { + return {ok: false, message: e.message} + } + })()`); + if (!ok) { throw new AssertionError(message); } + }; + + let runFn: any = it; + if (type === 'only') { + runFn = it.only; + } else if (type === 'skip') { + runFn = it.skip; + } + + runFn(name, wrapped); +} + +export const itremote = Object.assign( + (name: string, fn: Function, args?: any[]) => { + runRemote('none', name, fn, args); + }, { + only: (name: string, fn: Function, args?: any[]) => { + runRemote('only', name, fn, args); + }, + skip: (name: string, fn: Function, args?: any[]) => { + runRemote('skip', name, fn, args); + } + }); + +export async function listen (server: http.Server | https.Server | http2.Http2SecureServer) { + const hostname = '127.0.0.1'; + await new Promise(resolve => server.listen(0, hostname, () => resolve())); + const { port } = server.address() as net.AddressInfo; + const protocol = (server instanceof http.Server) ? 'http' : 'https'; + return { port, hostname, url: url.format({ protocol, hostname, port }) }; +} diff --git a/spec-main/video-helpers.js b/spec/lib/video-helpers.js similarity index 95% rename from spec-main/video-helpers.js rename to spec/lib/video-helpers.js index d5538c8eab15a..2a0b9b95b19f3 100644 --- a/spec-main/video-helpers.js +++ b/spec/lib/video-helpers.js @@ -259,9 +259,9 @@ function checkFrames (frames) { duration += frames[i].duration; } return { - duration: duration, - width: width, - height: height + duration, + width, + height }; } @@ -313,16 +313,16 @@ function bitsToBuffer (bits) { function generateEBML (json) { const ebml = []; - for (let i = 0; i < json.length; i++) { - if (!('id' in json[i])) { + for (const item of json) { + if (!('id' in item)) { // already encoded blob or byteArray - ebml.push(json[i]); + ebml.push(item); continue; } - let data = json[i].data; + let data = item.data; if (typeof data === 'object') data = generateEBML(data); - if (typeof data === 'number') data = ('size' in json[i]) ? numToFixedBuffer(data, json[i].size) : bitsToBuffer(data.toString(2)); + if (typeof data === 'number') data = ('size' in item) ? numToFixedBuffer(data, item.size) : bitsToBuffer(data.toString(2)); if (typeof data === 'string') data = strToBuffer(data); const len = data.size || data.byteLength || data.length; @@ -335,7 +335,7 @@ function generateEBML (json) { // going to fix this, i'm probably just going to write some hacky thing which // converts that string into a buffer-esque thing - ebml.push(numToBuffer(json[i].id)); + ebml.push(numToBuffer(item.id)); ebml.push(bitsToBuffer(size)); ebml.push(data); } @@ -349,13 +349,13 @@ function toFlatArray (arr, outBuffer) { if (outBuffer == null) { outBuffer = []; } - for (let i = 0; i < arr.length; i++) { - if (typeof arr[i] === 'object') { + for (const item of arr) { + if (typeof item === 'object') { // an array - toFlatArray(arr[i], outBuffer); + toFlatArray(item, outBuffer); } else { // a simple element - outBuffer.push(arr[i]); + outBuffer.push(item); } } return outBuffer; @@ -394,10 +394,12 @@ function parseWebP (riff) { const height = tmp & 0x3FFF; const verticalScale = tmp >> 14; return { - width: width, - height: height, + width, + height, + horizontalScale, + verticalScale, data: VP8, - riff: riff + riff }; } @@ -440,7 +442,7 @@ function parseRIFF (string) { // basically, the only purpose is for encoding "Duration", which is encoded as // a double (considerably more difficult to encode than an integer) function doubleToString (num) { - return [].slice.call( + return Array.prototype.slice.call( new Uint8Array( ( new Float64Array([num]) // create a float64 array @@ -475,7 +477,7 @@ WhammyVideo.prototype.add = function (frame, duration) { // quickly store image data so we don't block cpu. encode in compile method. frame = frame.getContext('2d').getImageData(0, 0, frame.width, frame.height); } else if (typeof frame !== 'string') { - throw new Error('frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string'); + throw new TypeError('frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string'); } if (typeof frame === 'string' && !(/^data:image\/webp;base64,/ig).test(frame)) { throw new Error('Input must be formatted properly as a base64 encoded DataURI of type image/webp'); diff --git a/spec/lib/window-helpers.ts b/spec/lib/window-helpers.ts new file mode 100644 index 0000000000000..42d3beb39e1f3 --- /dev/null +++ b/spec/lib/window-helpers.ts @@ -0,0 +1,70 @@ +import { BaseWindow, BrowserWindow, webContents } from 'electron/main'; + +import { expect } from 'chai'; + +import { once } from 'node:events'; + +async function ensureWindowIsClosed (window: BaseWindow | null) { + if (window && !window.isDestroyed()) { + if (window instanceof BrowserWindow && window.webContents && !window.webContents.isDestroyed()) { + // If a window isn't destroyed already, and it has non-destroyed WebContents, + // then calling destroy() won't immediately destroy it, as it may have + // children which need to be destroyed first. In that case, we + // await the 'closed' event which signals the complete shutdown of the + // window. + const isClosed = once(window, 'closed'); + window.destroy(); + await isClosed; + } else { + // If there's no WebContents or if the WebContents is already destroyed, + // then the 'closed' event has already been emitted so there's nothing to + // wait for. + window.destroy(); + } + } +} + +export const closeWindow = async ( + window: BaseWindow | null = null, + { assertNotWindows } = { assertNotWindows: true } +) => { + await ensureWindowIsClosed(window); + + if (assertNotWindows) { + let windows = BaseWindow.getAllWindows(); + if (windows.length > 0) { + setTimeout(async () => { + // Wait until next tick to assert that all windows have been closed. + windows = BaseWindow.getAllWindows(); + try { + expect(windows).to.have.lengthOf(0); + } finally { + for (const win of windows) { + await ensureWindowIsClosed(win); + } + } + }); + } + } +}; + +export async function closeAllWindows (assertNotWindows = false) { + let windowsClosed = 0; + for (const w of BaseWindow.getAllWindows()) { + await closeWindow(w, { assertNotWindows }); + windowsClosed++; + } + return windowsClosed; +} + +export async function cleanupWebContents () { + let webContentsDestroyed = 0; + const existingWCS = webContents.getAllWebContents(); + for (const contents of existingWCS) { + const isDestroyed = once(contents, 'destroyed'); + contents.destroy(); + await isDestroyed; + webContentsDestroyed++; + } + return webContentsDestroyed; +} diff --git a/spec-main/logging-spec.ts b/spec/logging-spec.ts similarity index 95% rename from spec-main/logging-spec.ts rename to spec/logging-spec.ts index a98ed4b9532a3..46fa410a07d2f 100644 --- a/spec-main/logging-spec.ts +++ b/spec/logging-spec.ts @@ -1,12 +1,14 @@ import { app } from 'electron'; -import { expect } from 'chai'; -import { emittedOnce } from './events-helpers'; -import { startRemoteControlApp, ifdescribe } from './spec-helpers'; -import * as fs from 'fs/promises'; -import * as path from 'path'; +import { expect } from 'chai'; import * as uuid from 'uuid'; +import { once } from 'node:events'; +import * as fs from 'node:fs/promises'; +import * as path from 'node:path'; + +import { startRemoteControlApp, ifdescribe } from './lib/spec-helpers'; + function isTestingBindingAvailable () { try { process._linkedBinding('electron_common_testing'); @@ -87,7 +89,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => { setTimeout(() => { app.quit(); }); return app.getPath('userData'); }); - await emittedOnce(rc.process, 'exit'); + await once(rc.process, 'exit'); const logFilePath = path.join(userDataDir, 'electron_debug.log'); const stat = await fs.stat(logFilePath); expect(stat.isFile()).to.be.true(); @@ -103,7 +105,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => { setTimeout(() => { app.quit(); }); return app.getPath('userData'); }); - await emittedOnce(rc.process, 'exit'); + await once(rc.process, 'exit'); const logFilePath = path.join(userDataDir, 'electron_debug.log'); const stat = await fs.stat(logFilePath); expect(stat.isFile()).to.be.true(); @@ -118,7 +120,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => { process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); setTimeout(() => { require('electron').app.quit(); }); }); - await emittedOnce(rc.process, 'exit'); + await once(rc.process, 'exit'); const stat = await fs.stat(logFilePath); expect(stat.isFile()).to.be.true(); const contents = await fs.readFile(logFilePath, 'utf8'); @@ -132,7 +134,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => { process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); setTimeout(() => { require('electron').app.quit(); }); }); - await emittedOnce(rc.process, 'exit'); + await once(rc.process, 'exit'); const stat = await fs.stat(logFilePath); expect(stat.isFile()).to.be.true(); const contents = await fs.readFile(logFilePath, 'utf8'); @@ -146,7 +148,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => { process._linkedBinding('electron_common_testing').log(0, 'LATER_LOG'); setTimeout(() => { require('electron').app.quit(); }); }); - await emittedOnce(rc.process, 'exit'); + await once(rc.process, 'exit'); const stat = await fs.stat(logFilePath); expect(stat.isFile()).to.be.true(); const contents = await fs.readFile(logFilePath, 'utf8'); diff --git a/spec/modules-spec.ts b/spec/modules-spec.ts new file mode 100644 index 0000000000000..ecfdf1a9e8a35 --- /dev/null +++ b/spec/modules-spec.ts @@ -0,0 +1,251 @@ +import { BrowserWindow } from 'electron/main'; + +import { expect } from 'chai'; + +import * as childProcess from 'node:child_process'; +import { once } from 'node:events'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import { ifdescribe, ifit } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +const Module = require('node:module') as NodeJS.ModuleInternal; + +const nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; + +describe('modules support', () => { + const fixtures = path.join(__dirname, 'fixtures'); + + describe('third-party module', () => { + ifdescribe(nativeModulesEnabled)('echo', () => { + afterEach(closeAllWindows); + it('can be required in renderer', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect( + w.webContents.executeJavaScript( + "{ require('@electron-ci/echo'); null }" + ) + ).to.be.fulfilled(); + }); + + it('can be required in node binary', async function () { + const child = childProcess.fork(path.join(fixtures, 'module', 'echo.js')); + const [msg] = await once(child, 'message'); + expect(msg).to.equal('ok'); + }); + + ifit(process.platform === 'win32')('can be required if electron.exe is renamed', () => { + const testExecPath = path.join(path.dirname(process.execPath), 'test.exe'); + fs.copyFileSync(process.execPath, testExecPath); + try { + const fixture = path.join(fixtures, 'module', 'echo-renamed.js'); + expect(fs.existsSync(fixture)).to.be.true(); + const child = childProcess.spawnSync(testExecPath, [fixture]); + expect(child.status).to.equal(0); + } finally { + fs.unlinkSync(testExecPath); + } + }); + }); + + const enablePlatforms: NodeJS.Platform[] = [ + 'linux', + 'darwin', + 'win32' + ]; + ifdescribe(nativeModulesEnabled && enablePlatforms.includes(process.platform))('module that use uv_dlopen', () => { + it('can be required in renderer', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'@electron-ci/uv-dlopen\'); null }')).to.be.fulfilled(); + }); + + it('can be required in node binary', async function () { + const child = childProcess.fork(path.join(fixtures, 'module', 'uv-dlopen.js')); + const [exitCode] = await once(child, 'exit'); + expect(exitCode).to.equal(0); + }); + }); + + describe('q', () => { + describe('Q.when', () => { + it('emits the fulfil callback', (done) => { + const Q = require('q'); + Q(true).then((val: boolean) => { + expect(val).to.be.true(); + done(); + }); + }); + }); + }); + + describe('require(\'electron/...\')', () => { + it('require(\'electron/lol\') should throw in the main process', () => { + expect(() => { + require('electron/lol'); + }).to.throw(/Cannot find module 'electron\/lol'/); + }); + + it('require(\'electron/lol\') should throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron/lol\'); null }')).to.eventually.be.rejected(); + }); + + it('require(\'electron\') should not throw in the main process', () => { + expect(() => { + require('electron'); + }).to.not.throw(); + }); + + it('require(\'electron\') should not throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron\'); null }')).to.be.fulfilled(); + }); + + it('require(\'electron/main\') should not throw in the main process', () => { + expect(() => { + require('electron/main'); + }).to.not.throw(); + }); + + it('require(\'electron/main\') should not throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron/main\'); null }')).to.be.fulfilled(); + }); + + it('require(\'electron/renderer\') should not throw in the main process', () => { + expect(() => { + require('electron/renderer'); + }).to.not.throw(); + }); + + it('require(\'electron/renderer\') should not throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron/renderer\'); null }')).to.be.fulfilled(); + }); + + it('require(\'electron/common\') should not throw in the main process', () => { + expect(() => { + require('electron/common'); + }).to.not.throw(); + }); + + it('require(\'electron/common\') should not throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron/common\'); null }')).to.be.fulfilled(); + }); + }); + + describe('coffeescript', () => { + it('can be registered and used to require .coffee files', () => { + expect(() => { + require('coffeescript').register(); + }).to.not.throw(); + expect(require('./fixtures/module/test.coffee')).to.be.true(); + }); + }); + }); + + describe('global variables', () => { + describe('process', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-process')).to.equal('declared process'); + }); + }); + + describe('global', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-global')).to.equal('declared global'); + }); + }); + + describe('Buffer', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-buffer')).to.equal('declared Buffer'); + }); + }); + }); + + describe('Module._nodeModulePaths', () => { + describe('when the path is inside the resources path', () => { + it('does not include paths outside of the resources path', () => { + let modulePath = process.resourcesPath; + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = process.resourcesPath + '-foo'; + const nodeModulePaths = Module._nodeModulePaths(modulePath); + expect(nodeModulePaths).to.include(path.join(modulePath, 'node_modules')); + expect(nodeModulePaths).to.include(path.join(modulePath, '..', 'node_modules')); + + modulePath = path.join(process.resourcesPath, 'foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'bar'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'bar', 'node_modules'), + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar', 'node_modules'), + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + }); + }); + + describe('when the path is outside the resources path', () => { + it('includes paths outside of the resources path', () => { + const modulePath = path.resolve('/foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(modulePath, 'node_modules'), + path.resolve('/node_modules') + ]); + }); + }); + }); + + describe('require', () => { + describe('when loaded URL is not file: protocol', () => { + afterEach(closeAllWindows); + it('searches for module under app directory', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + const result = await w.webContents.executeJavaScript('typeof require("q").when'); + expect(result).to.equal('function'); + }); + }); + }); + + describe('esm', () => { + it('can load the built-in "electron" module via ESM import', async () => { + await expect(import('electron')).to.eventually.be.ok(); + }); + + it('the built-in "electron" module loaded via ESM import has the same exports as the CJS module', async () => { + const esmElectron = await import('electron'); + const cjsElectron = require('electron'); + expect(Object.keys(esmElectron)).to.deep.equal(Object.keys(cjsElectron)); + }); + }); +}); diff --git a/spec/node-spec.ts b/spec/node-spec.ts new file mode 100644 index 0000000000000..0d22f3fbfd71d --- /dev/null +++ b/spec/node-spec.ts @@ -0,0 +1,1001 @@ +import { webContents } from 'electron/main'; + +import { expect } from 'chai'; + +import * as childProcess from 'node:child_process'; +import { once } from 'node:events'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { EventEmitter } from 'node:stream'; +import * as util from 'node:util'; + +import { copyMacOSFixtureApp, getCodesignIdentity, shouldRunCodesignTests, signApp, spawn } from './lib/codesign-helpers'; +import { withTempDirectory } from './lib/fs-helpers'; +import { getRemoteContext, ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers'; + +const mainFixturesPath = path.resolve(__dirname, 'fixtures'); + +describe('node feature', () => { + const fixtures = path.join(__dirname, 'fixtures'); + + describe('child_process', () => { + describe('child_process.fork', () => { + it('Works in browser process', async () => { + const child = childProcess.fork(path.join(fixtures, 'module', 'ping.js')); + const message = once(child, 'message'); + child.send('message'); + const [msg] = await message; + expect(msg).to.equal('message'); + }); + + it('Has its module searth paths restricted', async () => { + const child = childProcess.fork(path.join(fixtures, 'module', 'module-paths.js')); + const [msg] = await once(child, 'message'); + expect(msg.length).to.equal(2); + }); + }); + }); + + describe('child_process in renderer', () => { + useRemoteContext(); + + describe('child_process.fork', () => { + itremote('works in current process', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'ping.js')); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, [fixtures]); + + itremote('preserves args', async (fixtures: string) => { + const args = ['--expose_gc', '-test', '1']; + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'process_args.js'), args); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(args).to.deep.equal(msg.slice(2)); + }, [fixtures]); + + itremote('works in forked process', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'fork_ping.js')); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, [fixtures]); + + itremote('works in forked process when options.env is specified', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'fork_ping.js'), [], { + path: process.env.PATH + }); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, [fixtures]); + + itremote('has String::localeCompare working in script', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'locale-compare.js')); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.deep.equal([0, -1, 1]); + }, [fixtures]); + + itremote('has setImmediate working in script', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'set-immediate.js')); + const message = new Promise(resolve => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('ok'); + }, [fixtures]); + + itremote('pipes stdio', async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'process-stdout.js'), { silent: true }); + let data = ''; + child.stdout.on('data', (chunk: any) => { + data += String(chunk); + }); + const code = await new Promise(resolve => child.once('close', resolve)); + expect(code).to.equal(0); + expect(data).to.equal('pipes stdio'); + }, [fixtures]); + + itremote('works when sending a message to a process forked with the --eval argument', async () => { + const source = "process.on('message', (message) => { process.send(message) })"; + const forked = require('node:child_process').fork('--eval', [source]); + const message = new Promise(resolve => forked.once('message', resolve)); + forked.send('hello'); + const msg = await message; + expect(msg).to.equal('hello'); + }); + + it('has the electron version in process.versions', async () => { + const source = 'process.send(process.versions)'; + const forked = require('node:child_process').fork('--eval', [source]); + const [message] = await once(forked, 'message'); + expect(message) + .to.have.own.property('electron') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); + }); + }); + + describe('child_process.spawn', () => { + itremote('supports spawning Electron as a node process via the ELECTRON_RUN_AS_NODE env var', async (fixtures: string) => { + const child = require('node:child_process').spawn(process.execPath, [require('node:path').join(fixtures, 'module', 'run-as-node.js')], { + env: { + ELECTRON_RUN_AS_NODE: true + } + }); + + let output = ''; + child.stdout.on('data', (data: any) => { + output += data; + }); + try { + await new Promise(resolve => child.stdout.once('close', resolve)); + expect(JSON.parse(output)).to.deep.equal({ + stdoutType: 'pipe', + processType: 'undefined', + window: 'undefined' + }); + } finally { + child.kill(); + } + }, [fixtures]); + }); + + describe('child_process.exec', () => { + ifit(process.platform === 'linux')('allows executing a setuid binary from non-sandboxed renderer', async () => { + // Chrome uses prctl(2) to set the NO_NEW_PRIVILEGES flag on Linux (see + // https://github.com/torvalds/linux/blob/40fde647cc/Documentation/userspace-api/no_new_privs.rst). + // We disable this for unsandboxed processes, which the renderer tests + // are running in. If this test fails with an error like 'effective uid + // is not 0', then it's likely that our patch to prevent the flag from + // being set has become ineffective. + const w = await getRemoteContext(); + const stdout = await w.webContents.executeJavaScript('require(\'child_process\').execSync(\'sudo --help\')'); + expect(stdout).to.not.be.empty(); + }); + }); + }); + + describe('EventSource', () => { + itremote('works correctly when nodeIntegration is enabled in the renderer', () => { + const es = new EventSource('https://example.com'); + expect(es).to.have.property('url').that.is.a('string'); + expect(es).to.have.property('readyState').that.is.a('number'); + expect(es).to.have.property('withCredentials').that.is.a('boolean'); + }); + }); + + describe('fetch', () => { + itremote('works correctly when nodeIntegration is enabled in the renderer', async (fixtures: string) => { + const file = require('node:path').join(fixtures, 'hello.txt'); + expect(() => { + fetch('file://' + file); + }).to.not.throw(); + + expect(() => { + const formData = new FormData(); + formData.append('username', 'Groucho'); + }).not.to.throw(); + + expect(() => { + const request = new Request('https://example.com', { + method: 'POST', + body: JSON.stringify({ foo: 'bar' }) + }); + expect(request.method).to.equal('POST'); + }).not.to.throw(); + + expect(() => { + const response = new Response('Hello, world!'); + expect(response.status).to.equal(200); + }).not.to.throw(); + + expect(() => { + const headers = new Headers(); + headers.append('Content-Type', 'text/xml'); + }).not.to.throw(); + }, [fixtures]); + }); + + it('does not hang when using the fs module in the renderer process', async () => { + const appPath = path.join(mainFixturesPath, 'apps', 'libuv-hang', 'main.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath], { + cwd: path.join(mainFixturesPath, 'apps', 'libuv-hang'), + stdio: 'inherit' + }); + const [code] = await once(appProcess, 'close'); + expect(code).to.equal(0); + }); + + describe('contexts', () => { + describe('setTimeout called under Chromium event loop in browser process', () => { + it('Can be scheduled in time', (done) => { + setTimeout(done, 0); + }); + + it('Can be promisified', (done) => { + util.promisify(setTimeout)(0).then(done); + }); + }); + + describe('setInterval called under Chromium event loop in browser process', () => { + it('can be scheduled in time', (done) => { + let interval: any = null; + let clearing = false; + const clear = () => { + if (interval === null || clearing) return; + + // interval might trigger while clearing (remote is slow sometimes) + clearing = true; + clearInterval(interval); + clearing = false; + interval = null; + done(); + }; + interval = setInterval(clear, 10); + }); + }); + + const suspendListeners = (emitter: EventEmitter, eventName: string, callback: (...args: any[]) => void) => { + const listeners = emitter.listeners(eventName) as ((...args: any[]) => void)[]; + emitter.removeAllListeners(eventName); + emitter.once(eventName, (...args) => { + emitter.removeAllListeners(eventName); + for (const listener of listeners) { + emitter.on(eventName, listener); + } + + callback(...args); + }); + }; + describe('error thrown in main process node context', () => { + it('gets emitted as a process uncaughtException event', async () => { + fs.readFile(__filename, () => { + throw new Error('hello'); + }); + const result = await new Promise(resolve => suspendListeners(process, 'uncaughtException', (error) => { + resolve(error.message); + })); + expect(result).to.equal('hello'); + }); + }); + + describe('promise rejection in main process node context', () => { + it('gets emitted as a process unhandledRejection event', async () => { + fs.readFile(__filename, () => { + Promise.reject(new Error('hello')); + }); + const result = await new Promise(resolve => suspendListeners(process, 'unhandledRejection', (error) => { + resolve(error.message); + })); + expect(result).to.equal('hello'); + }); + + it('does not log the warning more than once when the rejection is unhandled', async () => { + const appPath = path.join(mainFixturesPath, 'api', 'unhandled-rejection.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + + let output = ''; + const out = (data: string) => { + output += data; + if (/UnhandledPromiseRejectionWarning/.test(data)) { + appProcess.kill(); + } + }; + appProcess.stdout!.on('data', out); + appProcess.stderr!.on('data', out); + + await once(appProcess, 'exit'); + expect(/UnhandledPromiseRejectionWarning/.test(output)).to.equal(true); + const matches = output.match(/Error: oops/gm); + expect(matches).to.have.lengthOf(1); + }); + + it('does not log the warning more than once when the rejection is handled', async () => { + const appPath = path.join(mainFixturesPath, 'api', 'unhandled-rejection-handled.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + + let output = ''; + const out = (data: string) => { output += data; }; + appProcess.stdout!.on('data', out); + appProcess.stderr!.on('data', out); + + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + expect(/UnhandledPromiseRejectionWarning/.test(output)).to.equal(false); + const matches = output.match(/Error: oops/gm); + expect(matches).to.have.lengthOf(1); + }); + }); + }); + + describe('contexts in renderer', () => { + useRemoteContext(); + + describe('setTimeout in fs callback', () => { + itremote('does not crash', async (filename: string) => { + await new Promise(resolve => require('node:fs').readFile(filename, () => { + setTimeout(resolve, 0); + })); + }, [__filename]); + }); + + describe('error thrown in renderer process node context', () => { + itremote('gets emitted as a process uncaughtException event', async (filename: string) => { + const error = new Error('boo!'); + require('node:fs').readFile(filename, () => { + throw error; + }); + await new Promise((resolve, reject) => { + process.once('uncaughtException', (thrown) => { + try { + expect(thrown).to.equal(error); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + }, [__filename]); + }); + + describe('URL handling in the renderer process', () => { + itremote('can successfully handle WHATWG URLs constructed by Blink', (fixtures: string) => { + const url = new URL('file://' + require('node:path').resolve(fixtures, 'pages', 'base-page.html')); + expect(() => { + require('node:fs').createReadStream(url); + }).to.not.throw(); + }, [fixtures]); + }); + + describe('setTimeout called under blink env in renderer process', () => { + itremote('can be scheduled in time', async () => { + await new Promise(resolve => setTimeout(resolve, 10)); + }); + + itremote('works from the timers module', async () => { + await new Promise(resolve => require('node:timers').setTimeout(resolve, 10)); + }); + }); + + describe('setInterval called under blink env in renderer process', () => { + itremote('can be scheduled in time', async () => { + await new Promise(resolve => { + const id = setInterval(() => { + clearInterval(id); + resolve(); + }, 10); + }); + }); + + itremote('can be scheduled in time from timers module', async () => { + const { setInterval, clearInterval } = require('node:timers'); + await new Promise(resolve => { + const id = setInterval(() => { + clearInterval(id); + resolve(); + }, 10); + }); + }); + }); + }); + + describe('message loop in renderer', () => { + useRemoteContext(); + + describe('process.nextTick', () => { + itremote('emits the callback', () => new Promise(resolve => process.nextTick(resolve))); + + itremote('works in nested calls', () => + new Promise(resolve => { + process.nextTick(() => { + process.nextTick(() => process.nextTick(resolve)); + }); + })); + }); + + describe('setImmediate', () => { + itremote('emits the callback', () => new Promise(resolve => setImmediate(resolve))); + + itremote('works in nested calls', () => new Promise(resolve => { + setImmediate(() => { + setImmediate(() => setImmediate(resolve)); + }); + })); + }); + }); + + ifdescribe(process.platform === 'darwin')('net.connect', () => { + itremote('emit error when connect to a socket path without listeners', async (fixtures: string) => { + const socketPath = require('node:path').join(require('node:os').tmpdir(), 'electron-test.sock'); + const script = require('node:path').join(fixtures, 'module', 'create_socket.js'); + const child = require('node:child_process').fork(script, [socketPath]); + const code = await new Promise(resolve => child.once('exit', resolve)); + expect(code).to.equal(0); + const client = require('node:net').connect(socketPath); + const error = await new Promise(resolve => client.once('error', resolve)); + expect(error.code).to.equal('ECONNREFUSED'); + }, [fixtures]); + }); + + describe('Buffer', () => { + useRemoteContext(); + + itremote('can be created from Blink external string', () => { + const p = document.createElement('p'); + p.innerText = '闲云潭影日悠悠,物换星移几度秋'; + const b = Buffer.from(p.innerText); + expect(b.toString()).to.equal('闲云潭影日悠悠,物换星移几度秋'); + expect(Buffer.byteLength(p.innerText)).to.equal(45); + }); + + itremote('correctly parses external one-byte UTF8 string', () => { + const p = document.createElement('p'); + p.innerText = 'Jøhänñéß'; + const b = Buffer.from(p.innerText); + expect(b.toString()).to.equal('Jøhänñéß'); + expect(Buffer.byteLength(p.innerText)).to.equal(13); + }); + + itremote('does not crash when creating large Buffers', () => { + let buffer = Buffer.from(new Array(4096).join(' ')); + expect(buffer.length).to.equal(4095); + buffer = Buffer.from(new Array(4097).join(' ')); + expect(buffer.length).to.equal(4096); + }); + + itremote('does not crash for crypto operations', () => { + const crypto = require('node:crypto'); + const data = 'lG9E+/g4JmRmedDAnihtBD4Dfaha/GFOjd+xUOQI05UtfVX3DjUXvrS98p7kZQwY3LNhdiFo7MY5rGft8yBuDhKuNNag9vRx/44IuClDhdQ='; + const key = 'q90K9yBqhWZnAMCMTOJfPQ=='; + const cipherText = '{"error_code":114,"error_message":"Tham số không hợp lệ","data":null}'; + for (let i = 0; i < 10000; ++i) { + const iv = Buffer.from('0'.repeat(32), 'hex'); + const input = Buffer.from(data, 'base64'); + const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(key, 'base64'), iv); + const result = Buffer.concat([decipher.update(input), decipher.final()]).toString('utf8'); + expect(cipherText).to.equal(result); + } + }); + + itremote('does not crash when using crypto.diffieHellman() constructors', () => { + const crypto = require('node:crypto'); + + crypto.createDiffieHellman('abc'); + crypto.createDiffieHellman('abc', 2); + + // Needed to test specific DiffieHellman ctors. + + crypto.createDiffieHellman('abc', Buffer.from([2])); + crypto.createDiffieHellman('abc', '123'); + }); + + itremote('does not crash when calling crypto.createPrivateKey() with an unsupported algorithm', () => { + const crypto = require('node:crypto'); + + const ed448 = { + crv: 'Ed448', + x: 'KYWcaDwgH77xdAwcbzOgvCVcGMy9I6prRQBhQTTdKXUcr-VquTz7Fd5adJO0wT2VHysF3bk3kBoA', + d: 'UhC3-vN5vp_g9PnTknXZgfXUez7Xvw-OfuJ0pYkuwzpYkcTvacqoFkV_O05WMHpyXkzH9q2wzx5n', + kty: 'OKP' + }; + + expect(() => { + crypto.createPrivateKey({ key: ed448, format: 'jwk' }); + }).to.throw(/Invalid JWK data/); + }); + }); + + describe('process.stdout', () => { + useRemoteContext(); + + itremote('does not throw an exception when accessed', () => { + expect(() => process.stdout).to.not.throw(); + }); + + itremote('does not throw an exception when calling write()', () => { + expect(() => { + process.stdout.write('test'); + }).to.not.throw(); + }); + + // TODO: figure out why process.stdout.isTTY is true on Darwin but not Linux/Win. + ifdescribe(process.platform !== 'darwin')('isTTY', () => { + itremote('should be undefined in the renderer process', function () { + expect(process.stdout.isTTY).to.be.undefined(); + }); + }); + }); + + describe('process.stdin', () => { + useRemoteContext(); + + itremote('does not throw an exception when accessed', () => { + expect(() => process.stdin).to.not.throw(); + }); + + itremote('returns null when read from', () => { + expect(process.stdin.read()).to.be.null(); + }); + }); + + describe('process.version', () => { + itremote('should not have -pre', () => { + expect(process.version.endsWith('-pre')).to.be.false(); + }); + }); + + describe('vm.runInNewContext', () => { + itremote('should not crash', () => { + require('node:vm').runInNewContext(''); + }); + }); + + describe('crypto', () => { + useRemoteContext(); + itremote('should list the ripemd160 hash in getHashes', () => { + expect(require('node:crypto').getHashes()).to.include('ripemd160'); + }); + + itremote('should be able to create a ripemd160 hash and use it', () => { + const hash = require('node:crypto').createHash('ripemd160'); + hash.update('electron-ripemd160'); + expect(hash.digest('hex')).to.equal('fa7fec13c624009ab126ebb99eda6525583395fe'); + }); + + itremote('should list aes-{128,256}-cfb in getCiphers', () => { + expect(require('node:crypto').getCiphers()).to.include.members(['aes-128-cfb', 'aes-256-cfb']); + }); + + itremote('should be able to create an aes-128-cfb cipher', () => { + require('node:crypto').createCipheriv('aes-128-cfb', '0123456789abcdef', '0123456789abcdef'); + }); + + itremote('should be able to create an aes-256-cfb cipher', () => { + require('node:crypto').createCipheriv('aes-256-cfb', '0123456789abcdef0123456789abcdef', '0123456789abcdef'); + }); + + itremote('should be able to create a bf-{cbc,cfb,ecb} ciphers', () => { + require('node:crypto').createCipheriv('bf-cbc', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + require('node:crypto').createCipheriv('bf-cfb', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + require('node:crypto').createCipheriv('bf-ecb', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + }); + + itremote('should list des-ede-cbc in getCiphers', () => { + expect(require('node:crypto').getCiphers()).to.include('des-ede-cbc'); + }); + + itremote('should be able to create an des-ede-cbc cipher', () => { + const key = Buffer.from('0123456789abcdeff1e0d3c2b5a49786', 'hex'); + const iv = Buffer.from('fedcba9876543210', 'hex'); + require('node:crypto').createCipheriv('des-ede-cbc', key, iv); + }); + + itremote('should not crash when getting an ECDH key', () => { + const ecdh = require('node:crypto').createECDH('prime256v1'); + expect(ecdh.generateKeys()).to.be.an.instanceof(Buffer); + expect(ecdh.getPrivateKey()).to.be.an.instanceof(Buffer); + }); + + itremote('should not crash when generating DH keys or fetching DH fields', () => { + const dh = require('node:crypto').createDiffieHellman('modp15'); + expect(dh.generateKeys()).to.be.an.instanceof(Buffer); + expect(dh.getPublicKey()).to.be.an.instanceof(Buffer); + expect(dh.getPrivateKey()).to.be.an.instanceof(Buffer); + expect(dh.getPrime()).to.be.an.instanceof(Buffer); + expect(dh.getGenerator()).to.be.an.instanceof(Buffer); + }); + + itremote('should not crash when creating an ECDH cipher', () => { + const crypto = require('node:crypto'); + const dh = crypto.createECDH('prime256v1'); + dh.generateKeys(); + dh.setPrivateKey(dh.getPrivateKey()); + }); + }); + + itremote('includes the electron version in process.versions', () => { + expect(process.versions) + .to.have.own.property('electron') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); + }); + + itremote('includes the chrome version in process.versions', () => { + expect(process.versions) + .to.have.own.property('chrome') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+\.\d+$/); + }); + + describe('NODE_OPTIONS', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise; + + it('Fails for options disallowed by Node.js itself', (done) => { + after(async () => { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + + // Exit code 9 indicates cli flag parsing failure + expect(code).to.equal(9); + child.kill(); + }); + + const env = { ...process.env, NODE_OPTIONS: '--v8-options' }; + child = childProcess.spawn(process.execPath, { env }); + exitPromise = once(child, 'exit'); + + let output = ''; + let success = false; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/electron: --v8-options is not allowed in NODE_OPTIONS/m.test(output)) { + success = true; + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + child.on('exit', () => { + if (!success) { + cleanup(); + done(new Error(`Unexpected output: ${output.toString()}`)); + } + }); + }); + + it('Disallows crypto-related options', (done) => { + after(() => { + child.kill(); + }); + + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { ...process.env, NODE_OPTIONS: '--use-openssl-ca' }; + child = childProcess.spawn(process.execPath, ['--enable-logging', appPath], { env }); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/The NODE_OPTION --use-openssl-ca is not supported in Electron/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + + it('does allow --require in non-packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { + ...process.env, + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }; + // App should exit with code 1. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + }); + + it('does not allow --require in packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { + ...process.env, + ELECTRON_FORCE_IS_PACKAGED: 'true', + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }; + // App should exit with code 0. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + }); + + ifdescribe(shouldRunCodesignTests)('NODE_OPTIONS in signed app', function () { + let identity = ''; + + beforeEach(function () { + const result = getCodesignIdentity(); + if (result === null) { + this.skip(); + } else { + identity = result; + } + }); + + const script = path.join(fixtures, 'api', 'fork-with-node-options.js'); + const nodeOptionsWarning = 'Node.js environment variables are disabled because this process is invoked by other apps'; + + it('is disabled when invoked by other apps in ELECTRON_RUN_AS_NODE mode', async () => { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir); + await signApp(appPath, identity); + // Invoke Electron by using the system node binary as middle layer, so + // the check of NODE_OPTIONS will think the process is started by other + // apps. + const { code, out } = await spawn('node', [script, path.join(appPath, 'Contents/MacOS/Electron')]); + expect(code).to.equal(0); + expect(out).to.include(nodeOptionsWarning); + }); + }); + + it('is disabled when invoked by alien binary in app bundle in ELECTRON_RUN_AS_NODE mode', async function () { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir); + await signApp(appPath, identity); + // Find system node and copy it to app bundle. + const nodePath = process.env.PATH?.split(path.delimiter).find(dir => fs.existsSync(path.join(dir, 'node'))); + if (!nodePath) { + this.skip(); + return; + } + const alienBinary = path.join(appPath, 'Contents/MacOS/node'); + await fs.promises.cp(path.join(nodePath, 'node'), alienBinary, { recursive: true }); + // Try to execute electron app from the alien node in app bundle. + const { code, out } = await spawn(alienBinary, [script, path.join(appPath, 'Contents/MacOS/Electron')]); + expect(code).to.equal(0); + expect(out).to.include(nodeOptionsWarning); + }); + }); + + it('is respected when invoked from self', async () => { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir, null); + await signApp(appPath, identity); + const appExePath = path.join(appPath, 'Contents/MacOS/Electron'); + const { code, out } = await spawn(appExePath, [script, appExePath]); + expect(code).to.equal(1); + expect(out).to.not.include(nodeOptionsWarning); + expect(out).to.include('NODE_OPTIONS passed to child'); + }); + }); + }); + + describe('Node.js cli flags', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise; + + it('Prohibits crypto-related flags in ELECTRON_RUN_AS_NODE mode', (done) => { + after(async () => { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + expect(code).to.equal(9); + child.kill(); + }); + + child = childProcess.spawn(process.execPath, ['--force-fips'], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + exitPromise = once(child, 'exit'); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/.*The Node.js cli flag --force-fips is not supported in Electron/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + }); + + describe('process.stdout', () => { + it('is a real Node stream', () => { + expect((process.stdout as any)._type).to.not.be.undefined(); + }); + }); + + describe('fs.readFile', () => { + it('can accept a FileHandle as the Path argument', async () => { + const filePathForHandle = path.resolve(mainFixturesPath, 'dogs-running.txt'); + const fileHandle = await fs.promises.open(filePathForHandle, 'r'); + + const file = await fs.promises.readFile(fileHandle, { encoding: 'utf8' }); + expect(file).to.not.be.empty(); + await fileHandle.close(); + }); + }); + + describe('inspector', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise | null; + + afterEach(async () => { + if (child && exitPromise) { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + expect(code).to.equal(0); + } else if (child) { + child.kill(); + } + child = null as any; + exitPromise = null as any; + }); + + it('Supports starting the v8 inspector with --inspect/--inspect-brk', (done) => { + child = childProcess.spawn(process.execPath, ['--inspect-brk', path.join(fixtures, 'module', 'run-as-node.js')], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/Debugger listening on ws:/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + + it('Supports starting the v8 inspector with --inspect and a provided port', async () => { + child = childProcess.spawn(process.execPath, ['--inspect=17364', path.join(fixtures, 'module', 'run-as-node.js')], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + exitPromise = once(child, 'exit'); + + let output = ''; + const listener = (data: Buffer) => { output += data; }; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + await once(child, 'exit'); + cleanup(); + if (/^Debugger listening on ws:/m.test(output)) { + expect(output.trim()).to.contain(':17364', 'should be listening on port 17364'); + } else { + throw new Error(`Unexpected output: ${output.toString()}`); + } + }); + + it('Does not start the v8 inspector when --inspect is after a -- argument', async () => { + child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'noop.js'), '--', '--inspect']); + exitPromise = once(child, 'exit'); + + let output = ''; + const listener = (data: Buffer) => { output += data; }; + child.stderr.on('data', listener); + child.stdout.on('data', listener); + await once(child, 'exit'); + if (output.trim().startsWith('Debugger listening on ws://')) { + throw new Error('Inspector was started when it should not have been'); + } + }); + + // IPC Electron child process not supported on Windows. + ifit(process.platform !== 'win32')('does not crash when quitting with the inspector connected', function (done) { + child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], { + stdio: ['ipc'] + }) as childProcess.ChildProcessWithoutNullStreams; + exitPromise = once(child, 'exit'); + + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + let output = ''; + const success = false; + function listener (data: Buffer) { + output += data; + console.log(data.toString()); // NOTE: temporary debug logging to try to catch flake. + const match = /^Debugger listening on (ws:\/\/.+:\d+\/.+)\n/m.exec(output.trim()); + if (match) { + cleanup(); + // NOTE: temporary debug logging to try to catch flake. + child.stderr.on('data', (m) => console.log(m.toString())); + child.stdout.on('data', (m) => console.log(m.toString())); + const w = (webContents as typeof ElectronInternal.WebContents).create(); + w.loadURL('about:blank') + .then(() => w.executeJavaScript(`new Promise(resolve => { + const connection = new WebSocket(${JSON.stringify(match[1])}) + connection.onopen = () => { + connection.onclose = () => resolve() + connection.close() + } + })`)) + .then(() => { + w.destroy(); + child.send('plz-quit'); + done(); + }); + } + } + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + child.on('exit', () => { + if (!success) cleanup(); + }); + }); + + it('Supports js binding', async () => { + child = childProcess.spawn(process.execPath, ['--inspect', path.join(fixtures, 'module', 'inspector-binding.js')], { + env: { ELECTRON_RUN_AS_NODE: 'true' }, + stdio: ['ipc'] + }) as childProcess.ChildProcessWithoutNullStreams; + exitPromise = once(child, 'exit'); + + const [{ cmd, debuggerEnabled, success }] = await once(child, 'message'); + expect(cmd).to.equal('assert'); + expect(debuggerEnabled).to.be.true(); + expect(success).to.be.true(); + }); + }); + + it('Can find a module using a package.json main field', () => { + const result = childProcess.spawnSync(process.execPath, [path.resolve(fixtures, 'api', 'electron-main-module', 'app.asar')], { stdio: 'inherit' }); + expect(result.status).to.equal(0); + }); + + it('handles Promise timeouts correctly', async () => { + const scriptPath = path.join(fixtures, 'module', 'node-promise-timer.js'); + const child = childProcess.spawn(process.execPath, [scriptPath], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + const [code, signal] = await once(child, 'exit'); + expect(code).to.equal(0); + expect(signal).to.equal(null); + child.kill(); + }); + + it('performs microtask checkpoint correctly', (done) => { + let timer : NodeJS.Timeout; + const listener = () => { + done(new Error('catch block is delayed to next tick')); + }; + + const f3 = async () => { + return new Promise((resolve, reject) => { + timer = setTimeout(listener); + reject(new Error('oops')); + }); + }; + + setTimeout(() => { + f3().catch(() => { + clearTimeout(timer); + done(); + }); + }); + }); +}); diff --git a/spec/package.json b/spec/package.json index d14f50aac78e2..3ea7820d5681b 100644 --- a/spec/package.json +++ b/spec/package.json @@ -1,34 +1,61 @@ { - "name": "electron-test", - "productName": "Electron Test", - "main": "static/main.js", + "name": "electron-test-main", + "productName": "Electron Test Main", + "main": "index.js", "version": "0.1.0", + "scripts": { + "node-gyp-install": "node-gyp install" + }, "devDependencies": { + "@types/basic-auth": "^1.1.8", + "@types/busboy": "^1.5.4", + "@types/chai": "^4.3.19", + "@types/chai-as-promised": "^7.1.3", + "@types/dirty-chai": "^2.0.5", + "@types/express": "^4.17.13", + "@types/mocha": "^7.0.2", + "@types/send": "^0.14.5", + "@types/split": "^1.0.5", + "@types/uuid": "^3.4.6", + "@types/w3c-web-serial": "^1.0.7", + "express": "^4.20.0", + "@electron-ci/echo": "file:./fixtures/native-addon/echo", + "@electron-ci/is-valid-window": "file:./is-valid-window", + "@electron-ci/uv-dlopen": "file:./fixtures/native-addon/uv-dlopen/", + "@electron-ci/osr-gpu": "file:./fixtures/native-addon/osr-gpu/", + "@electron-ci/external-ab": "file:./fixtures/native-addon/external-ab/", + "@electron/fuses": "^1.8.0", + "@electron/packager": "^18.3.2", + "@marshallofsound/mocha-appveyor-reporter": "^0.4.3", + "@types/sinon": "^9.0.4", + "@types/ws": "^7.2.0", "basic-auth": "^2.0.1", + "busboy": "^1.6.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "coffeescript": "^2.4.1", "dbus-native": "github:nornagon/dbus-native#master", "dirty-chai": "^2.0.1", "graceful-fs": "^4.1.15", - "is-valid-window": "0.0.5", "mkdirp": "^0.5.1", - "mocha": "^5.2.0", + "mocha": "^10.0.0", "mocha-junit-reporter": "^1.18.0", "mocha-multi-reporters": "^1.1.7", - "send": "^0.16.2", + "pdfjs-dist": "^4.2.67", + "ps-list": "^7.0.0", + "q": "^1.5.1", + "send": "^0.19.0", + "sinon": "^9.0.1", "split": "^1.0.1", - "temp": "^0.9.0", "uuid": "^3.3.3", - "walkdir": "^0.3.2", - "winreg": "^1.2.4", - "ws": "^7.4.6", + "winreg": "1.2.4", + "ws": "^7.5.10", "yargs": "^16.0.3" }, - "dependencies": { - "mocha-appveyor-reporter": "^0.4.2" - }, "resolutions": { - "nan": "github:jkleinsc/nan#remove_accessor_signature" + "nan": "file:../../third_party/nan", + "dbus-native/optimist/minimist": "1.2.7", + "dbus-native/xml2js": "0.5.0", + "abstract-socket": "github:deepak1556/node-abstractsocket#928cc591decd12aff7dad96449da8afc29832c19" } } diff --git a/spec/parse-features-string-spec.ts b/spec/parse-features-string-spec.ts new file mode 100644 index 0000000000000..1392ae1582b8e --- /dev/null +++ b/spec/parse-features-string-spec.ts @@ -0,0 +1,22 @@ +import { expect } from 'chai'; + +import { parseCommaSeparatedKeyValue } from '../lib/browser/parse-features-string'; + +describe('feature-string parsing', () => { + it('is indifferent to whitespace around keys and values', () => { + const checkParse = (string: string, parsed: Record) => { + const features = parseCommaSeparatedKeyValue(string); + expect(features).to.deep.equal(parsed); + }; + checkParse('a=yes,c=d', { a: true, c: 'd' }); + checkParse('a=yes ,c=d', { a: true, c: 'd' }); + checkParse('a=yes, c=d', { a: true, c: 'd' }); + checkParse('a=yes , c=d', { a: true, c: 'd' }); + checkParse(' a=yes , c=d', { a: true, c: 'd' }); + checkParse(' a= yes , c=d', { a: true, c: 'd' }); + checkParse(' a = yes , c=d', { a: true, c: 'd' }); + checkParse(' a = yes , c =d', { a: true, c: 'd' }); + checkParse(' a = yes , c = d', { a: true, c: 'd' }); + checkParse(' a = yes , c = d ', { a: true, c: 'd' }); + }); +}); diff --git a/spec-main/pipe-transport.ts b/spec/pipe-transport.ts similarity index 100% rename from spec-main/pipe-transport.ts rename to spec/pipe-transport.ts diff --git a/spec/process-binding-spec.ts b/spec/process-binding-spec.ts new file mode 100644 index 0000000000000..db734208e5f1b --- /dev/null +++ b/spec/process-binding-spec.ts @@ -0,0 +1,46 @@ +import { BrowserWindow } from 'electron/main'; + +import { expect } from 'chai'; + +import { closeAllWindows } from './lib/window-helpers'; + +describe('process._linkedBinding', () => { + describe('in the main process', () => { + it('can access electron_browser bindings', () => { + process._linkedBinding('electron_browser_app'); + }); + + it('can access electron_common bindings', () => { + process._linkedBinding('electron_common_v8_util'); + }); + + it('cannot access electron_renderer bindings', () => { + expect(() => { + process._linkedBinding('electron_renderer_ipc'); + }).to.throw(/No such binding was linked: electron_renderer_ipc/); + }); + }); + + describe('in the renderer process', () => { + afterEach(closeAllWindows); + + it('cannot access electron_browser bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('void process._linkedBinding(\'electron_browser_app\')')) + .to.eventually.be.rejectedWith(/Script failed to execute/); + }); + + it('can access electron_common bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript('void process._linkedBinding(\'electron_common_v8_util\')'); + }); + + it('can access electron_renderer bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript('void process._linkedBinding(\'electron_renderer_ipc\')'); + }); + }); +}); diff --git a/spec-main/release-notes-spec.ts b/spec/release-notes-spec.ts similarity index 79% rename from spec-main/release-notes-spec.ts rename to spec/release-notes-spec.ts index aa47575f4b007..be34d0608c328 100644 --- a/spec-main/release-notes-spec.ts +++ b/spec/release-notes-spec.ts @@ -1,9 +1,11 @@ -import { GitProcess, IGitExecutionOptions, IGitResult } from 'dugite'; import { expect } from 'chai'; -import * as notes from '../script/release/notes/notes.js'; -import * as path from 'path'; +import { GitProcess, IGitExecutionOptions, IGitResult } from 'dugite'; import * as sinon from 'sinon'; +import * as path from 'node:path'; + +import * as notes from '../script/release/notes/notes'; + /* Fake a Dugite GitProcess that only returns the specific commits that we want to test */ @@ -211,4 +213,51 @@ describe('release notes', () => { expect(results.breaking[0].hash).to.equal(testCommit.sha1); }); }); + // test that when you have multiple stack updates only the + // latest will be kept + describe('superseding stack updates', () => { + const oldBranch = '27-x-y'; + const newBranch = '28-x-y'; + + const version = 'v28.0.0'; + + it('with different major versions', async function () { + const mostRecentCommit = new Commit('9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', 'chore: bump chromium to 119.0.6043.0'); + + const sharedChromiumHistory = [ + new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base + ]; + const chromiumPatchUpdates = [ + new Commit('d9ba26273ad3e7a34c905eccbd5dabda4eb7b402', 'chore: bump chromium to 118.0.5991.0'), + mostRecentCommit, + new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0') + ]; + + gitFake.setBranch(oldBranch, sharedChromiumHistory); + gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]); + + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.other).to.have.lengthOf(1); + expect(results.other[0].hash).to.equal(mostRecentCommit.sha1); + }); + it('with different build versions', async function () { + const mostRecentCommit = new Commit('8f7a48879ef8633a76279803637cdee7f7c6cd4f', 'chore: bump chromium to 119.0.6045.0'); + + const sharedChromiumHistory = [ + new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base + ]; + const chromiumPatchUpdates = [ + mostRecentCommit, + new Commit('9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', 'chore: bump chromium to 119.0.6043.0'), + new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0') + ]; + + gitFake.setBranch(oldBranch, sharedChromiumHistory); + gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]); + + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.other).to.have.lengthOf(1); + expect(results.other[0].hash).to.equal(mostRecentCommit.sha1); + }); + }); }); diff --git a/spec/security-warnings-spec.ts b/spec/security-warnings-spec.ts new file mode 100644 index 0000000000000..3ca40ef325f3b --- /dev/null +++ b/spec/security-warnings-spec.ts @@ -0,0 +1,218 @@ +import { BrowserWindow, WebPreferences } from 'electron/main'; + +import { expect } from 'chai'; + +import * as fs from 'node:fs/promises'; +import * as http from 'node:http'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; + +import { emittedUntil } from './lib/events-helpers'; +import { listen } from './lib/spec-helpers'; +import { closeWindow } from './lib/window-helpers'; + +const messageContainsSecurityWarning = (event: Event, level: number, message: string) => { + return message.includes('Electron Security Warning'); +}; + +const isLoaded = (event: Event, level: number, message: string) => { + return (message === 'loaded'); +}; + +describe('security warnings', () => { + let server: http.Server; + let w: BrowserWindow; + let useCsp = true; + let serverUrl: string; + + before(async () => { + // Create HTTP Server + server = http.createServer(async (request, response) => { + const uri = new URL(request.url!, `http://${request.headers.host}`).pathname!; + let filename = path.join(__dirname, 'fixtures', 'pages', uri); + + try { + const stats = await fs.stat(filename); + if (stats.isDirectory()) { + filename += '/index.html'; + } + + const file = await fs.readFile(filename, 'binary'); + const cspHeaders = [ + ...(useCsp ? ['script-src \'self\' \'unsafe-inline\''] : []) + ]; + response.writeHead(200, { 'Content-Security-Policy': cspHeaders }); + response.write(file, 'binary'); + } catch { + response.writeHead(404, { 'Content-Type': 'text/plain' }); + } + + response.end(); + }); + + serverUrl = `http://localhost2:${(await listen(server)).port}`; + }); + + after(() => { + // Close server + server.close(); + server = null as unknown as any; + }); + + afterEach(async () => { + useCsp = true; + await closeWindow(w); + w = null as unknown as any; + }); + + it('should warn about Node.js integration with remote content', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Node.js Integration with Remote Content'); + }); + + it('should not warn about Node.js integration with remote content from localhost', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true + } + }); + + w.loadURL(`${serverUrl}/base-page-security-onload-message.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', isLoaded); + expect(message).to.not.include('Node.js Integration with Remote Content'); + }); + + const generateSpecs = (description: string, webPreferences: WebPreferences) => { + describe(description, () => { + it('should warn about disabled webSecurity', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + webSecurity: false, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Disabled webSecurity'); + }); + + it('should warn about insecure Content-Security-Policy', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + useCsp = false; + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Insecure Content-Security-Policy'); + }); + + it('should not warn about secure Content-Security-Policy', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + useCsp = true; + w.loadURL(`${serverUrl}/base-page-security.html`); + let didNotWarn = true; + w.webContents.on('console-message', () => { + didNotWarn = false; + }); + await setTimeout(500); + expect(didNotWarn).to.equal(true); + }); + + it('should warn about allowRunningInsecureContent', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + allowRunningInsecureContent: true, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('allowRunningInsecureContent'); + }); + + it('should warn about experimentalFeatures', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + experimentalFeatures: true, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('experimentalFeatures'); + }); + + it('should warn about enableBlinkFeatures', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + enableBlinkFeatures: 'my-cool-feature', + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('enableBlinkFeatures'); + }); + + it('should warn about allowpopups', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/webview-allowpopups.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('allowpopups'); + }); + + it('should warn about insecure resources', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/insecure-resources.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Insecure Resources'); + }); + + it('should not warn about loading insecure-resources.html from localhost', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/insecure-resources.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.not.include('insecure-resources.html'); + }); + }); + }; + + generateSpecs('without sandbox', { contextIsolation: false }); + generateSpecs('with sandbox', { sandbox: true, contextIsolation: false }); +}); diff --git a/spec/spec-helpers.js b/spec/spec-helpers.js deleted file mode 100644 index 893049a095a52..0000000000000 --- a/spec/spec-helpers.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.ifit = (condition) => (condition ? it : it.skip); -exports.ifdescribe = (condition) => (condition ? describe : describe.skip); - -exports.delay = (time = 0) => new Promise(resolve => setTimeout(resolve, time)); diff --git a/spec-main/spellchecker-spec.ts b/spec/spellchecker-spec.ts similarity index 78% rename from spec-main/spellchecker-spec.ts rename to spec/spellchecker-spec.ts index 3cc058158729b..25341e4bddc9b 100644 --- a/spec-main/spellchecker-spec.ts +++ b/spec/spellchecker-spec.ts @@ -1,13 +1,15 @@ import { BrowserWindow, Session, session } from 'electron/main'; import { expect } from 'chai'; -import * as path from 'path'; -import * as fs from 'fs'; -import * as http from 'http'; -import { AddressInfo } from 'net'; -import { closeWindow } from './window-helpers'; -import { emittedOnce } from './events-helpers'; -import { ifit, ifdescribe, delay } from './spec-helpers'; + +import { once } from 'node:events'; +import * as fs from 'node:fs/promises'; +import * as http from 'node:http'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; + +import { ifit, ifdescribe, listen } from './lib/spec-helpers'; +import { closeWindow } from './lib/window-helpers'; const features = process._linkedBinding('electron_common_features'); const v8Util = process._linkedBinding('electron_common_v8_util'); @@ -18,7 +20,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () let w: BrowserWindow; async function rightClick () { - const contextMenuPromise = emittedOnce(w.webContents, 'context-menu'); + const contextMenuPromise = once(w.webContents, 'context-menu'); w.webContents.sendInputEvent({ type: 'mouseDown', button: 'right', @@ -36,33 +38,33 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () const timeout = (process.env.IS_ASAN ? 180 : 10) * 1000; let contextMenuParams = await rightClick(); while (!fn(contextMenuParams) && (Date.now() - now < timeout)) { - await delay(100); + await setTimeout(100); contextMenuParams = await rightClick(); } return contextMenuParams; } // Setup a server to download hunspell dictionary. - const server = http.createServer((req, res) => { + const server = http.createServer(async (req, res) => { // The provided is minimal dict for testing only, full list of words can // be found at src/third_party/hunspell_dictionaries/xx_XX.dic. - fs.readFile(path.join(__dirname, '/../../third_party/hunspell_dictionaries/xx-XX-3-0.bdic'), function (err, data) { - if (err) { - console.error('Failed to read dictionary file'); - res.writeHead(404); - res.end(JSON.stringify(err)); - return; - } + try { + const data = await fs.readFile(path.join(__dirname, '/../../third_party/hunspell_dictionaries/xx-XX-3-0.bdic')); res.writeHead(200); res.end(data); - }); + } catch (err) { + console.error('Failed to read dictionary file'); + res.writeHead(404); + res.end(JSON.stringify(err)); + } }); - before((done) => { - server.listen(0, '127.0.0.1', () => done()); + let serverUrl: string; + before(async () => { + serverUrl = (await listen(server)).url; }); after(() => server.close()); - const fixtures = path.resolve(__dirname, '../spec/fixtures'); + const fixtures = path.resolve(__dirname, 'fixtures'); const preload = path.join(fixtures, 'module', 'preload-electron.js'); const generateSpecs = (description: string, sandbox: boolean) => { @@ -77,7 +79,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () sandbox } }); - w.webContents.session.setSpellCheckerDictionaryDownloadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`); + w.webContents.session.setSpellCheckerDictionaryDownloadURL(serverUrl); w.webContents.session.setSpellCheckerLanguages(['en-US']); await w.loadFile(path.resolve(__dirname, './fixtures/chromium/spellchecker.html')); }); @@ -107,7 +109,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () ifit(shouldRun)('should detect incorrectly spelled words as incorrect after disabling all languages and re-enabling', async () => { w.webContents.session.setSpellCheckerLanguages([]); - await delay(500); + await setTimeout(500); w.webContents.session.setSpellCheckerLanguages(['en-US']); await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); @@ -147,13 +149,13 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () // spellCheckerEnabled is sent to renderer asynchronously and there is // no event notifying when it is finished, so wait a little while to // ensure the setting has been changed in renderer. - await delay(500); + await setTimeout(500); expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(false); w.webContents.session.spellCheckerEnabled = true; v8Util.runUntilIdle(); expect(w.webContents.session.spellCheckerEnabled).to.be.true(); - await delay(500); + await setTimeout(500); expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true); }); }); @@ -212,6 +214,44 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () }); }); + describe('ses.setSpellCheckerLanguages', () => { + const isMac = process.platform === 'darwin'; + + ifit(isMac)('should be a no-op when setSpellCheckerLanguages is called on macOS', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['i-am-a-nonexistent-language']); + }).to.not.throw(); + }); + + ifit(!isMac)('should throw when a bad language is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['i-am-a-nonexistent-language']); + }).to.throw(/Invalid language code provided: "i-am-a-nonexistent-language" is not a valid language code/); + }); + + ifit(!isMac)('should not throw when a recognized language is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['es']); + }).to.not.throw(); + }); + }); + + describe('SetSpellCheckerDictionaryDownloadURL', () => { + const isMac = process.platform === 'darwin'; + + ifit(isMac)('should be a no-op when a bad url is passed on macOS', () => { + expect(() => { + w.webContents.session.setSpellCheckerDictionaryDownloadURL('i-am-not-a-valid-url'); + }).to.not.throw(); + }); + + ifit(!isMac)('should throw when a bad url is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerDictionaryDownloadURL('i-am-not-a-valid-url'); + }).to.throw(/The URL you provided to setSpellCheckerDictionaryDownloadURL is not a valid URL/); + }); + }); + describe('ses.removeWordFromSpellCheckerDictionary', () => { it('should successfully remove words to custom dictionary', async () => { const result1 = ses.addWordToSpellCheckerDictionary('foobar'); diff --git a/spec/static/get-files.js b/spec/static/get-files.js deleted file mode 100644 index 9857d9742e89d..0000000000000 --- a/spec/static/get-files.js +++ /dev/null @@ -1,15 +0,0 @@ -async function getFiles (directoryPath, { filter = null } = {}) { - const files = []; - const walker = require('walkdir').walk(directoryPath, { - no_recurse: true - }); - walker.on('file', (file) => { - if (!filter || filter(file)) { - files.push(file); - } - }); - await new Promise((resolve) => walker.on('end', resolve)); - return files; -} - -module.exports = getFiles; diff --git a/spec/static/index.html b/spec/static/index.html deleted file mode 100644 index f69432535ac6a..0000000000000 --- a/spec/static/index.html +++ /dev/null @@ -1,107 +0,0 @@ - - - diff --git a/spec/static/main.js b/spec/static/main.js deleted file mode 100644 index 8a7afc6482cda..0000000000000 --- a/spec/static/main.js +++ /dev/null @@ -1,172 +0,0 @@ -// Deprecated APIs are still supported and should be tested. -process.throwDeprecation = false; - -const electron = require('electron'); -const { app, BrowserWindow, dialog, ipcMain, session } = electron; - -try { - require('fs').rmdirSync(app.getPath('userData'), { recursive: true }); -} catch (e) { - console.warn('Warning: couldn\'t clear user data directory:', e); -} - -const fs = require('fs'); -const path = require('path'); -const util = require('util'); -const v8 = require('v8'); - -const argv = require('yargs') - .boolean('ci') - .array('files') - .string('g').alias('g', 'grep') - .boolean('i').alias('i', 'invert') - .argv; - -let window = null; - -v8.setFlagsFromString('--expose_gc'); -app.commandLine.appendSwitch('js-flags', '--expose_gc'); -app.commandLine.appendSwitch('ignore-certificate-errors'); -app.commandLine.appendSwitch('disable-renderer-backgrounding'); -// Some ports are considered to be "unsafe" by Chromium -// but Windows on Microsoft-hosted agents sometimes assigns one of them -// to a Node.js server. Chromium refuses to establish a connection -// and the whole app crashes with the "Error: net::ERR_UNSAFE_PORT" error. -// Let's allow connections to those ports to avoid test failures. -// Use a comma-separated list of ports as a flag value, e.g. "666,667,668". -app.commandLine.appendSwitch('explicitly-allowed-ports', '2049'); - -// Disable security warnings (the security warnings test will enable them) -process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true; - -// Accessing stdout in the main process will result in the process.stdout -// throwing UnknownSystemError in renderer process sometimes. This line makes -// sure we can reproduce it in renderer process. -// eslint-disable-next-line -process.stdout - -// Access console to reproduce #3482. -// eslint-disable-next-line -console - -ipcMain.on('message', function (event, ...args) { - event.sender.send('message', ...args); -}); - -ipcMain.handle('get-modules', () => Object.keys(electron)); -ipcMain.handle('get-temp-dir', () => app.getPath('temp')); -ipcMain.handle('ping', () => null); - -// Write output to file if OUTPUT_TO_FILE is defined. -const outputToFile = process.env.OUTPUT_TO_FILE; -const print = function (_, method, args) { - const output = util.format.apply(null, args); - if (outputToFile) { - fs.appendFileSync(outputToFile, output + '\n'); - } else { - console[method](output); - } -}; -ipcMain.on('console-call', print); - -ipcMain.on('process.exit', function (event, code) { - process.exit(code); -}); - -ipcMain.on('eval', function (event, script) { - event.returnValue = eval(script) // eslint-disable-line -}); - -ipcMain.on('echo', function (event, msg) { - event.returnValue = msg; -}); - -process.removeAllListeners('uncaughtException'); -process.on('uncaughtException', function (error) { - console.error(error, error.stack); - process.exit(1); -}); - -global.nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; - -app.on('window-all-closed', function () { - app.quit(); -}); - -app.on('child-process-gone', (event, details) => { - if (details.type === 'GPU' && details.reason !== 'clean-exit') { - if (details.reason === 'crashed') { - console.log('GPU process crashed'); - } else { - console.log(`GPU process exited with code ${details.exitCode}`); - } - } -}); - -app.on('renderer-process-crashed', (event, contents, killed) => { - console.log(`webContents ${contents.id} crashed: ${contents.getURL()} (killed=${killed})`); -}); - -app.whenReady().then(async function () { - await session.defaultSession.clearCache(); - await session.defaultSession.clearStorageData(); - // Test if using protocol module would crash. - electron.protocol.registerStringProtocol('test-if-crashes', function () {}); - - window = new BrowserWindow({ - title: 'Electron Tests', - show: false, - width: 800, - height: 600, - webPreferences: { - backgroundThrottling: false, - nodeIntegration: true, - webviewTag: true, - contextIsolation: false - } - }); - window.loadFile('static/index.html', { - query: { - grep: argv.grep, - invert: argv.invert ? 'true' : '', - files: argv.files ? argv.files.join(',') : undefined - } - }); - window.on('unresponsive', function () { - const chosen = dialog.showMessageBox(window, { - type: 'warning', - buttons: ['Close', 'Keep Waiting'], - message: 'Window is not responding', - detail: 'The window is not responding. Would you like to force close it or just keep waiting?' - }); - if (chosen === 0) window.destroy(); - }); - window.webContents.on('crashed', function () { - console.error('Renderer process crashed'); - process.exit(1); - }); -}); - -ipcMain.on('handle-unhandled-rejection', (event, message) => { - suspendListeners(process, 'unhandledRejection', (error) => { - event.returnValue = error.message; - }); - fs.readFile(__filename, () => { - Promise.reject(new Error(message)); - }); -}); - -// Suspend listeners until the next event and then restore them -const suspendListeners = (emitter, eventName, callback) => { - const listeners = emitter.listeners(eventName); - emitter.removeAllListeners(eventName); - emitter.once(eventName, (...args) => { - emitter.removeAllListeners(eventName); - listeners.forEach((listener) => { - emitter.on(eventName, listener); - }); - - // eslint-disable-next-line standard/no-callback-literal - callback(...args); - }); -}; diff --git a/spec/ts-smoke/electron/main.ts b/spec/ts-smoke/electron/main.ts index 6cd4db3b71efd..dec772168fd69 100644 --- a/spec/ts-smoke/electron/main.ts +++ b/spec/ts-smoke/electron/main.ts @@ -1,4 +1,4 @@ -// tslint:disable:ordered-imports curly no-console no-angle-bracket-type-assertion object-literal-sort-keys only-arrow-functions +/* eslint-disable */ import { app, @@ -6,6 +6,7 @@ import { BrowserWindow, contentTracing, dialog, + desktopCapturer, globalShortcut, ipcMain, Menu, @@ -15,75 +16,75 @@ import { powerSaveBlocker, protocol, Tray, - clipboard, - crashReporter, - nativeImage, screen, - shell, session, systemPreferences, webContents, - Event, TouchBar -} from 'electron' +} from 'electron/main'; -import * as path from 'path' +import { clipboard, crashReporter, nativeImage, shell } from 'electron/common'; +import * as path from 'node:path'; // Quick start -// https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md +// https://github.com/electron/electron/blob/main/docs/tutorial/quick-start.md // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the javascript object is GCed. -let mainWindow: Electron.BrowserWindow = null -const mainWindow2: BrowserWindow = null +let mainWindow: Electron.BrowserWindow = null; // Quit when all windows are closed. app.on('window-all-closed', () => { if (process.platform !== 'darwin') { - app.quit() + app.quit(); } -}) +}); // Check single instance app -const gotLock = app.requestSingleInstanceLock() +const gotLock = app.requestSingleInstanceLock(); if (!gotLock) { - app.quit() - process.exit(0) + app.quit(); + process.exit(0); } // This method will be called when Electron has done everything // initialization and ready for creating browser windows. app.whenReady().then(() => { // Create the browser window. - mainWindow = new BrowserWindow({ width: 800, height: 600 }) + mainWindow = new BrowserWindow({ width: 800, height: 600 }); // and load the index.html of the app. - mainWindow.loadURL(`file://${__dirname}/index.html`) - mainWindow.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }) - mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }) - mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer', postData: [{ type: 'rawData', bytes: Buffer.from([123]) }] }) - - mainWindow.webContents.openDevTools() - mainWindow.webContents.toggleDevTools() - mainWindow.webContents.openDevTools({ mode: 'detach' }) - mainWindow.webContents.closeDevTools() - mainWindow.webContents.addWorkSpace('/path/to/workspace') - mainWindow.webContents.removeWorkSpace('/path/to/workspace') - const opened: boolean = mainWindow.webContents.isDevToolsOpened() - const focused = mainWindow.webContents.isDevToolsFocused() + mainWindow.loadURL(`file://${__dirname}/index.html`); + mainWindow.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }); + mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }); + mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer', postData: [{ type: 'rawData', bytes: Buffer.from([123]) }] }); + + mainWindow.webContents.openDevTools(); + mainWindow.webContents.toggleDevTools(); + mainWindow.webContents.openDevTools({ mode: 'detach' }); + mainWindow.webContents.closeDevTools(); + mainWindow.webContents.addWorkSpace('/path/to/workspace'); + mainWindow.webContents.removeWorkSpace('/path/to/workspace'); + + const opened = mainWindow.webContents.isDevToolsOpened(); + console.log('isDevToolsOpened', opened); + + const focused = mainWindow.webContents.isDevToolsFocused(); + console.log('isDevToolsFocused', focused); + // Emitted when the window is closed. mainWindow.on('closed', () => { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. - mainWindow = null - }) + mainWindow = null; + }); - mainWindow.webContents.setVisualZoomLevelLimits(50, 200) + mainWindow.webContents.setVisualZoomLevelLimits(50, 200); - mainWindow.webContents.print({ silent: true, printBackground: false }) - mainWindow.webContents.print() + mainWindow.webContents.print({ silent: true, printBackground: false }); + mainWindow.webContents.print(); mainWindow.webContents.printToPDF({ margins: { @@ -91,96 +92,100 @@ app.whenReady().then(() => { }, printBackground: true, pageRanges: '1-3', - landscape: true - }).then((data: Buffer) => console.log(data)) - - mainWindow.webContents.printToPDF({}).then(data => console.log(data)) - - mainWindow.webContents.executeJavaScript('return true;').then((v: boolean) => console.log(v)) - mainWindow.webContents.executeJavaScript('return true;', true).then((v: boolean) => console.log(v)) - mainWindow.webContents.executeJavaScript('return true;', true) - mainWindow.webContents.executeJavaScript('return true;', true).then((result: boolean) => console.log(result)) - mainWindow.webContents.insertText('blah, blah, blah') - mainWindow.webContents.startDrag({ file: '/path/to/img.png', icon: nativeImage.createFromPath('/path/to/icon.png') }) - mainWindow.webContents.findInPage('blah') + landscape: true, + pageSize: { + width: 100, + height: 100 + } + }).then((data: Buffer) => console.log(data)); + + mainWindow.webContents.printToPDF({}).then(data => console.log(data)); + + mainWindow.webContents.executeJavaScript('return true;').then((v: boolean) => console.log(v)); + mainWindow.webContents.executeJavaScript('return true;', true).then((v: boolean) => console.log(v)); + mainWindow.webContents.executeJavaScript('return true;', true); + mainWindow.webContents.executeJavaScript('return true;', true).then((result: boolean) => console.log(result)); + mainWindow.webContents.insertText('blah, blah, blah'); + mainWindow.webContents.startDrag({ file: '/path/to/img.png', icon: nativeImage.createFromPath('/path/to/icon.png') }); + mainWindow.webContents.findInPage('blah'); mainWindow.webContents.findInPage('blah', { forward: true, matchCase: false - }) - mainWindow.webContents.stopFindInPage('clearSelection') - mainWindow.webContents.stopFindInPage('keepSelection') - mainWindow.webContents.stopFindInPage('activateSelection') + }); + mainWindow.webContents.stopFindInPage('clearSelection'); + mainWindow.webContents.stopFindInPage('keepSelection'); + mainWindow.webContents.stopFindInPage('activateSelection'); - mainWindow.loadURL('https://github.com') + mainWindow.loadURL('https://github.com'); mainWindow.webContents.on('did-finish-load', function () { mainWindow.webContents.savePage('/tmp/test.html', 'HTMLComplete').then(() => { - console.log('Page saved successfully') - }) - }) + console.log('Page saved successfully'); + }); + }); try { - mainWindow.webContents.debugger.attach('1.1') + mainWindow.webContents.debugger.attach('1.1'); } catch (err) { - console.log('Debugger attach failed : ', err) + console.log('Debugger attach failed : ', err); } mainWindow.webContents.debugger.on('detach', function (event, reason) { - console.log('Debugger detached due to : ', reason) - }) + console.log('Debugger detached due to : ', reason); + }); mainWindow.webContents.debugger.on('message', function (event, method, params: any) { if (method === 'Network.requestWillBeSent') { if (params.request.url === 'https://www.github.com') { - mainWindow.webContents.debugger.detach() + mainWindow.webContents.debugger.detach(); } } - }) + }); - mainWindow.webContents.debugger.sendCommand('Network.enable') + mainWindow.webContents.debugger.sendCommand('Network.enable'); mainWindow.webContents.capturePage().then(image => { - console.log(image.toDataURL()) - }) + console.log(image.toDataURL()); + }); mainWindow.webContents.capturePage({ x: 0, y: 0, width: 100, height: 200 }).then(image => { - console.log(image.toPNG()) - }) -}) + console.log(image.toPNG()); + }); +}); -app.commandLine.appendSwitch('enable-web-bluetooth') +app.commandLine.appendSwitch('enable-web-bluetooth'); app.whenReady().then(() => { mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => { - event.preventDefault() + event.preventDefault(); const result = (() => { for (const device of deviceList) { if (device.deviceName === 'test') { - return device + return device; } } - return null - })() + return null; + })(); if (!result) { - callback('') + callback(''); } else { - callback(result.deviceId) + callback(result.deviceId); } - }) -}) + }); +}); // Locale -app.getLocale() +app.getLocale(); // Desktop environment integration -app.addRecentDocument('/Users/USERNAME/Desktop/work.type') -app.clearRecentDocuments() +app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); +app.clearRecentDocuments(); const dockMenu = Menu.buildFromTemplate([ { label: 'New Window', click: () => { - console.log('New Window') + console.log('New Window'); } }, { @@ -224,14 +229,14 @@ const dockMenu = Menu.buildFromTemplate([ } ] } -]) -app.dock.setMenu(dockMenu) -app.dock.setBadge('foo') -const dockid = app.dock.bounce('informational') -app.dock.cancelBounce(dockid) -app.dock.setIcon('/path/to/icon.png') +]); +app.dock.setMenu(dockMenu); +app.dock.setBadge('foo'); +const dockid = app.dock.bounce('informational'); +app.dock.cancelBounce(dockid); +app.dock.setIcon('/path/to/icon.png'); -app.setBadgeCount(app.getBadgeCount() + 1) +app.setBadgeCount(app.getBadgeCount() + 1); app.setUserTasks([ { @@ -243,8 +248,8 @@ app.setUserTasks([ description: 'Create a new window', workingDirectory: path.dirname(process.execPath) } -]) -app.setUserTasks([]) +]); +app.setUserTasks([]); app.setJumpList([ { @@ -302,127 +307,150 @@ app.setJumpList([ description: 'Recover Project' }] } -]) +]); if (app.isUnityRunning()) { - console.log('unity running') + console.log('unity running'); } if (app.isAccessibilitySupportEnabled()) { - console.log('a11y running') + console.log('a11y running'); } -app.setLoginItemSettings({ openAtLogin: true, openAsHidden: false }) -console.log(app.getLoginItemSettings().wasOpenedAtLogin) +app.setLoginItemSettings({ openAtLogin: true, openAsHidden: false }); +console.log(app.getLoginItemSettings().wasOpenedAtLogin); app.setAboutPanelOptions({ applicationName: 'Test', version: '1.2.3' -}) +}); // Online/Offline Event Detection -// https://github.com/electron/electron/blob/master/docs/tutorial/online-offline-events.md +// https://github.com/electron/electron/blob/main/docs/tutorial/online-offline-events.md -let onlineStatusWindow: Electron.BrowserWindow +let onlineStatusWindow: Electron.BrowserWindow; app.whenReady().then(() => { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, vibrancy: 'sidebar' }) - onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`) -}) -app.on('accessibility-support-changed', (_, enabled) => console.log('accessibility: ' + enabled)) - -ipcMain.on('online-status-changed', (event: any, status: any) => { - console.log(status) -}) + onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, vibrancy: 'sidebar' }); + onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`); +}); +app.on('accessibility-support-changed', (_, enabled) => console.log('accessibility: ' + enabled)); -// Synopsis -// https://github.com/electron/electron/blob/master/docs/api/synopsis.md +ipcMain.on('online-status-changed', (event, status: any) => { + console.log(status); +}); app.whenReady().then(() => { window = new BrowserWindow({ width: 800, height: 600, titleBarStyle: 'hiddenInset' - }) - window.loadURL('https://github.com') -}) + }); + window.loadURL('https://github.com'); +}); // Supported command line switches -// https://github.com/electron/electron/blob/master/docs/api/command-line-switches.md +// https://github.com/electron/electron/blob/main/docs/api/command-line-switches.md -app.commandLine.appendSwitch('remote-debugging-port', '8315') -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') -app.commandLine.appendSwitch('vmodule', 'console=0') +app.commandLine.appendSwitch('remote-debugging-port', '8315'); +app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); +app.commandLine.appendSwitch('vmodule', 'console=0'); // systemPreferences -// https://github.com/electron/electron/blob/master/docs/api/system-preferences.md +// https://github.com/electron/electron/blob/main/docs/api/system-preferences.md const browserOptions = { width: 1000, height: 800, transparent: false, frame: true -} +}; // Make the window transparent only if the platform supports it. if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) { - browserOptions.transparent = true - browserOptions.frame = false + browserOptions.transparent = true; + browserOptions.frame = false; } if (process.platform === 'win32') { - systemPreferences.on('color-changed', () => { console.log('color changed') }) - systemPreferences.on('inverted-color-scheme-changed', (_, inverted) => console.log(inverted ? 'inverted' : 'not inverted')) - console.log('Color for menu is', systemPreferences.getColor('menu')) + systemPreferences.on('color-changed', () => { console.log('color changed'); }); + // @ts-expect-error Removed API + systemPreferences.on('inverted-color-scheme-changed', (_, inverted) => console.log(inverted ? 'inverted' : 'not inverted')); + // @ts-expect-error Removed API + systemPreferences.on('high-contrast-color-scheme-changed', (_, highContrast) => console.log(highContrast ? 'high contrast' : 'not high contrast')); + console.log('Color for menu is', systemPreferences.getColor('menu')); } if (process.platform === 'darwin') { - const value: string = systemPreferences.getUserDefault('Foo', 'string'); - // @ts-expect-error - const value2: number = systemPreferences.getUserDefault('Foo', 'boolean'); + const value = systemPreferences.getUserDefault('Foo', 'string'); + console.log(value); + const value2 = systemPreferences.getUserDefault('Foo', 'boolean'); + console.log(value2); + // @ts-expect-error Removed API + console.log(systemPreferences.getAppLevelAppearance()); + // @ts-expect-error Removed API + systemPreferences.setAppLevelAppearance('dark'); + // @ts-expect-error Removed API + console.log(systemPreferences.appLevelAppearance); + // @ts-expect-error Removed API + console.log(systemPreferences.getColor('alternate-selected-control-text')); } // Create the window. -const win1 = new BrowserWindow(browserOptions) +const win1 = new BrowserWindow(browserOptions); // Navigate. if (browserOptions.transparent) { - win1.loadURL('file://' + __dirname + '/index.html') + win1.loadURL(`file://${__dirname}/index.html`); } else { // No transparency, so we load a fallback that uses basic styles. - win1.loadURL('file://' + __dirname + '/fallback.html') + win1.loadURL(`file://${__dirname}/fallback.html`); } // app -// https://github.com/electron/electron/blob/master/docs/api/app.md +// https://github.com/electron/electron/blob/main/docs/api/app.md app.on('certificate-error', function (event, webContents, url, error, certificate, callback) { if (url === 'https://github.com') { // Verification logic. - event.preventDefault() - callback(true) + event.preventDefault(); + callback(true); } else { - callback(false) + callback(false); } -}) +}); app.on('select-client-certificate', function (event, webContents, url, list, callback) { - event.preventDefault() - callback(list[0]) -}) + event.preventDefault(); + callback(list[0]); +}); app.on('login', function (event, webContents, request, authInfo, callback) { - event.preventDefault() - callback('username', 'secret') -}) + event.preventDefault(); + callback('username', 'secret'); +}); -const win2 = new BrowserWindow({ show: false }) +const win2 = new BrowserWindow({ show: false }); win2.once('ready-to-show', () => { - win2.show() -}) + win2.show(); +}); + +app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) }); +app.exit(0); + +app.configureHostResolver({ secureDnsMode: 'off' }); + +// @ts-expect-error Invalid type value +app.configureHostResolver({ secureDnsMode: 'foo' }); -app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) }) -app.exit(0) +// @ts-expect-error Removed API +console.log(app.runningUnderRosettaTranslation); + +// @ts-expect-error Removed API +app.on('gpu-process-crashed', () => {}); + +// @ts-expect-error Removed API +app.on('renderer-process-crashed', () => {}); // auto-updater -// https://github.com/electron/electron/blob/master/docs/api/auto-updater.md +// https://github.com/electron/electron/blob/main/docs/api/auto-updater.md autoUpdater.setFeedURL({ url: 'http://mycompany.com/myapp/latest?version=' + app.getVersion(), @@ -430,63 +458,63 @@ autoUpdater.setFeedURL({ key: 'value' }, serverType: 'default' -}) -autoUpdater.checkForUpdates() -autoUpdater.quitAndInstall() +}); +autoUpdater.checkForUpdates(); +autoUpdater.quitAndInstall(); autoUpdater.on('error', (error) => { - console.log('error', error) -}) + console.log('error', error); +}); autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateURL) => { - console.log('update-downloaded', releaseNotes, releaseName, releaseDate, updateURL) -}) + console.log('update-downloaded', releaseNotes, releaseName, releaseDate, updateURL); +}); // BrowserWindow -// https://github.com/electron/electron/blob/master/docs/api/browser-window.md +// https://github.com/electron/electron/blob/main/docs/api/browser-window.md -let win3 = new BrowserWindow({ width: 800, height: 600, show: false }) +let win3 = new BrowserWindow({ width: 800, height: 600, show: false }); win3.on('closed', () => { - win3 = null -}) - -win3.loadURL('https://github.com') -win3.show() - -const toolbarRect = document.getElementById('toolbar').getBoundingClientRect() -win3.setSheetOffset(toolbarRect.height) - -let window = new BrowserWindow() -window.setProgressBar(0.5) -window.setRepresentedFilename('/etc/passwd') -window.setDocumentEdited(true) -window.previewFile('/path/to/file') -window.previewFile('/path/to/file', 'Displayed Name') -window.setVibrancy('menu') -window.setVibrancy('titlebar') -window.setVibrancy('selection') -window.setVibrancy('popover') -window.setIcon('/path/to/icon') + win3 = null; +}); + +win3.loadURL('https://github.com'); +win3.show(); + +const toolbarRect = document.getElementById('toolbar').getBoundingClientRect(); +win3.setSheetOffset(toolbarRect.height); + +let window = new BrowserWindow(); +window.setProgressBar(0.5); +window.setRepresentedFilename('/etc/passwd'); +window.setDocumentEdited(true); +window.previewFile('/path/to/file'); +window.previewFile('/path/to/file', 'Displayed Name'); +window.setVibrancy('menu'); +window.setVibrancy('titlebar'); +window.setVibrancy('selection'); +window.setVibrancy('popover'); +window.setIcon('/path/to/icon'); // content-tracing -// https://github.com/electron/electron/blob/master/docs/api/content-tracing.md +// https://github.com/electron/electron/blob/main/docs/api/content-tracing.md const options = { categoryFilter: '*', traceOptions: 'record-until-full,enable-sampling' -} +}; contentTracing.startRecording(options).then(() => { - console.log('Tracing started') + console.log('Tracing started'); setTimeout(function () { contentTracing.stopRecording('').then(path => { - console.log(`Tracing data recorded to ${path}`) - }) - }, 5000) -}) + console.log(`Tracing data recorded to ${path}`); + }); + }, 5000); +}); // dialog -// https://github.com/electron/electron/blob/master/docs/api/dialog.md +// https://github.com/electron/electron/blob/main/docs/api/dialog.md // variant without browserWindow dialog.showOpenDialogSync({ @@ -494,7 +522,7 @@ dialog.showOpenDialogSync({ defaultPath: '/var/log/syslog', filters: [{ name: '', extensions: [''] }], properties: ['openFile', 'openDirectory', 'multiSelections'] -}) +}); // variant with browserWindow dialog.showOpenDialog(win3, { @@ -503,44 +531,71 @@ dialog.showOpenDialog(win3, { filters: [{ name: '', extensions: [''] }], properties: ['openFile', 'openDirectory', 'multiSelections'] }).then(ret => { - console.log(ret) -}) + console.log(ret); +}); + +// variants without browserWindow +dialog.showMessageBox({ message: 'test', type: 'warning' }); +dialog.showMessageBoxSync({ message: 'test', type: 'error' }); + +// @ts-expect-error Invalid type value +dialog.showMessageBox({ message: 'test', type: 'foo' }); +// @ts-expect-error Invalid type value +dialog.showMessageBoxSync({ message: 'test', type: 'foo' }); + +// variants with browserWindow +dialog.showMessageBox(win3, { message: 'test', type: 'question' }); +dialog.showMessageBoxSync(win3, { message: 'test', type: 'info' }); + +// @ts-expect-error Invalid type value +dialog.showMessageBox(win3, { message: 'test', type: 'foo' }); +// @ts-expect-error Invalid type value +dialog.showMessageBoxSync(win3, { message: 'test', type: 'foo' }); + +// desktopCapturer +// https://github.com/electron/electron/blob/main/docs/api/desktop-capturer.md + +ipcMain.handle('get-sources', (event, options) => desktopCapturer.getSources(options)); + +desktopCapturer.getSources({ types: ['window', 'screen'] }); +// @ts-expect-error Invalid type value +desktopCapturer.getSources({ types: ['unknown'] }); // global-shortcut -// https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md +// https://github.com/electron/electron/blob/main/docs/api/global-shortcut.md // Register a 'ctrl+x' shortcut listener. const ret = globalShortcut.register('ctrl+x', () => { - console.log('ctrl+x is pressed') -}) -if (!ret) { console.log('registration fails') } + console.log('ctrl+x is pressed'); +}); +if (!ret) { console.log('registration fails'); } // Check whether a shortcut is registered. -console.log(globalShortcut.isRegistered('ctrl+x')) +console.log(globalShortcut.isRegistered('ctrl+x')); // Unregister a shortcut. -globalShortcut.unregister('ctrl+x') +globalShortcut.unregister('ctrl+x'); // Unregister all shortcuts. -globalShortcut.unregisterAll() +globalShortcut.unregisterAll(); // ipcMain -// https://github.com/electron/electron/blob/master/docs/api/ipc-main-process.md +// https://github.com/electron/electron/blob/main/docs/api/ipc-main.md -ipcMain.on('asynchronous-message', (event, arg: any) => { - console.log(arg) // prints "ping" - event.sender.send('asynchronous-reply', 'pong') -}) +ipcMain.handle('ping-pong', (event, arg: any) => { + console.log(arg); // prints "ping" + return 'pong'; +}); -ipcMain.on('synchronous-message', (event, arg: any) => { - console.log(arg) // prints "ping" - event.returnValue = 'pong' -}) +ipcMain.on('asynchronous-message', (event, arg: any) => { + console.log(arg); // prints "ping" + event.sender.send('asynchronous-reply', 'pong'); +}); ipcMain.on('synchronous-message', (event, arg: any) => { - console.log("event isn't namespaced and refers to the correct type.") - event.returnValue = 'pong' -}) + console.log(arg); // prints "ping" + event.returnValue = 'pong'; +}); const winWindows = new BrowserWindow({ width: 800, @@ -548,31 +603,32 @@ const winWindows = new BrowserWindow({ show: false, thickFrame: false, type: 'toolbar' -}) +}); +console.log(winWindows.id); // menu-item -// https://github.com/electron/electron/blob/master/docs/api/menu-item.md +// https://github.com/electron/electron/blob/main/docs/api/menu-item.md -const menuItem = new MenuItem({}) +const menuItem = new MenuItem({}); -menuItem.label = 'Hello World!' +menuItem.label = 'Hello World!'; menuItem.click = (passedMenuItem: Electron.MenuItem, browserWindow: Electron.BrowserWindow) => { - console.log('click', passedMenuItem, browserWindow) -} + console.log('click', passedMenuItem, browserWindow); +}; // menu -// https://github.com/electron/electron/blob/master/docs/api/menu.md +// https://github.com/electron/electron/blob/main/docs/api/menu.md -let menu = new Menu() -menu.append(new MenuItem({ label: 'MenuItem1', click: () => { console.log('item 1 clicked') } })) -menu.append(new MenuItem({ type: 'separator' })) -menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true })) -menu.insert(0, menuItem) +let menu = new Menu(); +menu.append(new MenuItem({ label: 'MenuItem1', click: () => { console.log('item 1 clicked'); } })); +menu.append(new MenuItem({ type: 'separator' })); +menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true })); +menu.insert(0, menuItem); -console.log(menu.items) +console.log(menu.items); -const pos = screen.getCursorScreenPoint() -menu.popup({ x: pos.x, y: pos.y }) +const pos = screen.getCursorScreenPoint(); +menu.popup({ x: pos.x, y: pos.y }); // main.js const template = [ @@ -614,7 +670,7 @@ const template = [ { label: 'Quit', accelerator: 'Command+Q', - click: () => { app.quit() } + click: () => { app.quit(); } } ] }, @@ -663,8 +719,8 @@ const template = [ label: 'Reload', accelerator: 'Command+R', click: (item, focusedWindow) => { - if (focusedWindow) { - focusedWindow.webContents.reloadIgnoringCache() + if (focusedWindow instanceof BrowserWindow) { + focusedWindow.webContents.reloadIgnoringCache(); } } }, @@ -672,8 +728,8 @@ const template = [ label: 'Toggle DevTools', accelerator: 'Alt+Command+I', click: (item, focusedWindow) => { - if (focusedWindow) { - focusedWindow.webContents.toggleDevTools() + if (focusedWindow instanceof BrowserWindow) { + focusedWindow.webContents.toggleDevTools(); } } }, @@ -684,8 +740,8 @@ const template = [ label: 'Actual Size', accelerator: 'CmdOrCtrl+0', click: (item, focusedWindow) => { - if (focusedWindow) { - focusedWindow.webContents.zoomLevel = 0 + if (focusedWindow instanceof BrowserWindow) { + focusedWindow.webContents.zoomLevel = 0; } } }, @@ -693,9 +749,9 @@ const template = [ label: 'Zoom In', accelerator: 'CmdOrCtrl+Plus', click: (item, focusedWindow) => { - if (focusedWindow) { - const { webContents } = focusedWindow - webContents.zoomLevel += 0.5 + if (focusedWindow instanceof BrowserWindow) { + const { webContents } = focusedWindow; + webContents.zoomLevel += 0.5; } } }, @@ -703,9 +759,9 @@ const template = [ label: 'Zoom Out', accelerator: 'CmdOrCtrl+-', click: (item, focusedWindow) => { - if (focusedWindow) { - const { webContents } = focusedWindow - webContents.zoomLevel -= 0.5 + if (focusedWindow instanceof BrowserWindow) { + const { webContents } = focusedWindow; + webContents.zoomLevel -= 0.5; } } } @@ -737,11 +793,11 @@ const template = [ label: 'Help', submenu: [] } -] +]; -menu = Menu.buildFromTemplate(template) +menu = Menu.buildFromTemplate(template); -Menu.setApplicationMenu(menu) // Must be called within app.whenReady().then(function(){ ... }); +Menu.setApplicationMenu(menu); // Must be called within app.whenReady().then(function(){ ... }); Menu.buildFromTemplate([ { label: '4', id: '4' }, @@ -749,7 +805,7 @@ Menu.buildFromTemplate([ { label: '1', id: '1', before: ['4'] }, { label: '2', id: '2' }, { label: '3', id: '3' } -]) +]); Menu.buildFromTemplate([ { label: 'a' }, @@ -758,7 +814,7 @@ Menu.buildFromTemplate([ { label: '2' }, { label: 'c' }, { label: '3' } -]) +]); // All possible MenuItem roles Menu.buildFromTemplate([ @@ -791,7 +847,7 @@ Menu.buildFromTemplate([ { role: 'stopSpeaking' }, { role: 'close' }, { role: 'minimize' }, - { role: 'zoom' }, + { role: 'zoom' }, { role: 'front' }, { role: 'appMenu' }, { role: 'fileMenu' }, @@ -803,140 +859,144 @@ Menu.buildFromTemplate([ { role: 'toggleTabBar' }, { role: 'selectNextTab' }, { role: 'selectPreviousTab' }, + { role: 'showAllTabs' }, { role: 'mergeAllWindows' }, { role: 'clearRecentDocuments' }, - { role : 'moveTabToNewWindow'} -]) + { role: 'moveTabToNewWindow' } +]); // net -// https://github.com/electron/electron/blob/master/docs/api/net.md +// https://github.com/electron/electron/blob/main/docs/api/net.md app.whenReady().then(() => { - const request = net.request('https://github.com') - request.setHeader('Some-Custom-Header-Name', 'Some-Custom-Header-Value') - const header = request.getHeader('Some-Custom-Header-Name') - request.removeHeader('Some-Custom-Header-Name') + const request = net.request('https://github.com'); + request.setHeader('Some-Custom-Header-Name', 'Some-Custom-Header-Value'); + const header = request.getHeader('Some-Custom-Header-Name'); + console.log('header', header); + request.removeHeader('Some-Custom-Header-Name'); request.on('response', (response) => { - console.log(`Status code: ${response.statusCode}`) - console.log(`Status message: ${response.statusMessage}`) - console.log(`Headers: ${JSON.stringify(response.headers)}`) - console.log(`Http version: ${response.httpVersion}`) - console.log(`Major Http version: ${response.httpVersionMajor}`) - console.log(`Minor Http version: ${response.httpVersionMinor}`) + console.log(`Status code: ${response.statusCode}`); + console.log(`Status message: ${response.statusMessage}`); + console.log(`Headers: ${JSON.stringify(response.headers)}`); + console.log(`Http version: ${response.httpVersion}`); + console.log(`Major Http version: ${response.httpVersionMajor}`); + console.log(`Minor Http version: ${response.httpVersionMinor}`); response.on('data', (chunk) => { - console.log(`BODY: ${chunk}`) - }) + console.log(`BODY: ${chunk}`); + }); response.on('end', () => { - console.log('No more data in response.') - }) + console.log('No more data in response.'); + }); response.on('error', () => { - console.log('"error" event emitted') - }) + console.log('"error" event emitted'); + }); response.on('aborted', () => { - console.log('"aborted" event emitted') - }) - }) + console.log('"aborted" event emitted'); + }); + }); request.on('login', (authInfo, callback) => { - callback('username', 'password') - }) + callback('username', 'password'); + }); request.on('finish', () => { - console.log('"finish" event emitted') - }) + console.log('"finish" event emitted'); + }); request.on('abort', () => { - console.log('"abort" event emitted') - }) + console.log('"abort" event emitted'); + }); request.on('error', () => { - console.log('"error" event emitted') - }) - request.write('Hello World!', 'utf-8') - request.end('Hello World!', 'utf-8') - request.abort() -}) + console.log('"error" event emitted'); + }); + request.write('Hello World!', 'utf-8'); + request.end('Hello World!', 'utf-8'); + request.abort(); +}); // power-monitor -// https://github.com/electron/electron/blob/master/docs/api/power-monitor.md +// https://github.com/electron/electron/blob/main/docs/api/power-monitor.md app.whenReady().then(() => { powerMonitor.on('suspend', () => { - console.log('The system is going to sleep') - }) + console.log('The system is going to sleep'); + }); powerMonitor.on('resume', () => { - console.log('The system has resumed from sleep') - }) + console.log('The system has resumed from sleep'); + }); powerMonitor.on('on-ac', () => { - console.log('The system changed to AC power') - }) + console.log('The system changed to AC power'); + }); powerMonitor.on('on-battery', () => { - console.log('The system changed to battery power') - }) -}) + console.log('The system changed to battery power'); + }); +}); // power-save-blocker -// https://github.com/electron/electron/blob/master/docs/api/power-save-blocker.md +// https://github.com/electron/electron/blob/main/docs/api/power-save-blocker.md -const id = powerSaveBlocker.start('prevent-display-sleep') -console.log(powerSaveBlocker.isStarted(id)) +const id = powerSaveBlocker.start('prevent-display-sleep'); +console.log(powerSaveBlocker.isStarted(id)); -powerSaveBlocker.stop(id) +const stopped = powerSaveBlocker.stop(id); +console.log(`The powerSaveBlocker is ${stopped ? 'stopped' : 'not stopped'}`); // protocol -// https://github.com/electron/electron/blob/master/docs/api/protocol.md +// https://github.com/electron/electron/blob/main/docs/api/protocol.md app.whenReady().then(() => { - protocol.registerSchemesAsPrivileged([{ scheme: 'https', privileges: { standard: true, allowServiceWorkers: true } }]) + protocol.registerSchemesAsPrivileged([{ scheme: 'https', privileges: { standard: true, allowServiceWorkers: true } }]); protocol.registerFileProtocol('atom', (request, callback) => { - callback(`${__dirname}/${request.url}`) - }) + callback(`${__dirname}/${request.url}`); + }); protocol.registerBufferProtocol('atom', (request, callback) => { - callback({ mimeType: 'text/html', data: Buffer.from('
Response
') }) - }) + callback({ mimeType: 'text/html', data: Buffer.from('
Response
') }); + }); protocol.registerStringProtocol('atom', (request, callback) => { - callback('Hello World!') - }) + callback('Hello World!'); + }); protocol.registerHttpProtocol('atom', (request, callback) => { - callback({ url: request.url, method: request.method }) - }) + callback({ url: request.url, method: request.method }); + }); - protocol.unregisterProtocol('atom') + protocol.unregisterProtocol('atom'); - const registered: boolean = protocol.isProtocolRegistered('atom') -}) + const registered = protocol.isProtocolRegistered('atom'); + console.log('isProtocolRegistered', registered); +}); // tray -// https://github.com/electron/electron/blob/master/docs/api/tray.md +// https://github.com/electron/electron/blob/main/docs/api/tray.md -let appIcon: Electron.Tray = null +let appIcon: Electron.Tray = null; app.whenReady().then(() => { - appIcon = new Tray('/path/to/my/icon') + appIcon = new Tray('/path/to/my/icon'); const contextMenu = Menu.buildFromTemplate([ { label: 'Item1', type: 'radio' }, { label: 'Item2', type: 'radio' }, { label: 'Item3', type: 'radio', checked: true }, { label: 'Item4', type: 'radio' } - ]) + ]); - appIcon.setTitle('title') - appIcon.setToolTip('This is my application.') + appIcon.setTitle('title'); + appIcon.setToolTip('This is my application.'); - appIcon.setImage('/path/to/new/icon') - appIcon.setPressedImage('/path/to/new/icon') + appIcon.setImage('/path/to/new/icon'); + appIcon.setPressedImage('/path/to/new/icon'); - appIcon.popUpContextMenu(contextMenu, { x: 100, y: 100 }) - appIcon.setContextMenu(contextMenu) + appIcon.popUpContextMenu(contextMenu, { x: 100, y: 100 }); + appIcon.setContextMenu(contextMenu); - appIcon.setIgnoreDoubleClickEvents(true) + appIcon.setIgnoreDoubleClickEvents(true); appIcon.on('click', (event, bounds) => { - console.log('click', event, bounds) - }) + console.log('click', event, bounds); + }); appIcon.on('balloon-show', () => { - console.log('balloon-show') - }) + console.log('balloon-show'); + }); appIcon.displayBalloon({ title: 'Hello World!', @@ -946,34 +1006,31 @@ app.whenReady().then(() => { respectQuietTime: true, largeIcon: true, noSound: true - }) -}) + }); +}); // clipboard -// https://github.com/electron/electron/blob/master/docs/api/clipboard.md - -{ - let str: string - clipboard.writeText('Example String') - clipboard.writeText('Example String', 'selection') - clipboard.writeBookmark('foo', 'http://example.com') - clipboard.writeBookmark('foo', 'http://example.com', 'selection') - clipboard.writeFindText('foo') - str = clipboard.readText('selection') - str = clipboard.readFindText() - console.log(clipboard.availableFormats()) - console.log(clipboard.readBookmark().title) - clipboard.clear() - - clipboard.write({ - html: '', - text: 'Hello World!', - image: clipboard.readImage() - }) -} +// https://github.com/electron/electron/blob/main/docs/api/clipboard.md + +clipboard.writeText('Example String'); +clipboard.writeText('Example String', 'selection'); +clipboard.writeBookmark('foo', 'http://example.com'); +clipboard.writeBookmark('foo', 'http://example.com', 'selection'); +clipboard.writeFindText('foo'); +console.log(clipboard.readText('selection')); +console.log(clipboard.readFindText()); +console.log(clipboard.availableFormats()); +console.log(clipboard.readBookmark().title); +clipboard.clear(); + +clipboard.write({ + html: '', + text: 'Hello World!', + image: clipboard.readImage() +}); // crash-reporter -// https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md +// https://github.com/electron/electron/blob/main/docs/api/crash-reporter.md crashReporter.start({ productName: 'YourName', @@ -983,51 +1040,67 @@ crashReporter.start({ extra: { someKey: 'value' } -}) +}); -console.log(crashReporter.getLastCrashReport()) -console.log(crashReporter.getUploadedReports()) +console.log(crashReporter.getLastCrashReport()); +console.log(crashReporter.getUploadedReports()); // nativeImage -// https://github.com/electron/electron/blob/master/docs/api/native-image.md +// https://github.com/electron/electron/blob/main/docs/api/native-image.md -const appIcon2 = new Tray('/Users/somebody/images/icon.png') -const window2 = new BrowserWindow({ icon: '/Users/somebody/images/window.png' }) -const image = clipboard.readImage() -const appIcon3 = new Tray(image) -const appIcon4 = new Tray('/Users/somebody/images/icon.png') +const appIcon2 = new Tray('/Users/somebody/images/icon.png'); +appIcon2.destroy(); -const image2 = nativeImage.createFromPath('/Users/somebody/images/icon.png') +const window2 = new BrowserWindow({ icon: '/Users/somebody/images/window.png' }); +console.log(window2.id); + +const image = clipboard.readImage(); +console.log(image.getSize()); + +const appIcon3 = new Tray(image); +appIcon3.destroy(); + +const appIcon4 = new Tray('/Users/somebody/images/icon.png'); +appIcon4.destroy(); + +const image2 = nativeImage.createFromPath('/Users/somebody/images/icon.png'); +console.log(image2.getSize()); + +image2.resize({ quality: 'best' }); +image2.resize({ quality: 'better' }); +image2.resize({ quality: 'good' }); +// @ts-expect-error Invalid type value +image2.resize({ quality: 'bad' }); // process -// https://github.com/electron/electron/blob/master/docs/api/process.md - -console.log(process.versions.electron) -console.log(process.versions.chrome) -console.log(process.type) -console.log(process.resourcesPath) -console.log(process.mas) -console.log(process.windowsStore) -process.noAsar = true -process.crash() -process.hang() -process.setFdLimit(8192) +// https://github.com/electron/electron/blob/main/docs/api/process.md + +console.log(process.versions.electron); +console.log(process.versions.chrome); +console.log(process.type); +console.log(process.resourcesPath); +console.log(process.mas); +console.log(process.windowsStore); +process.noAsar = true; +process.crash(); +process.hang(); +process.setFdLimit(8192); // screen -// https://github.com/electron/electron/blob/master/docs/api/screen.md +// https://github.com/electron/electron/blob/main/docs/api/screen.md app.whenReady().then(() => { - const size = screen.getPrimaryDisplay().workAreaSize - mainWindow = new BrowserWindow({ width: size.width, height: size.height }) -}) + const size = screen.getPrimaryDisplay().workAreaSize; + mainWindow = new BrowserWindow({ width: size.width, height: size.height }); +}); app.whenReady().then(() => { - const displays = screen.getAllDisplays() - let externalDisplay: any = null + const displays = screen.getAllDisplays(); + let externalDisplay: any = null; for (const i in displays) { if (displays[i].bounds.x > 0 || displays[i].bounds.y > 0) { - externalDisplay = displays[i] - break + externalDisplay = displays[i]; + break; } } @@ -1035,188 +1108,232 @@ app.whenReady().then(() => { mainWindow = new BrowserWindow({ x: externalDisplay.bounds.x + 50, y: externalDisplay.bounds.y + 50 - }) + }); } screen.on('display-added', (event, display) => { - console.log('display-added', display) - }) + console.log('display-added', display); + }); screen.on('display-removed', (event, display) => { - console.log('display-removed', display) - }) + console.log('display-removed', display); + }); screen.on('display-metrics-changed', (event, display, changes) => { - console.log('display-metrics-changed', display, changes) - }) -}) + console.log('display-metrics-changed', display, changes); + }); +}); // shell -// https://github.com/electron/electron/blob/master/docs/api/shell.md +// https://github.com/electron/electron/blob/main/docs/api/shell.md -shell.showItemInFolder('/home/user/Desktop/test.txt') -shell.trashItem('/home/user/Desktop/test.txt').then(() => {}) +shell.showItemInFolder('/home/user/Desktop/test.txt'); +shell.trashItem('/home/user/Desktop/test.txt').then(() => {}); shell.openPath('/home/user/Desktop/test.txt').then(err => { - if (err) console.log(err) -}) + if (err) console.log(err); +}); shell.openExternal('https://github.com', { activate: false -}).then(() => {}) +}).then(() => {}); -shell.beep() +shell.beep(); -shell.writeShortcutLink('/home/user/Desktop/shortcut.lnk', 'update', shell.readShortcutLink('/home/user/Desktop/shortcut.lnk')) +shell.writeShortcutLink('/home/user/Desktop/shortcut.lnk', 'update', shell.readShortcutLink('/home/user/Desktop/shortcut.lnk')); // cookies -// https://github.com/electron/electron/blob/master/docs/api/cookies.md +// https://github.com/electron/electron/blob/main/docs/api/cookies.md { // Query all cookies. session.defaultSession.cookies.get({}) .then(cookies => { - console.log(cookies) + console.log(cookies); }).catch((error: Error) => { - console.log(error) - }) + console.log(error); + }); // Query all cookies associated with a specific url. session.defaultSession.cookies.get({ url: 'http://www.github.com' }) .then(cookies => { - console.log(cookies) + console.log(cookies); }).catch((error: Error) => { - console.log(error) - }) + console.log(error); + }); // Set a cookie with the given cookie data; // may overwrite equivalent cookies if they exist. - const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' } + const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' }; session.defaultSession.cookies.set(cookie) .then(() => { // success }, (error: Error) => { - console.error(error) - }) + console.error(error); + }); } // session -// https://github.com/electron/electron/blob/master/docs/api/session.md +// https://github.com/electron/electron/blob/main/docs/api/session.md + +session.defaultSession.clearStorageData({ storages: ['cookies', 'filesystem'] }); +session.defaultSession.clearStorageData({ storages: ['localstorage', 'indexdb', 'serviceworkers'] }); +session.defaultSession.clearStorageData({ storages: ['shadercache', 'cachestorage'] }); +// @ts-expect-error Invalid type value +session.defaultSession.clearStorageData({ storages: ['wrong_path'] }); + +session.defaultSession.clearStorageData({ quotas: ['syncable', 'temporary'] }); +// @ts-expect-error Invalid type value +session.defaultSession.clearStorageData({ quotas: ['bad_type'] }); session.defaultSession.on('will-download', (event, item, webContents) => { - event.preventDefault() + console.log('will-download', webContents.id); + event.preventDefault(); require('got')(item.getURL()).then((data: any) => { - require('fs').writeFileSync('/somewhere', data) - }) -}) + require('node:fs').writeFileSync('/somewhere', data); + }); +}); // In the main process. session.defaultSession.on('will-download', (event, item, webContents) => { + console.log('will-download', webContents.id); // Set the save path, making Electron not to prompt a save dialog. - item.setSavePath('/tmp/save.pdf') - console.log(item.getSavePath()) - console.log(item.getMimeType()) - console.log(item.getFilename()) - console.log(item.getTotalBytes()) + item.setSavePath('/tmp/save.pdf'); + console.log(item.getSavePath()); + console.log(item.getMimeType()); + console.log(item.getFilename()); + console.log(item.getTotalBytes()); item.on('updated', (_event, state) => { if (state === 'interrupted') { - console.log('Download is interrupted but can be resumed') + console.log('Download is interrupted but can be resumed'); } else if (state === 'progressing') { if (item.isPaused()) { - console.log('Download is paused') + console.log('Download is paused'); } else { - console.log(`Received bytes: ${item.getReceivedBytes()}`) + console.log(`Received bytes: ${item.getReceivedBytes()}`); } } - }) + }); item.on('done', function (e, state) { if (state === 'completed') { - console.log('Download successfully') + console.log('Download successfully'); } else { - console.log(`Download failed: ${state}`) + console.log(`Download failed: ${state}`); } - }) -}) + }); +}); // To emulate a GPRS connection with 50kbps throughput and 500 ms latency. session.defaultSession.enableNetworkEmulation({ latency: 500, downloadThroughput: 6400, uploadThroughput: 6400 -}) +}); // To emulate a network outage. session.defaultSession.enableNetworkEmulation({ offline: true -}) +}); session.defaultSession.setCertificateVerifyProc((request, callback) => { - const { hostname } = request + const { hostname } = request; if (hostname === 'github.com') { - callback(0) + callback(0); } else { - callback(-2) + callback(-2); } -}) +}); session.defaultSession.setPermissionRequestHandler(function (webContents, permission, callback) { if (webContents.getURL() === 'github.com') { if (permission === 'notifications') { - callback(false) - return + callback(false); + return; } } - callback(true) -}) + callback(true); +}); // consider any url ending with `example.com`, `foobar.com`, `baz` // for integrated authentication. -session.defaultSession.allowNTLMCredentialsForDomains('*example.com, *foobar.com, *baz') +session.defaultSession.allowNTLMCredentialsForDomains('*example.com, *foobar.com, *baz'); // consider all urls for integrated authentication. -session.defaultSession.allowNTLMCredentialsForDomains('*') +session.defaultSession.allowNTLMCredentialsForDomains('*'); // Modify the user agent for all requests to the following urls. const filter = { urls: ['https://*.github.com/*', '*://electron.github.io'] -} +}; session.defaultSession.webRequest.onBeforeSendHeaders(filter, function (details: any, callback: any) { - details.requestHeaders['User-Agent'] = 'MyAgent' - callback({ cancel: false, requestHeaders: details.requestHeaders }) -}) + details.requestHeaders['User-Agent'] = 'MyAgent'; + callback({ cancel: false, requestHeaders: details.requestHeaders }); +}); app.whenReady().then(function () { - const protocol = session.defaultSession.protocol + const protocol = session.defaultSession.protocol; protocol.registerFileProtocol('atom', function (request, callback) { - const url = request.url.substr(7) - callback(path.normalize(__dirname + '/' + url)) - }) -}) + const url = request.url.substr(7); + callback(path.normalize(`${__dirname}/${url}`)); + }); +}); // webContents -// https://github.com/electron/electron/blob/master/docs/api/web-contents.md +// https://github.com/electron/electron/blob/main/docs/api/web-contents.md -console.log(webContents.getAllWebContents()) -console.log(webContents.getFocusedWebContents()) +console.log(webContents.getAllWebContents()); +console.log(webContents.getFocusedWebContents()); const win4 = new BrowserWindow({ webPreferences: { offscreen: true } -}) +}); win4.webContents.on('paint', (event, dirty, _image) => { - console.log(dirty, _image.getBitmap()) -}) + console.log(dirty, _image.getBitmap()); +}); + +win4.webContents.on('devtools-open-url', (event, url) => { + console.log(url); +}); + +win4.webContents.insertCSS('body {}', { cssOrigin: 'user' }); + +// @ts-expect-error Invalid type value +win4.webContents.insertCSS('body {}', { cssOrigin: 'foo' }); + +win4.loadURL('http://github.com'); -win4.loadURL('http://github.com') +// @ts-expect-error Removed API +win4.webContents.getPrinters(); -const unusedTouchBar = new TouchBar({ +// @ts-expect-error Removed API +win4.webContents.on('scroll-touch-begin', () => {}); +// @ts-expect-error Removed API +win4.webContents.on('scroll-touch-edge', () => {}); +// @ts-expect-error Removed API +win4.webContents.on('scroll-touch-end', () => {}); + +// @ts-expect-error Removed API +win4.webContents.on('crashed', () => {}); + +win4.webContents.on('context-menu', (event, params) => { + // @ts-expect-error Removed API + console.log(params.inputFieldType); +}); + +// TouchBar +// https://github.com/electron/electron/blob/main/docs/api/touch-bar.md + +const touchBar = new TouchBar({ items: [ new TouchBar.TouchBarButton({ label: '' }), new TouchBar.TouchBarLabel({ label: '' }) ] -}) +}); + +mainWindow.setTouchBar(touchBar); diff --git a/spec/ts-smoke/electron/renderer.ts b/spec/ts-smoke/electron/renderer.ts index cef883bebe047..8165569591457 100644 --- a/spec/ts-smoke/electron/renderer.ts +++ b/spec/ts-smoke/electron/renderer.ts @@ -1,196 +1,185 @@ +/* eslint-disable */ -import { - desktopCapturer, - ipcRenderer, - webFrame, - clipboard, - crashReporter, - shell -} from 'electron' - -import * as fs from 'fs' +import { ipcRenderer, webFrame } from 'electron/renderer'; +import { clipboard, crashReporter, shell } from 'electron/common'; // In renderer process (web page). -// https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md -console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" +// https://github.com/electron/electron/blob/main/docs/api/ipc-renderer.md + +(async () => { + console.log(await ipcRenderer.invoke('ping-pong')); // prints "pong" +})(); + +console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong" + +ipcRenderer.on('test', () => {}); +ipcRenderer.off('test', () => {}); +ipcRenderer.once('test', () => {}); +ipcRenderer.addListener('test', () => {}); +ipcRenderer.removeListener('test', () => {}); +ipcRenderer.removeAllListeners('test'); ipcRenderer.on('asynchronous-reply', (event, arg: any) => { - console.log(arg) // prints "pong" - event.sender.send('another-message', 'Hello World!') -}) + console.log(arg); // prints "pong" + event.sender.send('another-message', 'Hello World!'); +}); + +ipcRenderer.send('asynchronous-message', 'ping'); -ipcRenderer.send('asynchronous-message', 'ping') +// @ts-expect-error Removed API +ipcRenderer.sendTo(1, 'test', 'Hello World!'); // web-frame -// https://github.com/electron/electron/blob/master/docs/api/web-frame.md +// https://github.com/electron/electron/blob/main/docs/api/web-frame.md -webFrame.setZoomFactor(2) -console.log(webFrame.getZoomFactor()) +webFrame.setZoomFactor(2); +console.log(webFrame.getZoomFactor()); -webFrame.setZoomLevel(200) -console.log(webFrame.getZoomLevel()) +webFrame.setZoomLevel(200); +console.log(webFrame.getZoomLevel()); -webFrame.setVisualZoomLevelLimits(50, 200) +webFrame.setVisualZoomLevelLimits(50, 200); webFrame.setSpellCheckProvider('en-US', { spellCheck (words, callback) { setTimeout(() => { - const spellchecker = require('spellchecker') - const misspelled = words.filter(x => spellchecker.isMisspelled(x)) - callback(misspelled) - }, 0) + const spellchecker = require('spellchecker'); + const misspelled = words.filter(x => spellchecker.isMisspelled(x)); + callback(misspelled); + }, 0); } -}) +}); -webFrame.insertText('text') +webFrame.insertText('text'); -webFrame.executeJavaScript('return true;').then((v: boolean) => console.log(v)) -webFrame.executeJavaScript('return true;', true).then((v: boolean) => console.log(v)) -webFrame.executeJavaScript('return true;', true) -webFrame.executeJavaScript('return true;', true).then((result: boolean) => console.log(result)) +webFrame.executeJavaScript('return true;').then((v: boolean) => console.log(v)); +webFrame.executeJavaScript('return true;', true).then((v: boolean) => console.log(v)); +webFrame.executeJavaScript('return true;', true); +webFrame.executeJavaScript('return true;', true).then((result: boolean) => console.log(result)); -console.log(webFrame.getResourceUsage()) -webFrame.clearCache() +console.log(webFrame.getResourceUsage()); +webFrame.clearCache(); // clipboard -// https://github.com/electron/electron/blob/master/docs/api/clipboard.md +// https://github.com/electron/electron/blob/main/docs/api/clipboard.md -clipboard.writeText('Example String') -clipboard.writeText('Example String', 'selection') -console.log(clipboard.readText('selection')) -console.log(clipboard.availableFormats()) -clipboard.clear() +clipboard.writeText('Example String'); +clipboard.writeText('Example String', 'selection'); +console.log(clipboard.readText('selection')); +console.log(clipboard.availableFormats()); +clipboard.clear(); clipboard.write({ html: '', text: 'Hello World!', bookmark: 'Bookmark name', image: clipboard.readImage() -}) +}); // crash-reporter -// https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md +// https://github.com/electron/electron/blob/main/docs/api/crash-reporter.md crashReporter.start({ productName: 'YourName', companyName: 'YourCompany', submitURL: 'https://your-domain.com/url-to-submit', uploadToServer: true -}) +}); // desktopCapturer -// https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md +// https://github.com/electron/electron/blob/main/docs/api/desktop-capturer.md -desktopCapturer.getSources({ types: ['window', 'screen'] }).then(sources => { - for (let i = 0; i < sources.length; ++i) { - if (sources[i].name == 'Electron') { +getSources({ types: ['window', 'screen'] }).then(sources => { + for (const source of sources) { + if (source.name === 'Electron') { (navigator as any).webkitGetUserMedia({ audio: false, video: { mandatory: { chromeMediaSource: 'desktop', - chromeMediaSourceId: sources[i].id, + chromeMediaSourceId: source.id, minWidth: 1280, maxWidth: 1280, minHeight: 720, maxHeight: 720 } } - }, gotStream, getUserMediaError) - return + }, gotStream, getUserMediaError); + return; } } -}) +}); -function gotStream (stream: any) { - (document.querySelector('video') as HTMLVideoElement).src = URL.createObjectURL(stream) +function getSources (options: Electron.SourcesOptions) { + return ipcRenderer.invoke('get-sources', options) as Promise; } -function getUserMediaError (error: Error) { - console.log('getUserMediaError', error) -} - -// File object -// https://github.com/electron/electron/blob/master/docs/api/file-object.md - -/* -
- Drag your file here -
-*/ - -const holder = document.getElementById('holder') - -holder.ondragover = function () { - return false -} - -holder.ondragleave = holder.ondragend = function () { - return false +function gotStream (stream: any) { + (document.querySelector('video') as HTMLVideoElement).src = URL.createObjectURL(stream); } -holder.ondrop = function (e) { - e.preventDefault() - const file = e.dataTransfer.files[0] - console.log('File you dragged here is', file.path) - return false +function getUserMediaError (error: Error) { + console.log('getUserMediaError', error); } // nativeImage -// https://github.com/electron/electron/blob/master/docs/api/native-image.md +// https://github.com/electron/electron/blob/main/docs/api/native-image.md -const image = clipboard.readImage() +const image = clipboard.readImage(); +console.log(image.getSize()); -// https://github.com/electron/electron/blob/master/docs/api/process.md +// https://github.com/electron/electron/blob/main/docs/api/process.md // preload.js -const _setImmediate = setImmediate -const _clearImmediate = clearImmediate +const _setImmediate = setImmediate; +const _clearImmediate = clearImmediate; process.once('loaded', function () { - global.setImmediate = _setImmediate - global.clearImmediate = _clearImmediate -}) + global.setImmediate = _setImmediate; + global.clearImmediate = _clearImmediate; +}); // shell -// https://github.com/electron/electron/blob/master/docs/api/shell.md +// https://github.com/electron/electron/blob/main/docs/api/shell.md -shell.openExternal('https://github.com').then(() => {}) +shell.openExternal('https://github.com').then(() => {}); // -// https://github.com/electron/electron/blob/master/docs/api/web-view-tag.md +// https://github.com/electron/electron/blob/main/docs/api/webview-tag.md -const webview = document.createElement('webview') -webview.loadURL('https://github.com') +const webview = document.createElement('webview'); +webview.loadURL('https://github.com'); webview.addEventListener('console-message', function (e) { - console.log('Guest page logged a message:', e.message) -}) + console.log('Guest page logged a message:', e.message); +}); webview.addEventListener('found-in-page', function (e) { if (e.result.finalUpdate) { - webview.stopFindInPage('keepSelection') + webview.stopFindInPage('keepSelection'); } -}) +}); -const requestId = webview.findInPage('test') +const requestId = webview.findInPage('test'); +console.log(requestId); webview.addEventListener('close', function () { - webview.src = 'about:blank' -}) + webview.src = 'about:blank'; +}); // In embedder page. webview.addEventListener('ipc-message', function (event) { - console.log(event.channel) // Prints "pong" -}) -webview.send('ping') -webview.capturePage().then(image => { console.log(image) }) - -{ - const opened: boolean = webview.isDevToolsOpened() - const focused: boolean = webview.isDevToolsFocused() -} + console.log(event.channel); // Prints "pong" +}); +webview.send('ping'); +webview.capturePage().then(image => { console.log(image); }); + +const opened = webview.isDevToolsOpened(); +console.log('isDevToolsOpened', opened); + +const focused = webview.isDevToolsFocused(); +console.log('isDevToolsFocused', focused); // In guest page. ipcRenderer.on('ping', function () { - ipcRenderer.sendToHost('pong') -}) + ipcRenderer.sendToHost('pong'); +}); diff --git a/spec/ts-smoke/runner.js b/spec/ts-smoke/runner.js index 32b6a1c02e880..9099e42866d3d 100644 --- a/spec/ts-smoke/runner.js +++ b/spec/ts-smoke/runner.js @@ -1,18 +1,18 @@ -const path = require('path') -const childProcess = require('child_process') +const childProcess = require('node:child_process'); +const path = require('node:path'); const typeCheck = () => { - const tscExec = path.resolve(require.resolve('typescript'), '../../bin/tsc') + const tscExec = path.resolve(require.resolve('typescript'), '../../bin/tsc'); const tscChild = childProcess.spawn(process.execPath, [tscExec, '--project', './ts-smoke/tsconfig.json'], { cwd: path.resolve(__dirname, '../') - }) - tscChild.stdout.on('data', d => console.log(d.toString())) - tscChild.stderr.on('data', d => console.error(d.toString())) + }); + tscChild.stdout.on('data', d => console.log(d.toString())); + tscChild.stderr.on('data', d => console.error(d.toString())); tscChild.on('exit', (tscStatus) => { if (tscStatus !== 0) { - process.exit(tscStatus) + process.exit(tscStatus); } - }) -} + }); +}; -typeCheck() +typeCheck(); diff --git a/spec/types-spec.ts b/spec/types-spec.ts new file mode 100644 index 0000000000000..a635b64da6971 --- /dev/null +++ b/spec/types-spec.ts @@ -0,0 +1,10 @@ +import { expect } from 'chai'; + +describe('bundled @types/node', () => { + it('should match the major version of bundled node', () => { + expect(require('../npm/package.json').dependencies).to.have.property('@types/node'); + const range = require('../npm/package.json').dependencies['@types/node']; + expect(range).to.match(/^\^.+/, 'should allow any type dep in a major range'); + expect(range.slice(1).split('.')[0]).to.equal(process.versions.node.split('.')[0]); + }); +}); diff --git a/spec/version-bump-spec.ts b/spec/version-bump-spec.ts new file mode 100644 index 0000000000000..e84d4a82ac534 --- /dev/null +++ b/spec/version-bump-spec.ts @@ -0,0 +1,213 @@ +import { expect } from 'chai'; +import { GitProcess, IGitExecutionOptions, IGitResult } from 'dugite'; +import * as sinon from 'sinon'; + +import { ifdescribe } from './lib/spec-helpers'; +import { nextVersion } from '../script/release/version-bumper'; + +class GitFake { + branches: { + [key: string]: string[], + }; + + constructor () { + this.branches = {}; + } + + setBranch (channel: string): void { + this.branches[channel] = []; + } + + setVersion (channel: string, latestTag: string): void { + const tags = [latestTag]; + if (channel === 'alpha') { + const versionStrs = latestTag.split(`${channel}.`); + const latest = parseInt(versionStrs[1]); + + for (let i = latest; i >= 1; i--) { + tags.push(`${versionStrs[0]}${channel}.${latest - i}`); + } + } + + this.branches[channel] = tags; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + exec (args: string[], path: string, options?: IGitExecutionOptions | undefined): Promise { + let stdout = ''; + const stderr = ''; + const exitCode = 0; + + // handle for promoting from current master HEAD + let branch = 'stable'; + const v = (args[2] === 'HEAD') ? 'stable' : args[3]; + if (v.includes('nightly')) branch = 'nightly'; + if (v.includes('alpha')) branch = 'alpha'; + if (v.includes('beta')) branch = 'beta'; + + if (!this.branches[branch]) this.setBranch(branch); + + stdout = this.branches[branch].join('\n'); + return Promise.resolve({ exitCode, stdout, stderr }); + } +} + +describe('version-bumper', () => { + ifdescribe(!(process.platform === 'linux' && process.arch.indexOf('arm') === 0) && process.platform !== 'darwin')('nextVersion', () => { + describe('bump versions', () => { + const nightlyPattern = /[0-9.]*(-nightly.(\d{4})(\d{2})(\d{2}))$/g; + const betaPattern = /[0-9.]*(-beta[0-9.]*)/g; + + it('bumps to nightly from stable', async () => { + const version = 'v2.0.0'; + const next = await nextVersion('nightly', version); + const matches = next.match(nightlyPattern); + expect(matches).to.have.lengthOf(1); + }); + + it('bumps to nightly from beta', async () => { + const version = 'v2.0.0-beta.1'; + const next = await nextVersion('nightly', version); + const matches = next.match(nightlyPattern); + expect(matches).to.have.lengthOf(1); + }); + + it('bumps to nightly from nightly', async () => { + const version = 'v2.0.0-nightly.19950901'; + const next = await nextVersion('nightly', version); + const matches = next.match(nightlyPattern); + expect(matches).to.have.lengthOf(1); + }); + + it('bumps to a nightly version above our switch from N-0-x to N-x-y branch names', async () => { + const version = 'v2.0.0-nightly.19950901'; + const next = await nextVersion('nightly', version); + // If it starts with v8 then we didn't bump above the 8-x-y branch + expect(next.startsWith('v8')).to.equal(false); + }); + + it('throws error when bumping to beta from stable', () => { + const version = 'v2.0.0'; + return expect( + nextVersion('beta', version) + ).to.be.rejectedWith('Cannot bump to beta from stable.'); + }); + + it('bumps to beta from nightly', async () => { + const version = 'v2.0.0-nightly.19950901'; + const next = await nextVersion('beta', version); + const matches = next.match(betaPattern); + expect(matches).to.have.lengthOf(1); + }); + + it('bumps to beta from beta', async () => { + const version = 'v2.0.0-beta.8'; + const next = await nextVersion('beta', version); + expect(next).to.equal('2.0.0-beta.9'); + }); + + it('bumps to beta from beta if the previous beta is at least beta.10', async () => { + const version = 'v6.0.0-beta.15'; + const next = await nextVersion('beta', version); + expect(next).to.equal('6.0.0-beta.16'); + }); + + it('bumps to stable from beta', async () => { + const version = 'v2.0.0-beta.1'; + const next = await nextVersion('stable', version); + expect(next).to.equal('2.0.0'); + }); + + it('bumps to stable from stable', async () => { + const version = 'v2.0.0'; + const next = await nextVersion('stable', version); + expect(next).to.equal('2.0.1'); + }); + + it('bumps to minor from stable', async () => { + const version = 'v2.0.0'; + const next = await nextVersion('minor', version); + expect(next).to.equal('2.1.0'); + }); + + it('bumps to stable from nightly', async () => { + const version = 'v2.0.0-nightly.19950901'; + const next = await nextVersion('stable', version); + expect(next).to.equal('2.0.0'); + }); + + it('throws on an invalid version', () => { + const version = 'vI.AM.INVALID'; + return expect( + nextVersion('beta', version) + ).to.be.rejectedWith(`Invalid current version: ${version}`); + }); + + it('throws on an invalid bump type', () => { + const version = 'v2.0.0'; + return expect( + // @ts-expect-error 'WRONG' is not a valid bump type + nextVersion('WRONG', version) + ).to.be.rejectedWith('Invalid bump type.'); + }); + }); + }); + + // If we don't plan on continuing to support an alpha channel past Electron 15, + // these tests will be removed. Otherwise, integrate into the bump versions tests + describe('bump versions - alpha channel', () => { + const alphaPattern = /[0-9.]*(-alpha[0-9.]*)/g; + const betaPattern = /[0-9.]*(-beta[0-9.]*)/g; + + const sandbox = sinon.createSandbox(); + const gitFake = new GitFake(); + + beforeEach(() => { + const wrapper = (args: string[], path: string, options?: IGitExecutionOptions | undefined) => gitFake.exec(args, path, options); + sandbox.replace(GitProcess, 'exec', wrapper); + }); + + afterEach(() => { + gitFake.branches = {}; + sandbox.restore(); + }); + + it('bumps to alpha from nightly', async () => { + const version = 'v2.0.0-nightly.19950901'; + gitFake.setVersion('nightly', version); + const next = await nextVersion('alpha', version); + const matches = next.match(alphaPattern); + expect(matches).to.have.lengthOf(1); + }); + + it('throws error when bumping to alpha from stable', () => { + const version = 'v2.0.0'; + return expect( + nextVersion('alpha', version) + ).to.be.rejectedWith('Cannot bump to alpha from stable.'); + }); + + it('bumps to alpha from alpha', async () => { + const version = 'v2.0.0-alpha.8'; + gitFake.setVersion('alpha', version); + const next = await nextVersion('alpha', version); + expect(next).to.equal('2.0.0-alpha.9'); + }); + + it('bumps to alpha from alpha if the previous alpha is at least alpha.10', async () => { + const version = 'v6.0.0-alpha.15'; + gitFake.setVersion('alpha', version); + const next = await nextVersion('alpha', version); + expect(next).to.equal('6.0.0-alpha.16'); + }); + + it('bumps to beta from alpha', async () => { + const version = 'v2.0.0-alpha.8'; + gitFake.setVersion('alpha', version); + const next = await nextVersion('beta', version); + const matches = next.match(betaPattern); + expect(matches).to.have.lengthOf(1); + expect(next).to.equal('2.0.0-beta.1'); + }); + }); +}); diff --git a/spec/visibility-state-spec.ts b/spec/visibility-state-spec.ts new file mode 100644 index 0000000000000..23c47b484a306 --- /dev/null +++ b/spec/visibility-state-spec.ts @@ -0,0 +1,196 @@ +import { BaseWindow, BrowserWindow, BrowserWindowConstructorOptions, webContents, WebContents, WebContentsView } from 'electron/main'; + +import { expect } from 'chai'; + +import * as cp from 'node:child_process'; +import { once } from 'node:events'; +import * as path from 'node:path'; + +import { ifdescribe, waitUntil } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +// visibilityState specs pass on linux with a real window manager but on CI +// the environment does not let these specs pass +ifdescribe(process.platform !== 'linux')('document.visibilityState', () => { + let w: BaseWindow & {webContents: WebContents}; + + before(() => { + for (const checkWin of BaseWindow.getAllWindows()) { + console.log('WINDOW EXISTS BEFORE TEST STARTED:', checkWin.title, checkWin.id); + } + }); + + afterEach(async () => { + await closeAllWindows(); + w = null as unknown as BrowserWindow; + const existingWCS = webContents.getAllWebContents(); + existingWCS.forEach((contents) => contents.close()); + }); + + const load = () => w.webContents.loadFile(path.resolve(__dirname, 'fixtures', 'chromium', 'visibilitystate.html')); + + async function haveVisibilityState (state: string) { + const docVisState = await w.webContents.executeJavaScript('document.visibilityState'); + return docVisState === state; + } + + const itWithOptions = (name: string, options: BrowserWindowConstructorOptions, fn: Mocha.Func) => { + it(name, async function (...args) { + w = new BrowserWindow({ + ...options, + paintWhenInitiallyHidden: false, + webPreferences: { + ...(options.webPreferences || {}), + nodeIntegration: true, + contextIsolation: false + } + }); + if (options.show && process.platform === 'darwin') { + await once(w, 'show'); + } + await Promise.resolve(fn.apply(this, args)); + }); + + it(name + ' with BaseWindow', async function (...args) { + const baseWindow = new BaseWindow({ + ...options + }); + const wcv = new WebContentsView({ webPreferences: { ...(options.webPreferences ?? {}), nodeIntegration: true, contextIsolation: false } }); + baseWindow.contentView = wcv; + w = Object.assign(baseWindow, { webContents: wcv.webContents }); + if (options.show && process.platform === 'darwin') { + await once(w, 'show'); + } + await Promise.resolve(fn.apply(this, args)); + }); + }; + + itWithOptions('should be visible when the window is initially shown by default', {}, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be visible when the window is initially shown', { + show: true + }, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be hidden when the window is initially hidden', { + show: false + }, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be visible when the window is initially hidden but shown before the page is loaded', { + show: false + }, async () => { + w.show(); + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be hidden when the window is initially shown but hidden before the page is loaded', { + show: true + }, async () => { + w.hide(); + load(); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be toggle between visible and hidden as the window is hidden and shown', {}, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + w.hide(); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + w.show(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should become hidden when a window is minimized', {}, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + w.minimize(); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should become visible when a window is restored', {}, async () => { + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + w.minimize(); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + w.restore(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + ifdescribe(process.platform === 'darwin')('on platforms that support occlusion detection', () => { + let child: cp.ChildProcess; + + const makeOtherWindow = (opts: { x: number; y: number; width: number; height: number; }) => { + child = cp.spawn(process.execPath, [path.resolve(__dirname, 'fixtures', 'chromium', 'other-window.js'), `${opts.x}`, `${opts.y}`, `${opts.width}`, `${opts.height}`]); + return new Promise(resolve => { + child.stdout!.on('data', (chunk) => { + if (chunk.toString().includes('__ready__')) resolve(); + }); + }); + }; + + afterEach(() => { + if (child && !child.killed) { + child.kill('SIGTERM'); + } + }); + + itWithOptions('should be visible when two windows are on screen', { + x: 0, + y: 0, + width: 200, + height: 200 + }, async () => { + await makeOtherWindow({ + x: 200, + y: 0, + width: 200, + height: 200 + }); + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be visible when two windows are on screen that overlap partially', { + x: 50, + y: 50, + width: 150, + height: 150 + }, async () => { + await makeOtherWindow({ + x: 100, + y: 0, + width: 200, + height: 200 + }); + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + }); + + itWithOptions('should be hidden when a second window completely occludes the current window', { + x: 50, + y: 50, + width: 50, + height: 50 + }, async function () { + this.timeout(240000); + load(); + await expect(waitUntil(async () => await haveVisibilityState('visible'))).to.eventually.be.fulfilled(); + makeOtherWindow({ + x: 0, + y: 0, + width: 300, + height: 300 + }); + await expect(waitUntil(async () => await haveVisibilityState('hidden'))).to.eventually.be.fulfilled(); + }); + }); +}); diff --git a/spec/webview-spec.js b/spec/webview-spec.js deleted file mode 100644 index 226b7c670db4d..0000000000000 --- a/spec/webview-spec.js +++ /dev/null @@ -1,431 +0,0 @@ -const { expect } = require('chai'); -const path = require('path'); -const http = require('http'); -const url = require('url'); -const { ipcRenderer } = require('electron'); -const { emittedOnce, waitForEvent } = require('./events-helpers'); -const { ifdescribe, ifit, delay } = require('./spec-helpers'); - -const features = process._linkedBinding('electron_common_features'); -const nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; - -/* Most of the APIs here don't use standard callbacks */ -/* eslint-disable standard/no-callback-literal */ - -describe(' tag', function () { - this.timeout(3 * 60 * 1000); - - const fixtures = path.join(__dirname, 'fixtures'); - let webview = null; - - const loadWebView = async (webview, attributes = {}) => { - for (const [name, value] of Object.entries(attributes)) { - webview.setAttribute(name, value); - } - document.body.appendChild(webview); - await waitForEvent(webview, 'did-finish-load'); - return webview; - }; - - const startLoadingWebViewAndWaitForMessage = async (webview, attributes = {}) => { - loadWebView(webview, attributes); // Don't wait for load to be finished. - const event = await waitForEvent(webview, 'console-message'); - return event.message; - }; - - beforeEach(() => { - webview = new WebView(); - }); - - afterEach(() => { - if (!document.body.contains(webview)) { - document.body.appendChild(webview); - } - webview.remove(); - }); - - // FIXME(zcbenz): Disabled because of moving to OOPIF webview. - xdescribe('setDevToolsWebContents() API', () => { - it('sets webContents of webview as devtools', async () => { - const webview2 = new WebView(); - loadWebView(webview2); - - // Setup an event handler for further usage. - const waitForDomReady = waitForEvent(webview2, 'dom-ready'); - - loadWebView(webview, { src: 'about:blank' }); - await waitForEvent(webview, 'dom-ready'); - webview.getWebContents().setDevToolsWebContents(webview2.getWebContents()); - webview.getWebContents().openDevTools(); - - await waitForDomReady; - - // Its WebContents should be a DevTools. - const devtools = webview2.getWebContents(); - expect(devtools.getURL().startsWith('devtools://devtools')).to.be.true(); - - const name = await devtools.executeJavaScript('InspectorFrontendHost.constructor.name'); - document.body.removeChild(webview2); - - expect(name).to.be.equal('InspectorFrontendHostImpl'); - }); - }); - - describe('.reload()', () => { - it('should emit beforeunload handler', async () => { - await loadWebView(webview, { - nodeintegration: 'on', - webpreferences: 'contextIsolation=no', - src: `file://${fixtures}/pages/beforeunload-false.html` - }); - - // Event handler has to be added before reload. - const waitForOnbeforeunload = waitForEvent(webview, 'ipc-message'); - - webview.reload(); - - const { channel } = await waitForOnbeforeunload; - expect(channel).to.equal('onbeforeunload'); - }); - }); - - describe('.goForward()', () => { - it('should work after a replaced history entry', (done) => { - let loadCount = 1; - const listener = (e) => { - if (loadCount === 1) { - expect(e.channel).to.equal('history'); - expect(e.args[0]).to.equal(1); - expect(webview.canGoBack()).to.be.false(); - expect(webview.canGoForward()).to.be.false(); - } else if (loadCount === 2) { - expect(e.channel).to.equal('history'); - expect(e.args[0]).to.equal(2); - expect(webview.canGoBack()).to.be.false(); - expect(webview.canGoForward()).to.be.true(); - webview.removeEventListener('ipc-message', listener); - } - }; - - const loadListener = () => { - try { - if (loadCount === 1) { - webview.src = `file://${fixtures}/pages/base-page.html`; - } else if (loadCount === 2) { - expect(webview.canGoBack()).to.be.true(); - expect(webview.canGoForward()).to.be.false(); - - webview.goBack(); - } else if (loadCount === 3) { - webview.goForward(); - } else if (loadCount === 4) { - expect(webview.canGoBack()).to.be.true(); - expect(webview.canGoForward()).to.be.false(); - - webview.removeEventListener('did-finish-load', loadListener); - done(); - } - - loadCount += 1; - } catch (e) { - done(e); - } - }; - - webview.addEventListener('ipc-message', listener); - webview.addEventListener('did-finish-load', loadListener); - - loadWebView(webview, { - nodeintegration: 'on', - src: `file://${fixtures}/pages/history-replace.html` - }); - }); - }); - - // FIXME: https://github.com/electron/electron/issues/19397 - xdescribe('.clearHistory()', () => { - it('should clear the navigation history', async () => { - const message = waitForEvent(webview, 'ipc-message'); - await loadWebView(webview, { - nodeintegration: 'on', - src: `file://${fixtures}/pages/history.html` - }); - const event = await message; - - expect(event.channel).to.equal('history'); - expect(event.args[0]).to.equal(2); - expect(webview.canGoBack()).to.be.true(); - - webview.clearHistory(); - expect(webview.canGoBack()).to.be.false(); - }); - }); - - describe('basic auth', () => { - const auth = require('basic-auth'); - - it('should authenticate with correct credentials', (done) => { - const message = 'Authenticated'; - const server = http.createServer((req, res) => { - const credentials = auth(req); - if (credentials.name === 'test' && credentials.pass === 'test') { - res.end(message); - } else { - res.end('failed'); - } - server.close(); - }); - server.listen(0, '127.0.0.1', () => { - const port = server.address().port; - webview.addEventListener('ipc-message', (e) => { - try { - expect(e.channel).to.equal(message); - done(); - } catch (e) { - done(e); - } - }); - loadWebView(webview, { - nodeintegration: 'on', - webpreferences: 'contextIsolation=no', - src: `file://${fixtures}/pages/basic-auth.html?port=${port}` - }); - }); - }); - }); - - describe('executeJavaScript', () => { - it('can return the result of the executed script', async () => { - await loadWebView(webview, { - src: 'about:blank' - }); - - const jsScript = "'4'+2"; - const expectedResult = '42'; - - const result = await webview.executeJavaScript(jsScript); - expect(result).to.equal(expectedResult); - }); - }); - - it('supports inserting CSS', async () => { - await loadWebView(webview, { src: `file://${fixtures}/pages/base-page.html` }); - await webview.insertCSS('body { background-repeat: round; }'); - const result = await webview.executeJavaScript('window.getComputedStyle(document.body).getPropertyValue("background-repeat")'); - expect(result).to.equal('round'); - }); - - it('supports removing inserted CSS', async () => { - await loadWebView(webview, { src: `file://${fixtures}/pages/base-page.html` }); - const key = await webview.insertCSS('body { background-repeat: round; }'); - await webview.removeInsertedCSS(key); - const result = await webview.executeJavaScript('window.getComputedStyle(document.body).getPropertyValue("background-repeat")'); - expect(result).to.equal('repeat'); - }); - - describe('sendInputEvent', () => { - it('can send keyboard event', async () => { - loadWebView(webview, { - nodeintegration: 'on', - webpreferences: 'contextIsolation=no', - src: `file://${fixtures}/pages/onkeyup.html` - }); - await waitForEvent(webview, 'dom-ready'); - - const waitForIpcMessage = waitForEvent(webview, 'ipc-message'); - webview.sendInputEvent({ - type: 'keyup', - keyCode: 'c', - modifiers: ['shift'] - }); - - const { channel, args } = await waitForIpcMessage; - expect(channel).to.equal('keyup'); - expect(args).to.deep.equal(['C', 'KeyC', 67, true, false]); - }); - - it('can send mouse event', async () => { - loadWebView(webview, { - nodeintegration: 'on', - webpreferences: 'contextIsolation=no', - src: `file://${fixtures}/pages/onmouseup.html` - }); - await waitForEvent(webview, 'dom-ready'); - - const waitForIpcMessage = waitForEvent(webview, 'ipc-message'); - webview.sendInputEvent({ - type: 'mouseup', - modifiers: ['ctrl'], - x: 10, - y: 20 - }); - - const { channel, args } = await waitForIpcMessage; - expect(channel).to.equal('mouseup'); - expect(args).to.deep.equal([10, 20, false, true]); - }); - }); - - describe('media-started-playing media-paused events', () => { - beforeEach(function () { - if (!document.createElement('audio').canPlayType('audio/wav')) { - this.skip(); - } - }); - - it('emits when audio starts and stops playing', async () => { - await loadWebView(webview, { src: `file://${fixtures}/pages/base-page.html` }); - - // With the new autoplay policy, audio elements must be unmuted - // see https://goo.gl/xX8pDD. - const source = ` - const audio = document.createElement("audio") - audio.src = "../assets/tone.wav" - document.body.appendChild(audio); - audio.play() - `; - webview.executeJavaScript(source, true); - await waitForEvent(webview, 'media-started-playing'); - - webview.executeJavaScript('document.querySelector("audio").pause()', true); - await waitForEvent(webview, 'media-paused'); - }); - }); - - describe('.getWebContentsId', () => { - it('can return the WebContents ID', async () => { - const src = 'about:blank'; - await loadWebView(webview, { src }); - - expect(webview.getWebContentsId()).to.be.a('number'); - }); - }); - - // TODO(nornagon): this seems to have become much less reliable as of - // https://github.com/electron/electron/pull/32419. Tracked at - // https://github.com/electron/electron/issues/32705. - describe.skip('.capturePage()', () => { - before(function () { - // TODO(miniak): figure out why this is failing on windows - if (process.platform === 'win32') { - this.skip(); - } - }); - - it('returns a Promise with a NativeImage', async () => { - const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; - await loadWebView(webview, { src }); - - const image = await webview.capturePage(); - const imgBuffer = image.toPNG(); - - // Check the 25th byte in the PNG. - // Values can be 0,2,3,4, or 6. We want 6, which is RGB + Alpha - expect(imgBuffer[25]).to.equal(6); - }); - }); - - ifdescribe(features.isPrintingEnabled())('.printToPDF()', () => { - it('rejects on incorrectly typed parameters', async () => { - const badTypes = { - landscape: [], - displayHeaderFooter: '123', - printBackground: 2, - scale: 'not-a-number', - pageSize: 'IAmAPageSize', - margins: 'terrible', - pageRanges: { oops: 'im-not-the-right-key' }, - headerTemplate: [1, 2, 3], - footerTemplate: [4, 5, 6], - preferCSSPageSize: 'no' - }; - - // These will hard crash in Chromium unless we type-check - for (const [key, value] of Object.entries(badTypes)) { - const param = { [key]: value }; - - const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; - await loadWebView(webview, { src }); - await expect(webview.printToPDF(param)).to.eventually.be.rejected(); - } - }); - - it('can print to PDF', async () => { - const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; - await loadWebView(webview, { src }); - - const data = await webview.printToPDF({}); - expect(data).to.be.an.instanceof(Uint8Array).that.is.not.empty(); - }); - }); - - describe('DOM events', () => { - let div; - - beforeEach(() => { - div = document.createElement('div'); - div.style.width = '100px'; - div.style.height = '10px'; - div.style.overflow = 'hidden'; - webview.style.height = '100%'; - webview.style.width = '100%'; - }); - - afterEach(() => { - if (div != null) div.remove(); - }); - - const generateSpecs = (description, sandbox) => { - describe(description, () => { - // TODO(nornagon): disabled during chromium roll 2019-06-11 due to a - // 'ResizeObserver loop limit exceeded' error on Windows - xit('emits resize events', async () => { - const firstResizeSignal = waitForEvent(webview, 'resize'); - const domReadySignal = waitForEvent(webview, 'dom-ready'); - - webview.src = `file://${fixtures}/pages/a.html`; - webview.webpreferences = `sandbox=${sandbox ? 'yes' : 'no'}`; - div.appendChild(webview); - document.body.appendChild(div); - - const firstResizeEvent = await firstResizeSignal; - expect(firstResizeEvent.target).to.equal(webview); - expect(firstResizeEvent.newWidth).to.equal(100); - expect(firstResizeEvent.newHeight).to.equal(10); - - await domReadySignal; - - const secondResizeSignal = waitForEvent(webview, 'resize'); - - const newWidth = 1234; - const newHeight = 789; - div.style.width = `${newWidth}px`; - div.style.height = `${newHeight}px`; - - const secondResizeEvent = await secondResizeSignal; - expect(secondResizeEvent.target).to.equal(webview); - expect(secondResizeEvent.newWidth).to.equal(newWidth); - expect(secondResizeEvent.newHeight).to.equal(newHeight); - }); - - it('emits focus event', async () => { - const domReadySignal = waitForEvent(webview, 'dom-ready'); - webview.src = `file://${fixtures}/pages/a.html`; - webview.webpreferences = `sandbox=${sandbox ? 'yes' : 'no'}`; - document.body.appendChild(webview); - - await domReadySignal; - - // If this test fails, check if webview.focus() still works. - const focusSignal = waitForEvent(webview, 'focus'); - webview.focus(); - - await focusSignal; - }); - }); - }; - - generateSpecs('without sandbox', false); - generateSpecs('with sandbox', true); - }); -}); diff --git a/spec/webview-spec.ts b/spec/webview-spec.ts new file mode 100644 index 0000000000000..dfc30937706e1 --- /dev/null +++ b/spec/webview-spec.ts @@ -0,0 +1,2210 @@ +import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main'; + +import * as auth from 'basic-auth'; +import { expect } from 'chai'; + +import { once } from 'node:events'; +import * as http from 'node:http'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; +import * as url from 'node:url'; + +import { emittedUntil } from './lib/events-helpers'; +import { HexColors, ScreenCapture, hasCapturableScreen } from './lib/screen-helpers'; +import { ifit, ifdescribe, defer, itremote, useRemoteContext, listen } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +declare let WebView: any; +const features = process._linkedBinding('electron_common_features'); + +async function loadWebView (w: WebContents, attributes: Record, opts?: {openDevTools?: boolean}): Promise { + const { openDevTools } = { + openDevTools: false, + ...opts + }; + await w.executeJavaScript(` + new Promise((resolve, reject) => { + const webview = new WebView() + webview.id = 'webview' + for (const [k, v] of Object.entries(${JSON.stringify(attributes)})) { + webview.setAttribute(k, v) + } + document.body.appendChild(webview) + webview.addEventListener('dom-ready', () => { + if (${openDevTools}) { + webview.openDevTools() + } + }) + webview.addEventListener('did-finish-load', () => { + resolve() + }) + }) + `); +} +async function loadWebViewAndWaitForEvent (w: WebContents, attributes: Record, eventName: string): Promise { + return await w.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.id = 'webview' + for (const [k, v] of Object.entries(${JSON.stringify(attributes)})) { + webview.setAttribute(k, v) + } + webview.addEventListener(${JSON.stringify(eventName)}, (e) => resolve({...e}), {once: true}) + document.body.appendChild(webview) + })`); +}; +async function loadWebViewAndWaitForMessage (w: WebContents, attributes: Record): Promise { + const { message } = await loadWebViewAndWaitForEvent(w, attributes, 'console-message'); + return message; +}; + +describe(' tag', function () { + const fixtures = path.join(__dirname, 'fixtures'); + const blankPageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'blank.html')).toString(); + + function hideChildWindows (e: any, wc: WebContents) { + wc.setWindowOpenHandler(() => ({ + action: 'allow', + overrideBrowserWindowOptions: { + show: false + } + })); + } + + before(() => { + app.on('web-contents-created', hideChildWindows); + }); + + after(() => { + app.off('web-contents-created', hideChildWindows); + }); + + describe('behavior', () => { + afterEach(closeAllWindows); + + it('works without script tag in page', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-no-script.html')); + await once(ipcMain, 'pong'); + }); + + it('works with sandbox', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + sandbox: true + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html')); + await once(ipcMain, 'pong'); + }); + + it('works with contextIsolation', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html')); + await once(ipcMain, 'pong'); + }); + + it('works with contextIsolation + sandbox', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true, + sandbox: true + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html')); + await once(ipcMain, 'pong'); + }); + + it('works with Trusted Types', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-trusted-types.html')); + await once(ipcMain, 'pong'); + }); + + it('is disabled by default', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + preload: path.join(fixtures, 'module', 'preload-webview.js'), + nodeIntegration: true + } + }); + + const webview = once(ipcMain, 'webview'); + w.loadFile(path.join(fixtures, 'pages', 'webview-no-script.html')); + const [, type] = await webview; + + expect(type).to.equal('undefined', 'WebView still exists'); + }); + }); + + // FIXME(deepak1556): Ch69 follow up. + xdescribe('document.visibilityState/hidden', () => { + afterEach(() => { + ipcMain.removeAllListeners('pong'); + }); + + afterEach(closeAllWindows); + + it('updates when the window is shown after the ready-to-show event', async () => { + const w = new BrowserWindow({ show: false }); + const readyToShowSignal = once(w, 'ready-to-show'); + const pongSignal1 = once(ipcMain, 'pong'); + w.loadFile(path.join(fixtures, 'pages', 'webview-visibilitychange.html')); + await pongSignal1; + const pongSignal2 = once(ipcMain, 'pong'); + await readyToShowSignal; + w.show(); + + const [, visibilityState, hidden] = await pongSignal2; + expect(visibilityState).to.equal('visible'); + expect(hidden).to.be.false(); + }); + + it('inherits the parent window visibility state and receives visibilitychange events', async () => { + const w = new BrowserWindow({ show: false }); + w.loadFile(path.join(fixtures, 'pages', 'webview-visibilitychange.html')); + const [, visibilityState, hidden] = await once(ipcMain, 'pong'); + expect(visibilityState).to.equal('hidden'); + expect(hidden).to.be.true(); + + // We have to start waiting for the event + // before we ask the webContents to resize. + const getResponse = once(ipcMain, 'pong'); + w.webContents.emit('-window-visibility-change', 'visible'); + + return getResponse.then(([, visibilityState, hidden]) => { + expect(visibilityState).to.equal('visible'); + expect(hidden).to.be.false(); + }); + }); + }); + + describe('did-attach-webview event', () => { + afterEach(closeAllWindows); + it('is emitted when a webview has been attached', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + const didAttachWebview = once(w.webContents, 'did-attach-webview') as Promise<[any, WebContents]>; + const webviewDomReady = once(ipcMain, 'webview-dom-ready'); + w.loadFile(path.join(fixtures, 'pages', 'webview-did-attach-event.html')); + + const [, webContents] = await didAttachWebview; + const [, id] = await webviewDomReady; + expect(webContents.id).to.equal(id); + }); + }); + + describe('did-attach event', () => { + afterEach(closeAllWindows); + it('is emitted when a webview has been attached', async () => { + const w = new BrowserWindow({ + webPreferences: { + webviewTag: true + } + }); + await w.loadURL('about:blank'); + const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'about:blank') + webview.addEventListener('did-attach', (e) => { + resolve('ok') + }) + document.body.appendChild(webview) + })`); + expect(message).to.equal('ok'); + }); + }); + + describe('did-change-theme-color event', () => { + afterEach(closeAllWindows); + it('emits when theme color changes', async () => { + const w = new BrowserWindow({ + webPreferences: { + webviewTag: true + } + }); + await w.loadURL('about:blank'); + const src = url.format({ + pathname: `${fixtures.replaceAll('\\', '/')}/pages/theme-color.html`, + protocol: 'file', + slashes: true + }); + const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', '${src}') + webview.addEventListener('did-change-theme-color', (e) => { + resolve('ok') + }) + document.body.appendChild(webview) + })`); + expect(message).to.equal('ok'); + }); + }); + + describe('devtools', () => { + afterEach(closeAllWindows); + // FIXME: This test is flaky on WOA, so skip it there. + ifit(process.platform !== 'win32' || process.arch !== 'arm64')('loads devtools extensions registered on the parent window', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + w.webContents.session.removeExtension('foo'); + + const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo'); + await w.webContents.session.loadExtension(extensionPath, { + allowFileAccess: true + }); + + w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'webview-devtools.html')); + loadWebView(w.webContents, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${path.join(__dirname, 'fixtures', 'blank.html')}` + }, { openDevTools: true }); + let childWebContentsId = 0; + app.once('web-contents-created', (e, webContents) => { + childWebContentsId = webContents.id; + webContents.on('devtools-opened', function () { + const showPanelIntervalId = setInterval(function () { + if (!webContents.isDestroyed() && webContents.devToolsWebContents) { + webContents.devToolsWebContents.executeJavaScript('(' + function () { + const { EUI } = (window as any); + const instance = EUI.InspectorView.InspectorView.instance(); + const tabs = instance.tabbedPane.tabs; + const lastPanelId: any = tabs[tabs.length - 1].id; + instance.showPanel(lastPanelId); + }.toString() + ')()'); + } else { + clearInterval(showPanelIntervalId); + } + }, 100); + }); + }); + + const [, { runtimeId, tabId }] = await once(ipcMain, 'answer'); + expect(runtimeId).to.match(/^[a-z]{32}$/); + expect(tabId).to.equal(childWebContentsId); + await w.webContents.executeJavaScript('webview.closeDevTools()'); + }); + }); + + describe('zoom behavior', () => { + const zoomScheme = standardScheme; + const webviewSession = session.fromPartition('webview-temp'); + + afterEach(closeAllWindows); + + before(() => { + const protocol = webviewSession.protocol; + protocol.registerStringProtocol(zoomScheme, (request, respond) => { + respond('hello'); + }); + }); + + after(() => { + const protocol = webviewSession.protocol; + protocol.unregisterProtocol(zoomScheme); + }); + + it('inherits the zoomFactor of the parent window', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + zoomFactor: 1.2, + contextIsolation: false + } + }); + const zoomEventPromise = once(ipcMain, 'webview-parent-zoom-level'); + w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-factor.html')); + + const [, zoomFactor, zoomLevel] = await zoomEventPromise; + expect(zoomFactor).to.equal(1.2); + expect(zoomLevel).to.equal(1); + }); + + it('maintains the zoom level for a given host in the same session after navigation', () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + + const zoomPromise = new Promise((resolve) => { + ipcMain.on('webview-zoom-persist-level', (_event, values) => { + resolve(values); + }); + }); + + w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-change-persist-host.html')); + + expect(zoomPromise).to.eventually.deep.equal({ + initialZoomLevel: 2, + switchZoomLevel: 3, + finalZoomLevel: 2 + }); + }); + + it('maintains zoom level on navigation', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + zoomFactor: 1.2, + contextIsolation: false + } + }); + const promise = new Promise((resolve) => { + ipcMain.on('webview-zoom-level', (event, zoomLevel, zoomFactor, newHost, final) => { + if (!newHost) { + expect(zoomFactor).to.equal(1.44); + expect(zoomLevel).to.equal(2.0); + } else { + expect(zoomFactor).to.equal(1.2); + expect(zoomLevel).to.equal(1); + } + + if (final) { + resolve(); + } + }); + }); + + w.loadFile(path.join(fixtures, 'pages', 'webview-custom-zoom-level.html')); + + await promise; + }); + + it('maintains zoom level when navigating within same page', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + zoomFactor: 1.2, + contextIsolation: false + } + }); + const promise = new Promise((resolve) => { + ipcMain.on('webview-zoom-in-page', (event, zoomLevel, zoomFactor, final) => { + expect(zoomFactor).to.equal(1.44); + expect(zoomLevel).to.equal(2.0); + + if (final) { + resolve(); + } + }); + }); + + w.loadFile(path.join(fixtures, 'pages', 'webview-in-page-navigate.html')); + + await promise; + }); + + it('inherits zoom level for the origin when available', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + zoomFactor: 1.2, + contextIsolation: false + } + }); + w.loadFile(path.join(fixtures, 'pages', 'webview-origin-zoom-level.html')); + + const [, zoomLevel] = await once(ipcMain, 'webview-origin-zoom-level'); + expect(zoomLevel).to.equal(2.0); + }); + + it('does not crash when navigating with zoom level inherited from parent', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + zoomFactor: 1.2, + session: webviewSession, + contextIsolation: false + } + }); + const attachPromise = once(w.webContents, 'did-attach-webview') as Promise<[any, WebContents]>; + const readyPromise = once(ipcMain, 'dom-ready'); + w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-inherited.html')); + const [, webview] = await attachPromise; + await readyPromise; + expect(webview.getZoomFactor()).to.equal(1.2); + await w.loadURL(`${zoomScheme}://host1`); + }); + + it('does not crash when changing zoom level after webview is destroyed', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + session: webviewSession, + contextIsolation: false + } + }); + const attachPromise = once(w.webContents, 'did-attach-webview') as Promise<[any, WebContents]>; + await w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-inherited.html')); + await attachPromise; + await w.webContents.executeJavaScript('view.remove()'); + w.webContents.setZoomLevel(0.5); + }); + }); + + describe('requestFullscreen from webview', () => { + afterEach(closeAllWindows); + async function loadWebViewWindow (): Promise<[BrowserWindow, WebContents]> { + const w = new BrowserWindow({ + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + + const attachPromise = once(w.webContents, 'did-attach-webview') as Promise<[any, WebContents]>; + const loadPromise = once(w.webContents, 'did-finish-load'); + const readyPromise = once(ipcMain, 'webview-ready'); + + w.loadFile(path.join(__dirname, 'fixtures', 'webview', 'fullscreen', 'main.html')); + + const [, webview] = await attachPromise; + await Promise.all([readyPromise, loadPromise]); + + return [w, webview]; + }; + + afterEach(async () => { + // The leaving animation is un-observable but can interfere with future tests + // Specifically this is async on macOS but can be on other platforms too + await setTimeout(1000); + + closeAllWindows(); + }); + + ifit(process.platform !== 'darwin')('should make parent frame element fullscreen too (non-macOS)', async () => { + const [w, webview] = await loadWebViewWindow(); + expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false(); + + const parentFullscreen = once(ipcMain, 'fullscreenchange'); + await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await parentFullscreen; + + expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true(); + + const close = once(w, 'closed'); + w.close(); + await close; + }); + + ifit(process.platform === 'darwin')('should make parent frame element fullscreen too (macOS)', async () => { + const [w, webview] = await loadWebViewWindow(); + expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false(); + + const parentFullscreen = once(ipcMain, 'fullscreenchange'); + const enterHTMLFS = once(w.webContents, 'enter-html-full-screen'); + const leaveHTMLFS = once(w.webContents, 'leave-html-full-screen'); + + await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true(); + + await webview.executeJavaScript('document.exitFullscreen()'); + await Promise.all([enterHTMLFS, leaveHTMLFS, parentFullscreen]); + + const close = once(w, 'closed'); + w.close(); + await close; + }); + + // FIXME(zcbenz): Fullscreen events do not work on Linux. + ifit(process.platform !== 'linux')('exiting fullscreen should unfullscreen window', async () => { + const [w, webview] = await loadWebViewWindow(); + const enterFullScreen = once(w, 'enter-full-screen'); + await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await enterFullScreen; + + const leaveFullScreen = once(w, 'leave-full-screen'); + await webview.executeJavaScript('document.exitFullscreen()', true); + await leaveFullScreen; + await setTimeout(); + expect(w.isFullScreen()).to.be.false(); + + const close = once(w, 'closed'); + w.close(); + await close; + }); + + it('pressing ESC should unfullscreen window', async () => { + const [w, webview] = await loadWebViewWindow(); + const enterFullScreen = once(w, 'enter-full-screen'); + await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await enterFullScreen; + + const leaveFullScreen = once(w, 'leave-full-screen'); + webview.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' }); + await leaveFullScreen; + await setTimeout(1000); + expect(w.isFullScreen()).to.be.false(); + + const close = once(w, 'closed'); + w.close(); + await close; + }); + + it('pressing ESC should emit the leave-html-full-screen event', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + + const didAttachWebview = once(w.webContents, 'did-attach-webview') as Promise<[any, WebContents]>; + w.loadFile(path.join(fixtures, 'pages', 'webview-did-attach-event.html')); + + const [, webContents] = await didAttachWebview; + + const enterFSWindow = once(w, 'enter-html-full-screen'); + const enterFSWebview = once(webContents, 'enter-html-full-screen'); + await webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await enterFSWindow; + await enterFSWebview; + + const leaveFSWindow = once(w, 'leave-html-full-screen'); + const leaveFSWebview = once(webContents, 'leave-html-full-screen'); + webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' }); + await leaveFSWebview; + await leaveFSWindow; + + const close = once(w, 'closed'); + w.close(); + await close; + }); + + it('should support user gesture', async () => { + const [w, webview] = await loadWebViewWindow(); + + const waitForEnterHtmlFullScreen = once(webview, 'enter-html-full-screen'); + + const jsScript = "document.querySelector('video').webkitRequestFullscreen()"; + webview.executeJavaScript(jsScript, true); + + await waitForEnterHtmlFullScreen; + + const close = once(w, 'closed'); + w.close(); + await close; + }); + }); + + describe('child windows', () => { + let w: BrowserWindow; + beforeEach(async () => { + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true, contextIsolation: false } }); + await w.loadURL('about:blank'); + }); + afterEach(closeAllWindows); + + it('opens window of about:blank with cross-scripting enabled', async () => { + // Don't wait for loading to finish. + loadWebView(w.webContents, { + allowpopups: 'on', + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}` + }); + + const [, content] = await once(ipcMain, 'answer'); + expect(content).to.equal('Hello'); + }); + + it('opens window of same domain with cross-scripting enabled', async () => { + // Don't wait for loading to finish. + loadWebView(w.webContents, { + allowpopups: 'on', + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}` + }); + + const [, content] = await once(ipcMain, 'answer'); + expect(content).to.equal('Hello'); + }); + + it('returns null from window.open when allowpopups is not set', async () => { + // Don't wait for loading to finish. + loadWebView(w.webContents, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}` + }); + + const [, { windowOpenReturnedNull }] = await once(ipcMain, 'answer'); + expect(windowOpenReturnedNull).to.be.true(); + }); + + it('blocks accessing cross-origin frames', async () => { + // Don't wait for loading to finish. + loadWebView(w.webContents, { + allowpopups: 'on', + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}` + }); + + const [, content] = await once(ipcMain, 'answer'); + const expectedContent = + /Failed to read a named property 'toString' from 'Location': Blocked a frame with origin "(.*?)" from accessing a cross-origin frame./; + + expect(content).to.match(expectedContent); + }); + + it('emits a browser-window-created event', async () => { + // Don't wait for loading to finish. + loadWebView(w.webContents, { + allowpopups: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/window-open.html` + }); + + await once(app, 'browser-window-created'); + }); + + it('emits a web-contents-created event', async () => { + const webContentsCreated = emittedUntil(app, 'web-contents-created', + (event: Electron.Event, contents: Electron.WebContents) => contents.getType() === 'window'); + + loadWebView(w.webContents, { + allowpopups: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/window-open.html` + }); + + await webContentsCreated; + }); + + it('does not crash when creating window with noopener', async () => { + loadWebView(w.webContents, { + allowpopups: 'on', + src: `file://${path.join(fixtures, 'api', 'native-window-open-noopener.html')}` + }); + await once(app, 'browser-window-created'); + }); + }); + + describe('webpreferences attribute', () => { + let w: BrowserWindow; + beforeEach(async () => { + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true } }); + await w.loadURL('about:blank'); + }); + afterEach(closeAllWindows); + + it('can enable context isolation', async () => { + loadWebView(w.webContents, { + allowpopups: 'yes', + preload: `file://${fixtures}/api/isolated-preload.js`, + src: `file://${fixtures}/api/isolated.html`, + webpreferences: 'contextIsolation=yes' + }); + + const [, data] = await once(ipcMain, 'isolated-world'); + expect(data).to.deep.equal({ + preloadContext: { + preloadProperty: 'number', + pageProperty: 'undefined', + typeofRequire: 'function', + typeofProcess: 'object', + typeofArrayPush: 'function', + typeofFunctionApply: 'function', + typeofPreloadExecuteJavaScriptProperty: 'undefined' + }, + pageContext: { + preloadProperty: 'undefined', + pageProperty: 'string', + typeofRequire: 'undefined', + typeofProcess: 'undefined', + typeofArrayPush: 'number', + typeofFunctionApply: 'boolean', + typeofPreloadExecuteJavaScriptProperty: 'number', + typeofOpenedWindow: 'object' + } + }); + }); + }); + + describe('webpreferences attribute', () => { + const WINDOW_BACKGROUND_COLOR = '#55ccbb'; + + let w: BrowserWindow; + before(async () => { + w = new BrowserWindow({ + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + await w.loadURL(`file://${fixtures}/pages/flex-webview.html`); + w.setBackgroundColor(WINDOW_BACKGROUND_COLOR); + }); + afterEach(async () => { + await w.webContents.executeJavaScript(`{ + for (const el of document.querySelectorAll('webview')) el.remove(); + }`); + }); + after(() => w.close()); + + ifit(hasCapturableScreen())('is transparent by default', async () => { + await loadWebView(w.webContents, { + src: 'data:text/html,foo' + }); + + const screenCapture = new ScreenCapture(); + await screenCapture.expectColorAtCenterMatches(WINDOW_BACKGROUND_COLOR); + }); + + ifit(hasCapturableScreen())('remains transparent when set', async () => { + await loadWebView(w.webContents, { + src: 'data:text/html,foo', + webpreferences: 'transparent=yes' + }); + + const screenCapture = new ScreenCapture(); + await screenCapture.expectColorAtCenterMatches(WINDOW_BACKGROUND_COLOR); + }); + + ifit(hasCapturableScreen())('can disable transparency', async () => { + await loadWebView(w.webContents, { + src: 'data:text/html,foo', + webpreferences: 'transparent=no' + }); + + const screenCapture = new ScreenCapture(); + await screenCapture.expectColorAtCenterMatches(HexColors.WHITE); + }); + }); + + describe('permission request handlers', () => { + let w: BrowserWindow; + beforeEach(async () => { + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true, contextIsolation: false } }); + await w.loadURL('about:blank'); + }); + afterEach(closeAllWindows); + + const partition = 'permissionTest'; + + function setUpRequestHandler (webContentsId: number, requestedPermission: string) { + return new Promise((resolve, reject) => { + session.fromPartition(partition).setPermissionRequestHandler(function (webContents, permission, allow) { + if (webContents.id === webContentsId) { + // All midi permission requests are blocked or allowed as midiSysex permissions + // since https://chromium-review.googlesource.com/c/chromium/src/+/5154368 + if (permission === 'midiSysex') { + const allowed = requestedPermission === 'midi' || requestedPermission === 'midiSysex'; + return allow(!allowed); + } + + try { + expect(permission).to.equal(requestedPermission); + } catch (e) { + return reject(e); + } + allow(false); + resolve(); + } + }); + }); + } + afterEach(() => { + session.fromPartition(partition).setPermissionRequestHandler(null); + }); + + // This is disabled because CI machines don't have cameras or microphones, + // so Chrome responds with "NotFoundError" instead of + // "PermissionDeniedError". It should be re-enabled if we find a way to mock + // the presence of a microphone & camera. + xit('emits when using navigator.getUserMedia api', async () => { + const errorFromRenderer = once(ipcMain, 'message'); + loadWebView(w.webContents, { + src: `file://${fixtures}/pages/permissions/media.html`, + partition, + nodeintegration: 'on' + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + setUpRequestHandler(webViewContents.id, 'media'); + const [, errorName] = await errorFromRenderer; + expect(errorName).to.equal('PermissionDeniedError'); + }); + + it('emits when using navigator.geolocation api', async () => { + const errorFromRenderer = once(ipcMain, 'message'); + loadWebView(w.webContents, { + src: `file://${fixtures}/pages/permissions/geolocation.html`, + partition, + nodeintegration: 'on', + webpreferences: 'contextIsolation=no' + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + setUpRequestHandler(webViewContents.id, 'geolocation'); + const [, error] = await errorFromRenderer; + expect(error).to.equal('User denied Geolocation'); + }); + + it('emits when using navigator.requestMIDIAccess without sysex api', async () => { + const errorFromRenderer = once(ipcMain, 'message'); + loadWebView(w.webContents, { + src: `file://${fixtures}/pages/permissions/midi.html`, + partition, + nodeintegration: 'on', + webpreferences: 'contextIsolation=no' + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + setUpRequestHandler(webViewContents.id, 'midi'); + const [, error] = await errorFromRenderer; + expect(error).to.equal('NotAllowedError'); + }); + + it('emits when using navigator.requestMIDIAccess with sysex api', async () => { + const errorFromRenderer = once(ipcMain, 'message'); + loadWebView(w.webContents, { + src: `file://${fixtures}/pages/permissions/midi-sysex.html`, + partition, + nodeintegration: 'on', + webpreferences: 'contextIsolation=no' + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + setUpRequestHandler(webViewContents.id, 'midiSysex'); + const [, error] = await errorFromRenderer; + expect(error).to.equal('NotAllowedError'); + }); + + it('emits when accessing external protocol', async () => { + loadWebView(w.webContents, { + src: 'magnet:test', + partition + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + await setUpRequestHandler(webViewContents.id, 'openExternal'); + }); + + it('emits when using Notification.requestPermission', async () => { + const errorFromRenderer = once(ipcMain, 'message'); + loadWebView(w.webContents, { + src: `file://${fixtures}/pages/permissions/notification.html`, + partition, + nodeintegration: 'on', + webpreferences: 'contextIsolation=no' + }); + const [, webViewContents] = await once(app, 'web-contents-created') as [any, WebContents]; + + await setUpRequestHandler(webViewContents.id, 'notifications'); + + const [, error] = await errorFromRenderer; + expect(error).to.equal('denied'); + }); + }); + + describe('DOM events', () => { + afterEach(closeAllWindows); + it('receives extra properties on DOM events when contextIsolation is enabled', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + await w.loadURL('about:blank'); + const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'data:text/html,') + webview.addEventListener('console-message', (e) => { + resolve(e.message) + }) + document.body.appendChild(webview) + })`); + expect(message).to.equal('hi'); + }); + + it('emits focus event when contextIsolation is enabled', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + await w.loadURL('about:blank'); + await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'about:blank') + webview.addEventListener('dom-ready', () => { + webview.focus() + }) + webview.addEventListener('focus', () => { + resolve(); + }) + document.body.appendChild(webview) + })`); + }); + }); + + describe('attributes', () => { + let w: WebContents; + before(async () => { + const window = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + await window.loadURL(`file://${fixtures}/pages/blank.html`); + w = window.webContents; + }); + afterEach(async () => { + await w.executeJavaScript(`{ + for (const el of document.querySelectorAll('webview')) el.remove(); + }`); + }); + after(closeAllWindows); + + describe('src attribute', () => { + it('specifies the page to load', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/a.html` + }); + expect(message).to.equal('a'); + }); + + it('navigates to new page when changed', async () => { + await loadWebView(w, { + src: `file://${fixtures}/pages/a.html` + }); + + const { message } = await w.executeJavaScript(`new Promise(resolve => { + webview.addEventListener('console-message', e => resolve({message: e.message})) + webview.src = ${JSON.stringify(`file://${fixtures}/pages/b.html`)} + })`); + + expect(message).to.equal('b'); + }); + + it('resolves relative URLs', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + src: './e.html' + }); + expect(message).to.equal('Window script is loaded before preload script'); + }); + + it('ignores empty values', async () => { + loadWebView(w, {}); + + for (const emptyValue of ['""', 'null', 'undefined']) { + const src = await w.executeJavaScript(`webview.src = ${emptyValue}, webview.src`); + expect(src).to.equal(''); + } + }); + + it('does not wait until loadURL is resolved', async () => { + await loadWebView(w, { src: 'about:blank' }); + + const delay = await w.executeJavaScript(`new Promise(resolve => { + const before = Date.now(); + webview.src = 'file://${fixtures}/pages/blank.html'; + const now = Date.now(); + resolve(now - before); + })`); + + // Setting src is essentially sending a sync IPC message, which should + // not exceed more than a few ms. + // + // This is for testing #18638. + expect(delay).to.be.below(100); + }); + }); + + describe('nodeintegration attribute', () => { + it('inserts no node symbols when not set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/c.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'undefined', + module: 'undefined', + process: 'undefined', + global: 'undefined' + }); + }); + + it('inserts node symbols when set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/d.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object' + }); + }); + + it('loads node symbols after POST navigation when set', async function () { + const message = await loadWebViewAndWaitForMessage(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/post.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object' + }); + }); + + it('disables node integration on child windows when it is disabled on the webview', async () => { + const src = url.format({ + pathname: `${fixtures}/pages/webview-opener-no-node-integration.html`, + protocol: 'file', + query: { + p: `${fixtures}/pages/window-opener-node.html` + }, + slashes: true + }); + const message = await loadWebViewAndWaitForMessage(w, { + allowpopups: 'on', + webpreferences: 'contextIsolation=no', + src + }); + expect(JSON.parse(message).isProcessGlobalUndefined).to.be.true(); + }); + + ifit(!process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS)('loads native modules when navigation happens', async function () { + await loadWebView(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/native-module.html` + }); + + const message = await w.executeJavaScript(`new Promise(resolve => { + webview.addEventListener('console-message', e => resolve(e.message)) + webview.reload(); + })`); + + expect(message).to.equal('function'); + }); + }); + + describe('preload attribute', () => { + useRemoteContext({ webPreferences: { webviewTag: true } }); + it('loads the script before other scripts in window', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: `${fixtures}/module/preload.js`, + src: `file://${fixtures}/pages/e.html` + }); + + expect(message).to.be.a('string'); + expect(message).to.be.not.equal('Window script is loaded before preload script'); + }); + + it('preload script can still use "process" and "Buffer" when nodeintegration is off', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: `${fixtures}/module/preload-node-off.js`, + src: `file://${fixtures}/api/blank.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + process: 'object', + Buffer: 'function' + }); + }); + + it('runs in the correct scope when sandboxed', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: `${fixtures}/module/preload-context.js`, + src: `file://${fixtures}/api/blank.html`, + webpreferences: 'sandbox=yes' + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', // arguments passed to it should be available + electron: 'undefined', // objects from the scope it is called from should not be available + window: 'object', // the window object should be available + localVar: 'undefined' // but local variables should not be exposed to the window + }); + }); + + it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: `${fixtures}/module/preload-node-off-wrapper.js`, + webpreferences: 'sandbox=no', + src: `file://${fixtures}/api/blank.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + process: 'object', + Buffer: 'function' + }); + }); + + it('receives ipc message in preload script', async () => { + await loadWebView(w, { + preload: `${fixtures}/module/preload-ipc.js`, + src: `file://${fixtures}/pages/e.html` + }); + + const message = 'boom!'; + const { channel, args } = await w.executeJavaScript(`new Promise(resolve => { + webview.send('ping', ${JSON.stringify(message)}) + webview.addEventListener('ipc-message', ({channel, args}) => resolve({channel, args})) + })`); + + expect(channel).to.equal('pong'); + expect(args).to.deep.equal([message]); + }); + + itremote('.sendToFrame()', async (fixtures: string) => { + const w = new WebView(); + w.setAttribute('nodeintegration', 'on'); + w.setAttribute('webpreferences', 'contextIsolation=no'); + w.setAttribute('preload', `file://${fixtures}/module/preload-ipc.js`); + w.setAttribute('src', `file://${fixtures}/pages/ipc-message.html`); + document.body.appendChild(w); + const { frameId } = await new Promise(resolve => w.addEventListener('ipc-message', resolve, { once: true })); + + const message = 'boom!'; + + w.sendToFrame(frameId, 'ping', message); + const { channel, args } = await new Promise(resolve => w.addEventListener('ipc-message', resolve, { once: true })); + + expect(channel).to.equal('pong'); + expect(args).to.deep.equal([message]); + }, [fixtures]); + + it('works without script tag in page', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: `${fixtures}/module/preload.js`, + webpreferences: 'sandbox=no', + src: `file://${fixtures}/pages/base-page.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object', + Buffer: 'function' + }); + }); + + it('resolves relative URLs', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + preload: '../module/preload.js', + webpreferences: 'sandbox=no', + src: `file://${fixtures}/pages/e.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object', + Buffer: 'function' + }); + }); + + itremote('ignores empty values', async () => { + const webview = new WebView(); + + for (const emptyValue of ['', null, undefined]) { + webview.preload = emptyValue; + expect(webview.preload).to.equal(''); + } + }); + }); + + describe('httpreferrer attribute', () => { + it('sets the referrer url', async () => { + const referrer = 'http://github.com/'; + const received = await new Promise((resolve, reject) => { + const server = http.createServer((req, res) => { + try { + resolve(req.headers.referer); + } catch (e) { + reject(e); + } finally { + res.end(); + server.close(); + } + }); + listen(server).then(({ url }) => { + loadWebView(w, { + httpreferrer: referrer, + src: url + }); + }); + }); + expect(received).to.equal(referrer); + }); + }); + + describe('useragent attribute', () => { + it('sets the user agent', async () => { + const referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'; + const message = await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/useragent.html`, + useragent: referrer + }); + expect(message).to.equal(referrer); + }); + }); + + describe('disablewebsecurity attribute', () => { + it('does not disable web security when not set', async () => { + await loadWebView(w, { src: 'about:blank' }); + const result = await w.executeJavaScript(`webview.executeJavaScript(\`fetch(${JSON.stringify(blankPageUrl)}).then(() => 'ok', () => 'failed')\`)`); + expect(result).to.equal('failed'); + }); + + it('disables web security when set', async () => { + await loadWebView(w, { src: 'about:blank', disablewebsecurity: '' }); + const result = await w.executeJavaScript(`webview.executeJavaScript(\`fetch(${JSON.stringify(blankPageUrl)}).then(() => 'ok', () => 'failed')\`)`); + expect(result).to.equal('ok'); + }); + + it('does not break node integration', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + disablewebsecurity: '', + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/d.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object' + }); + }); + + it('does not break preload script', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + disablewebsecurity: '', + preload: `${fixtures}/module/preload.js`, + webpreferences: 'sandbox=no', + src: `file://${fixtures}/pages/e.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object', + Buffer: 'function' + }); + }); + }); + + describe('partition attribute', () => { + it('inserts no node symbols when not set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + partition: 'test1', + src: `file://${fixtures}/pages/c.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'undefined', + module: 'undefined', + process: 'undefined', + global: 'undefined' + }); + }); + + it('inserts node symbols when set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + nodeintegration: 'on', + partition: 'test2', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/d.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object' + }); + }); + + it('isolates storage for different id', async () => { + await w.executeJavaScript('localStorage.setItem(\'test\', \'one\')'); + + const message = await loadWebViewAndWaitForMessage(w, { + partition: 'test3', + src: `file://${fixtures}/pages/partition/one.html` + }); + + const parsedMessage = JSON.parse(message); + expect(parsedMessage).to.include({ + numberOfEntries: 0, + testValue: null + }); + }); + + it('uses current session storage when no id is provided', async () => { + await w.executeJavaScript('localStorage.setItem(\'test\', \'two\')'); + const testValue = 'two'; + + const message = await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/partition/one.html` + }); + + const parsedMessage = JSON.parse(message); + expect(parsedMessage).to.include({ + testValue + }); + }); + }); + + describe('allowpopups attribute', () => { + const generateSpecs = (description: string, webpreferences = '') => { + describe(description, () => { + it('can not open new window when not set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + webpreferences, + src: `file://${fixtures}/pages/window-open-hide.html` + }); + expect(message).to.equal('null'); + }); + + it('can open new window when set', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + webpreferences, + allowpopups: 'on', + src: `file://${fixtures}/pages/window-open-hide.html` + }); + expect(message).to.equal('window'); + }); + }); + }; + + generateSpecs('without sandbox'); + generateSpecs('with sandbox', 'sandbox=yes'); + }); + + describe('webpreferences attribute', () => { + it('can enable nodeintegration', async () => { + const message = await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/d.html`, + webpreferences: 'nodeIntegration,contextIsolation=no' + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object' + }); + }); + + it('can disable web security and enable nodeintegration', async () => { + await loadWebView(w, { src: 'about:blank', webpreferences: 'webSecurity=no, nodeIntegration=yes, contextIsolation=no' }); + const result = await w.executeJavaScript(`webview.executeJavaScript(\`fetch(${JSON.stringify(blankPageUrl)}).then(() => 'ok', () => 'failed')\`)`); + expect(result).to.equal('ok'); + const type = await w.executeJavaScript('webview.executeJavaScript("typeof require")'); + expect(type).to.equal('function'); + }); + }); + }); + + describe('events', () => { + useRemoteContext({ webPreferences: { webviewTag: true } }); + let w: WebContents; + before(async () => { + const window = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + await window.loadURL(`file://${fixtures}/pages/blank.html`); + w = window.webContents; + }); + afterEach(async () => { + await w.executeJavaScript(`{ + for (const el of document.querySelectorAll('webview')) el.remove(); + }`); + }); + after(closeAllWindows); + + describe('ipc-message event', () => { + it('emits when guest sends an ipc message to browser', async () => { + const { frameId, channel, args } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/ipc-message.html`, + nodeintegration: 'on', + webpreferences: 'contextIsolation=no' + }, 'ipc-message'); + + expect(frameId).to.be.an('array').that.has.lengthOf(2); + expect(channel).to.equal('channel'); + expect(args).to.deep.equal(['arg1', 'arg2']); + }); + }); + + describe('page-title-updated event', () => { + it('emits when title is set', async () => { + const { title, explicitSet } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/a.html` + }, 'page-title-updated'); + + expect(title).to.equal('test'); + expect(explicitSet).to.be.true(); + }); + }); + + describe('page-favicon-updated event', () => { + it('emits when favicon urls are received', async () => { + const { favicons } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/a.html` + }, 'page-favicon-updated'); + + expect(favicons).to.be.an('array').of.length(2); + if (process.platform === 'win32') { + expect(favicons[0]).to.match(/^file:\/\/\/[A-Z]:\/favicon.png$/i); + } else { + expect(favicons[0]).to.equal('file:///favicon.png'); + } + }); + }); + + describe('did-redirect-navigation event', () => { + it('is emitted on redirects', async () => { + const server = http.createServer((req, res) => { + if (req.url === '/302') { + res.setHeader('Location', '/200'); + res.statusCode = 302; + res.end(); + } else { + res.end(); + } + }); + const { url } = await listen(server); + defer(() => { server.close(); }); + const event = await loadWebViewAndWaitForEvent(w, { + src: `${url}/302` + }, 'did-redirect-navigation'); + + expect(event.url).to.equal(`${url}/200`); + expect(event.isInPlace).to.be.false(); + expect(event.isMainFrame).to.be.true(); + expect(event.frameProcessId).to.be.a('number'); + expect(event.frameRoutingId).to.be.a('number'); + }); + }); + + describe('will-navigate event', () => { + it('emits when a url that leads to outside of the page is loaded', async () => { + const { url } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/webview-will-navigate.html` + }, 'will-navigate'); + + expect(url).to.equal('http://host/'); + }); + }); + + describe('will-frame-navigate event', () => { + it('emits when a link that leads to outside of the page is loaded', async () => { + const { url, isMainFrame } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/webview-will-navigate.html` + }, 'will-frame-navigate'); + expect(url).to.equal('http://host/'); + expect(isMainFrame).to.be.true(); + }); + + it('emits when a link within an iframe, which leads to outside of the page, is loaded', async () => { + await loadWebView(w, { + src: `file://${fixtures}/pages/webview-will-navigate-in-frame.html`, + nodeIntegration: '' + }); + + const { url, frameProcessId, frameRoutingId } = await w.executeJavaScript(` + new Promise((resolve, reject) => { + let hasFrameNavigatedOnce = false; + const webview = document.getElementById('webview'); + webview.addEventListener('will-frame-navigate', ({url, isMainFrame, frameProcessId, frameRoutingId}) => { + if (isMainFrame) return; + if (hasFrameNavigatedOnce) resolve({ + url, + isMainFrame, + frameProcessId, + frameRoutingId, + }); + + // First navigation is the initial iframe load within the + hasFrameNavigatedOnce = true; + }); + webview.executeJavaScript('loadSubframe()'); + }); + `); + + expect(url).to.equal('http://host/'); + expect(frameProcessId).to.be.a('number'); + expect(frameRoutingId).to.be.a('number'); + }); + }); + + describe('did-navigate event', () => { + it('emits when a url that leads to outside of the page is clicked', async () => { + const pageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-will-navigate.html')).toString(); + const event = await loadWebViewAndWaitForEvent(w, { src: pageUrl }, 'did-navigate'); + expect(event.url).to.equal(pageUrl); + }); + }); + + describe('did-navigate-in-page event', () => { + it('emits when an anchor link is clicked', async () => { + const pageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html')).toString(); + const event = await loadWebViewAndWaitForEvent(w, { src: pageUrl }, 'did-navigate-in-page'); + expect(event.url).to.equal(`${pageUrl}#test_content`); + }); + + it('emits when window.history.replaceState is called', async () => { + const { url } = await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/webview-did-navigate-in-page-with-history.html` + }, 'did-navigate-in-page'); + expect(url).to.equal('http://host/'); + }); + + it('emits when window.location.hash is changed', async () => { + const pageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html')).toString(); + const event = await loadWebViewAndWaitForEvent(w, { src: pageUrl }, 'did-navigate-in-page'); + expect(event.url).to.equal(`${pageUrl}#test`); + }); + }); + + describe('close event', () => { + it('should fire when interior page calls window.close', async () => { + await loadWebViewAndWaitForEvent(w, { src: `file://${fixtures}/pages/close.html` }, 'close'); + }); + }); + + describe('devtools-opened event', () => { + it('should fire when webview.openDevTools() is called', async () => { + await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/base-page.html` + }, 'dom-ready'); + + await w.executeJavaScript(`new Promise((resolve) => { + webview.openDevTools() + webview.addEventListener('devtools-opened', () => resolve(), {once: true}) + })`); + await w.executeJavaScript('webview.closeDevTools()'); + }); + }); + + describe('devtools-closed event', () => { + itremote('should fire when webview.closeDevTools() is called', async (fixtures: string) => { + const webview = new WebView(); + webview.src = `file://${fixtures}/pages/base-page.html`; + document.body.appendChild(webview); + await new Promise(resolve => webview.addEventListener('dom-ready', resolve, { once: true })); + + webview.openDevTools(); + await new Promise(resolve => webview.addEventListener('devtools-opened', resolve, { once: true })); + + webview.closeDevTools(); + await new Promise(resolve => webview.addEventListener('devtools-closed', resolve, { once: true })); + }, [fixtures]); + }); + + describe('devtools-focused event', () => { + itremote('should fire when webview.openDevTools() is called', async (fixtures: string) => { + const webview = new WebView(); + webview.src = `file://${fixtures}/pages/base-page.html`; + document.body.appendChild(webview); + + const waitForDevToolsFocused = new Promise(resolve => webview.addEventListener('devtools-focused', resolve, { once: true })); + await new Promise(resolve => webview.addEventListener('dom-ready', resolve, { once: true })); + webview.openDevTools(); + + await waitForDevToolsFocused; + webview.closeDevTools(); + }, [fixtures]); + }); + + describe('dom-ready event', () => { + it('emits when document is loaded', async () => { + const server = http.createServer(() => {}); + const { port } = await listen(server); + await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/dom-ready.html?port=${port}` + }, 'dom-ready'); + defer(() => { server.close(); }); + }); + + itremote('throws a custom error when an API method is called before the event is emitted', () => { + const expectedErrorMessage = + 'The WebView must be attached to the DOM ' + + 'and the dom-ready event emitted before this method can be called.'; + const webview = new WebView(); + expect(() => { webview.stop(); }).to.throw(expectedErrorMessage); + }); + }); + + describe('context-menu event', () => { + it('emits when right-clicked in page', async () => { + await loadWebView(w, { src: 'about:blank' }); + + const { params, url } = await w.executeJavaScript(`new Promise(resolve => { + webview.addEventListener('context-menu', (e) => resolve({...e, url: webview.getURL() }), {once: true}) + // Simulate right-click to create context-menu event. + const opts = { x: 0, y: 0, button: 'right' }; + webview.sendInputEvent({ ...opts, type: 'mouseDown' }); + webview.sendInputEvent({ ...opts, type: 'mouseUp' }); + })`); + + expect(params.pageURL).to.equal(url); + expect(params.frame).to.be.undefined(); + expect(params.x).to.be.a('number'); + expect(params.y).to.be.a('number'); + }); + }); + + describe('found-in-page event', () => { + itremote('emits when a request is made', async (fixtures: string) => { + const webview = new WebView(); + const didFinishLoad = new Promise(resolve => webview.addEventListener('did-finish-load', resolve, { once: true })); + webview.src = `file://${fixtures}/pages/content.html`; + document.body.appendChild(webview); + // TODO(deepak1556): With https://codereview.chromium.org/2836973002 + // focus of the webContents is required when triggering the api. + // Remove this workaround after determining the cause for + // incorrect focus. + webview.focus(); + await didFinishLoad; + + const activeMatchOrdinal = []; + + for (;;) { + const foundInPage = new Promise(resolve => webview.addEventListener('found-in-page', resolve, { once: true })); + const requestId = webview.findInPage('virtual'); + const event = await foundInPage; + + expect(event.result.requestId).to.equal(requestId); + expect(event.result.matches).to.equal(3); + + activeMatchOrdinal.push(event.result.activeMatchOrdinal); + + if (event.result.activeMatchOrdinal === event.result.matches) { + break; + } + } + + expect(activeMatchOrdinal).to.deep.equal([1, 2, 3]); + webview.stopFindInPage('clearSelection'); + }, [fixtures]); + }); + + describe('will-attach-webview event', () => { + itremote('does not emit when src is not changed', async () => { + const webview = new WebView(); + document.body.appendChild(webview); + await setTimeout(); + const expectedErrorMessage = 'The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.'; + expect(() => { webview.stop(); }).to.throw(expectedErrorMessage); + }); + + it('supports changing the web preferences', async () => { + w.once('will-attach-webview', (event, webPreferences, params) => { + params.src = `file://${path.join(fixtures, 'pages', 'c.html')}`; + webPreferences.nodeIntegration = false; + }); + const message = await loadWebViewAndWaitForMessage(w, { + nodeintegration: 'yes', + src: `file://${fixtures}/pages/a.html` + }); + + const types = JSON.parse(message); + expect(types).to.include({ + require: 'undefined', + module: 'undefined', + process: 'undefined', + global: 'undefined' + }); + }); + + it('handler modifying params.instanceId does not break ', async () => { + w.once('will-attach-webview', (event, webPreferences, params) => { + params.instanceId = null as any; + }); + + await loadWebViewAndWaitForMessage(w, { + src: `file://${fixtures}/pages/a.html` + }); + }); + + it('supports preventing a webview from being created', async () => { + w.once('will-attach-webview', event => event.preventDefault()); + + await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/c.html` + }, 'destroyed'); + }); + + it('supports removing the preload script', async () => { + w.once('will-attach-webview', (event, webPreferences, params) => { + params.src = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-stripped-preload.html')).toString(); + delete webPreferences.preload; + }); + + const message = await loadWebViewAndWaitForMessage(w, { + nodeintegration: 'yes', + preload: path.join(fixtures, 'module', 'preload-set-global.js'), + src: `file://${fixtures}/pages/a.html` + }); + + expect(message).to.equal('undefined'); + }); + }); + + describe('media-started-playing and media-paused events', () => { + it('emits when audio starts and stops playing', async function () { + if (!await w.executeJavaScript('document.createElement(\'audio\').canPlayType(\'audio/wav\')')) { + return this.skip(); + } + + await loadWebView(w, { src: blankPageUrl }); + + // With the new autoplay policy, audio elements must be unmuted + // see https://goo.gl/xX8pDD. + await w.executeJavaScript(`new Promise(resolve => { + webview.executeJavaScript(\` + const audio = document.createElement("audio") + audio.src = "../assets/tone.wav" + document.body.appendChild(audio); + audio.play() + \`, true) + webview.addEventListener('media-started-playing', () => resolve(), {once: true}) + })`); + + await w.executeJavaScript(`new Promise(resolve => { + webview.executeJavaScript(\` + document.querySelector("audio").pause() + \`, true) + webview.addEventListener('media-paused', () => resolve(), {once: true}) + })`); + }); + }); + }); + + describe('methods', () => { + let w: WebContents; + before(async () => { + const window = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + await window.loadURL(`file://${fixtures}/pages/blank.html`); + w = window.webContents; + }); + afterEach(async () => { + await w.executeJavaScript(`{ + for (const el of document.querySelectorAll('webview')) el.remove(); + }`); + }); + after(closeAllWindows); + + describe('.reload()', () => { + it('should emit beforeunload handler', async () => { + await loadWebView(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/beforeunload-false.html` + }); + + // Event handler has to be added before reload. + const channel = await w.executeJavaScript(`new Promise(resolve => { + webview.addEventListener('ipc-message', e => resolve(e.channel)) + webview.reload(); + })`); + + expect(channel).to.equal('onbeforeunload'); + }); + }); + + describe('.goForward()', () => { + useRemoteContext({ webPreferences: { webviewTag: true } }); + itremote('should work after a replaced history entry', async (fixtures: string) => { + function waitForEvent (target: EventTarget, event: string) { + return new Promise(resolve => target.addEventListener(event, resolve, { once: true })); + } + + function waitForEvents (target: EventTarget, ...events: string[]) { + return Promise.all(events.map(event => waitForEvent(webview, event))); + } + + const webview = new WebView(); + + webview.setAttribute('nodeintegration', 'on'); + webview.setAttribute('webpreferences', 'contextIsolation=no'); + webview.src = `file://${fixtures}/pages/history-replace.html`; + document.body.appendChild(webview); + + { + const [e] = await waitForEvents(webview, 'ipc-message', 'did-stop-loading'); + expect(e.channel).to.equal('history'); + expect(e.args[0]).to.equal(1); + expect(webview.canGoBack()).to.be.false(); + expect(webview.canGoForward()).to.be.false(); + } + + webview.src = `file://${fixtures}/pages/base-page.html`; + + await new Promise(resolve => webview.addEventListener('did-stop-loading', resolve, { once: true })); + + expect(webview.canGoBack()).to.be.true(); + expect(webview.canGoForward()).to.be.false(); + + webview.goBack(); + + { + const [e] = await waitForEvents(webview, 'ipc-message', 'did-stop-loading'); + expect(e.channel).to.equal('history'); + expect(e.args[0]).to.equal(2); + expect(webview.canGoBack()).to.be.false(); + expect(webview.canGoForward()).to.be.true(); + } + + webview.goForward(); + + await new Promise(resolve => webview.addEventListener('did-stop-loading', resolve, { once: true })); + + expect(webview.canGoBack()).to.be.true(); + expect(webview.canGoForward()).to.be.false(); + }, [fixtures]); + }); + + describe('.clearHistory()', () => { + it('should clear the navigation history', async () => { + await loadWebView(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: blankPageUrl + }); + + // Navigation must be triggered by a user gesture to make canGoBack() return true + await w.executeJavaScript('webview.executeJavaScript(`history.pushState(null, "", "foo.html")`, true)'); + + expect(await w.executeJavaScript('webview.canGoBack()')).to.be.true(); + + await w.executeJavaScript('webview.clearHistory()'); + expect(await w.executeJavaScript('webview.canGoBack()')).to.be.false(); + }); + }); + + describe('executeJavaScript', () => { + it('can return the result of the executed script', async () => { + await loadWebView(w, { + src: 'about:blank' + }); + + const jsScript = "'4'+2"; + const expectedResult = '42'; + + const result = await w.executeJavaScript(`webview.executeJavaScript(${JSON.stringify(jsScript)})`); + expect(result).to.equal(expectedResult); + }); + }); + + it('supports inserting CSS', async () => { + await loadWebView(w, { src: `file://${fixtures}/pages/base-page.html` }); + await w.executeJavaScript('webview.insertCSS(\'body { background-repeat: round; }\')'); + const result = await w.executeJavaScript('webview.executeJavaScript(\'window.getComputedStyle(document.body).getPropertyValue("background-repeat")\')'); + expect(result).to.equal('round'); + }); + + it('supports removing inserted CSS', async () => { + await loadWebView(w, { src: `file://${fixtures}/pages/base-page.html` }); + const key = await w.executeJavaScript('webview.insertCSS(\'body { background-repeat: round; }\')'); + await w.executeJavaScript(`webview.removeInsertedCSS(${JSON.stringify(key)})`); + const result = await w.executeJavaScript('webview.executeJavaScript(\'window.getComputedStyle(document.body).getPropertyValue("background-repeat")\')'); + expect(result).to.equal('repeat'); + }); + + describe('sendInputEvent', () => { + it('can send keyboard event', async () => { + await loadWebViewAndWaitForEvent(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/onkeyup.html` + }, 'dom-ready'); + + const waitForIpcMessage = w.executeJavaScript('new Promise(resolve => webview.addEventListener("ipc-message", e => resolve({...e})), {once: true})'); + w.executeJavaScript(`webview.sendInputEvent({ + type: 'keyup', + keyCode: 'c', + modifiers: ['shift'] + })`); + + const { channel, args } = await waitForIpcMessage; + expect(channel).to.equal('keyup'); + expect(args).to.deep.equal(['C', 'KeyC', 67, true, false]); + }); + + it('can send mouse event', async () => { + await loadWebViewAndWaitForEvent(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/onmouseup.html` + }, 'dom-ready'); + + const waitForIpcMessage = w.executeJavaScript('new Promise(resolve => webview.addEventListener("ipc-message", e => resolve({...e})), {once: true})'); + w.executeJavaScript(`webview.sendInputEvent({ + type: 'mouseup', + modifiers: ['ctrl'], + x: 10, + y: 20 + })`); + + const { channel, args } = await waitForIpcMessage; + expect(channel).to.equal('mouseup'); + expect(args).to.deep.equal([10, 20, false, true]); + }); + }); + + describe('.getWebContentsId', () => { + it('can return the WebContents ID', async () => { + await loadWebView(w, { src: 'about:blank' }); + + expect(await w.executeJavaScript('webview.getWebContentsId()')).to.be.a('number'); + }); + }); + + ifdescribe(features.isPrintingEnabled())('.printToPDF()', () => { + it('rejects on incorrectly typed parameters', async () => { + const badTypes = { + landscape: [], + displayHeaderFooter: '123', + printBackground: 2, + scale: 'not-a-number', + pageSize: 'IAmAPageSize', + margins: 'terrible', + pageRanges: { oops: 'im-not-the-right-key' }, + headerTemplate: [1, 2, 3], + footerTemplate: [4, 5, 6], + preferCSSPageSize: 'no' + }; + + // These will hard crash in Chromium unless we type-check + for (const [key, value] of Object.entries(badTypes)) { + const param = { [key]: value }; + + const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; + await loadWebView(w, { src }); + await expect(w.executeJavaScript(`webview.printToPDF(${JSON.stringify(param)})`)).to.eventually.be.rejected(); + } + }); + + it('can print to PDF', async () => { + const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; + await loadWebView(w, { src }); + + const data = await w.executeJavaScript('webview.printToPDF({})'); + expect(data).to.be.an.instanceof(Uint8Array).that.is.not.empty(); + }); + }); + + describe('DOM events', () => { + for (const [description, sandbox] of [ + ['without sandbox', false] as const, + ['with sandbox', true] as const + ]) { + describe(description, () => { + it('emits focus event', async () => { + await loadWebViewAndWaitForEvent(w, { + src: `file://${fixtures}/pages/a.html`, + webpreferences: `sandbox=${sandbox ? 'yes' : 'no'}` + }, 'dom-ready'); + + // If this test fails, check if webview.focus() still works. + await w.executeJavaScript(`new Promise(resolve => { + webview.addEventListener('focus', () => resolve(), {once: true}); + webview.focus(); + })`); + }); + }); + } + }); + + // FIXME: This test is flaking constantly on Linux and macOS. + xdescribe('.capturePage()', () => { + it('returns a Promise with a NativeImage', async function () { + this.retries(5); + + const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; + await loadWebViewAndWaitForEvent(w, { src }, 'did-stop-loading'); + + const image = await w.executeJavaScript('webview.capturePage()'); + expect(image.isEmpty()).to.be.false(); + + // Check the 25th byte in the PNG. + // Values can be 0,2,3,4, or 6. We want 6, which is RGB + Alpha + const imgBuffer = image.toPNG(); + expect(imgBuffer[25]).to.equal(6); + }); + + it('returns a Promise with a NativeImage in the renderer', async function () { + this.retries(5); + + const src = 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'; + await loadWebViewAndWaitForEvent(w, { src }, 'did-stop-loading'); + + const byte = await w.executeJavaScript(`new Promise(resolve => { + webview.capturePage().then(image => { + resolve(image.toPNG()[25]) + }); + })`); + + expect(byte).to.equal(6); + }); + }); + + // FIXME(zcbenz): Disabled because of moving to OOPIF webview. + xdescribe('setDevToolsWebContents() API', () => { + /* + it('sets webContents of webview as devtools', async () => { + const webview2 = new WebView(); + loadWebView(webview2); + + // Setup an event handler for further usage. + const waitForDomReady = waitForEvent(webview2, 'dom-ready'); + + loadWebView(webview, { src: 'about:blank' }); + await waitForEvent(webview, 'dom-ready'); + webview.getWebContents().setDevToolsWebContents(webview2.getWebContents()); + webview.getWebContents().openDevTools(); + + await waitForDomReady; + + // Its WebContents should be a DevTools. + const devtools = webview2.getWebContents(); + expect(devtools.getURL().startsWith('devtools://devtools')).to.be.true(); + + const name = await devtools.executeJavaScript('InspectorFrontendHost.constructor.name'); + document.body.removeChild(webview2); + + expect(name).to.be.equal('InspectorFrontendHostImpl'); + }); + */ + }); + }); + + describe('basic auth', () => { + let w: WebContents; + before(async () => { + const window = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + nodeIntegration: true, + contextIsolation: false + } + }); + await window.loadURL(`file://${fixtures}/pages/blank.html`); + w = window.webContents; + }); + afterEach(async () => { + await w.executeJavaScript(`{ + for (const el of document.querySelectorAll('webview')) el.remove(); + }`); + }); + after(closeAllWindows); + + it('should authenticate with correct credentials', async () => { + const message = 'Authenticated'; + const server = http.createServer((req, res) => { + const credentials = auth(req)!; + if (credentials.name === 'test' && credentials.pass === 'test') { + res.end(message); + } else { + res.end('failed'); + } + }); + defer(() => { + server.close(); + }); + const { port } = await listen(server); + const e = await loadWebViewAndWaitForEvent(w, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + src: `file://${fixtures}/pages/basic-auth.html?port=${port}` + }, 'ipc-message'); + expect(e.channel).to.equal(message); + }); + }); +}); diff --git a/spec/yarn.lock b/spec/yarn.lock index 3bb7e4d164a92..dab7a807a7cf8 100644 --- a/spec/yarn.lock +++ b/spec/yarn.lock @@ -2,88 +2,515 @@ # yarn lockfile v1 +"@electron-ci/echo@file:./fixtures/native-addon/echo": + version "0.0.1" + +"@electron-ci/external-ab@file:./fixtures/native-addon/external-ab": + version "0.0.1" + +"@electron-ci/is-valid-window@file:./is-valid-window": + version "0.0.5" + dependencies: + nan "2.x" + +"@electron-ci/osr-gpu@file:./fixtures/native-addon/osr-gpu": + version "0.0.1" + +"@electron-ci/uv-dlopen@file:./fixtures/native-addon/uv-dlopen": + version "0.0.1" + +"@electron/asar@^3.2.1", "@electron/asar@^3.2.7": + version "3.2.10" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.10.tgz#615cf346b734b23cafa4e0603551010bd0e50aa8" + integrity sha512-mvBSwIBUeiRscrCeJE1LwctAriBj65eUDm0Pc11iE5gRwzkmsdbS7FnZ1XUWjpSeQWL1L5g12Fc/SchPM9DUOw== + dependencies: + commander "^5.0.0" + glob "^7.1.6" + minimatch "^3.0.4" + +"@electron/fuses@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@electron/fuses/-/fuses-1.8.0.tgz#ad34d3cc4703b1258b83f6989917052cfc1490a0" + integrity sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw== + dependencies: + chalk "^4.1.1" + fs-extra "^9.0.1" + minimist "^1.2.5" + +"@electron/get@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@electron/get/-/get-3.0.0.tgz#2b0c794b98902d0bc5218546872c1379bef68aa2" + integrity sha512-hLv4BYFiyrNRI+U0Mm2X7RxCCdJLkDUn8GCEp9QJzbLpZRko+UaLlCjOMkj6TEtirNLPyBA7y1SeGfnpOB21aQ== + dependencies: + debug "^4.1.1" + env-paths "^2.2.0" + fs-extra "^8.1.0" + got "^11.8.5" + progress "^2.0.3" + semver "^6.2.0" + sumchecker "^3.0.1" + optionalDependencies: + global-agent "^3.0.0" + +"@electron/notarize@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@electron/notarize/-/notarize-2.3.0.tgz#9659cf6c92563dd69411afce229f52f9f7196227" + integrity sha512-EiTBU0BwE7HZZjAG1fFWQaiQpCuPrVGn7jPss1kUjD6eTTdXXd29RiZqEqkgN7xqt/Pgn4g3I7Saqovanrfj3w== + dependencies: + debug "^4.1.1" + fs-extra "^9.0.1" + promise-retry "^2.0.1" + +"@electron/osx-sign@^1.0.5": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.2.0.tgz#d1c83cac03e52f210858594eb011142a1ad0ae70" + integrity sha512-kOA3bAeDXFMj2JHj0R2fk/IT92qpu3tZHwM4l/PdksAuy7eA3/23QktCiAoQICwPdtxCYdt9ZLimKvnNyUpdSQ== + dependencies: + compare-version "^0.1.2" + debug "^4.3.4" + fs-extra "^10.0.0" + isbinaryfile "^4.0.8" + minimist "^1.2.6" + plist "^3.0.5" + +"@electron/packager@^18.3.2": + version "18.3.2" + resolved "https://registry.yarnpkg.com/@electron/packager/-/packager-18.3.2.tgz#49412a06b3233635bd9cdf87edf9cd9e2aa0567f" + integrity sha512-orjylavppgIh24qkNpWm2B/LQUpCS/YLOoKoU+eMK/hJgIhShLDsusPIQzgUGVwNCichu8/zPAGfdQZXHG0gtw== + dependencies: + "@electron/asar" "^3.2.1" + "@electron/get" "^3.0.0" + "@electron/notarize" "^2.1.0" + "@electron/osx-sign" "^1.0.5" + "@electron/universal" "^2.0.1" + "@electron/windows-sign" "^1.0.0" + debug "^4.0.1" + extract-zip "^2.0.0" + filenamify "^4.1.0" + fs-extra "^11.1.0" + galactus "^1.0.0" + get-package-info "^1.0.0" + junk "^3.1.0" + parse-author "^2.0.0" + plist "^3.0.0" + resedit "^2.0.0" + resolve "^1.1.6" + semver "^7.1.3" + yargs-parser "^21.1.1" + +"@electron/universal@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-2.0.1.tgz#7b070ab355e02957388f3dbd68e2c3cd08c448ae" + integrity sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA== + dependencies: + "@electron/asar" "^3.2.7" + "@malept/cross-spawn-promise" "^2.0.0" + debug "^4.3.1" + dir-compare "^4.2.0" + fs-extra "^11.1.1" + minimatch "^9.0.3" + plist "^3.1.0" + +"@electron/windows-sign@^1.0.0": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@electron/windows-sign/-/windows-sign-1.1.2.tgz#5489861ca62348d2300407e85d949af95849955e" + integrity sha512-eXEiZjDtxW3QORCWfRUarANPRTlH9B6At4jqBZJ0NzokSGutXQUVLPA6WmGpIhDW6w2yCMdHW1EJd1HrXtU5sg== + dependencies: + cross-dirname "^0.1.0" + debug "^4.3.4" + fs-extra "^11.1.1" + minimist "^1.2.8" + postject "^1.0.0-alpha.6" + +"@malept/cross-spawn-promise@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz#d0772de1aa680a0bfb9ba2f32b4c828c7857cb9d" + integrity sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg== + dependencies: + cross-spawn "^7.0.1" + +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@marshallofsound/mocha-appveyor-reporter@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@marshallofsound/mocha-appveyor-reporter/-/mocha-appveyor-reporter-0.4.3.tgz#a9225224391a90e3c6bb48415d5015de895a7114" + integrity sha512-uKMY+VTNWQRcMr9P7ErRqi0TKAC6oceFs2Y6MDdXqDNxOU4AQYQ6WNrH8LuCQFeV9Y/vMU7wFJvD7oQeWsQzWQ== + dependencies: + got "^11.8.6" + "@nornagon/put@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@nornagon/put/-/put-0.0.8.tgz#9d497ec46c9364acc3f8b59aa3cf8ee4134ae337" integrity sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow== -"@types/color-name@^1.1.1": +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@sinonjs/samsam@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f" + integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg== + dependencies: + "@sinonjs/commons" "^1.6.0" + lodash.get "^4.4.2" + type-detect "^4.0.8" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918" + integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@types/basic-auth@^1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@types/basic-auth/-/basic-auth-1.1.8.tgz#ea235203c89e233faae66b99e03665747576e9e9" + integrity sha512-dKcUeixGuZn8pBjcUrf1N7x5K6lWuKuwHHitM2IZ4vwZUDWEhhNtwCWiba8jTA9zn0GQQ+fTFkWpKx8pOU/enw== + dependencies: + "@types/node" "*" + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/busboy@^1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/busboy/-/busboy-1.5.4.tgz#0038c31102ca90f2a7f0d8bc27ee5ebf1088e230" + integrity sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw== + dependencies: + "@types/node" "*" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/chai-as-promised@^7", "@types/chai-as-promised@^7.1.3": + version "7.1.8" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" + integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== + dependencies: + "@types/chai" "*" + +"@types/chai@*", "@types/chai@^4.3.19": + version "4.3.19" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.19.tgz#14519f437361d41e84102ed3fbc922ddace3e228" + integrity sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw== + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/dirty-chai@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/dirty-chai/-/dirty-chai-2.0.5.tgz#f743c5735ba0453e2ec8036610356b1aee5f522b" + integrity sha512-7plNsOhNtFn/4eD47et+3CRFNX4tgUrbJRutGhBFqQrWWIyRAV1XP7BYZY0YTOr49t/ZwM/lOW6sxnEXqwVdKg== + dependencies: + "@types/chai" "*" + "@types/chai-as-promised" "^7" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" + integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^4.17.13": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-cache-semantics@*": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/mocha@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" + integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w== + +"@types/node@*": + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== + dependencies: + undici-types "~5.26.4" + +"@types/qs@*": + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/responselike@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== + dependencies: + "@types/node" "*" + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/send@^0.14.5": + version "0.14.7" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.14.7.tgz#ee6224edd5a593d7f553235f350569accb56a4af" + integrity sha512-WCUMbzWW1sTEZX31cRMcBxflUXX/JmAYejhjxXtrLGn+vd/yyFjHh/F9FIigAEjE2LauhfH94BT7NJj9Ru2Wlg== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/sinon@^9.0.4": + version "9.0.11" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.11.tgz#7af202dda5253a847b511c929d8b6dda170562eb" + integrity sha512-PwP4UY33SeeVKodNE37ZlOsR9cReypbMJOhZ7BVE0lB+Hix3efCOxiJWiE5Ia+yL9Cn2Ch72EjFTRze8RZsNtg== + dependencies: + "@types/sinonjs__fake-timers" "*" + +"@types/sinonjs__fake-timers@*": + version "8.1.5" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz#5fd3592ff10c1e9695d377020c033116cc2889f2" + integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ== + +"@types/split@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/split/-/split-1.0.5.tgz#4bd47164b81d6381db37978d5344b374b6825f6c" + integrity sha512-gMiDr4vA6YofTpAkPQtP+5pvStIf3CMYphf32YAG/3RwogNL8ii1CQKDc+sxN62KuxPoRaJXcf2zDCDkEBH4FA== + dependencies: + "@types/node" "*" + "@types/through" "*" + +"@types/through@*": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.33.tgz#14ebf599320e1c7851e7d598149af183c6b9ea56" + integrity sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ== + dependencies: + "@types/node" "*" + +"@types/uuid@^3.4.6": + version "3.4.13" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.13.tgz#fe890e517fb840620be284ee213e81d702b1f76b" + integrity sha512-pAeZeUbLE4Z9Vi9wsWV2bYPTweEHeJJy0G4pEjOA/FSvy1Ad5U5Km8iDV6TKre1mjBiVNfAdVHKruP8bAh4Q5A== + +"@types/w3c-web-serial@^1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/w3c-web-serial/-/w3c-web-serial-1.0.7.tgz#44416509af271e5196833ff5e1337c7c256991c6" + integrity sha512-jzcwm//EZ0Z306L1/O1GXC3GthRd//9eaNB4/Yagm98UjEQViTzDS8bYvL+y+rTk1r9OFt9Yhp5pprUQFzSiiQ== + +"@types/ws@^7.2.0": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/yauzl@^2.9.1": + version "2.10.3" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" + integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== + dependencies: + "@types/node" "*" + +"@xmldom/xmldom@^0.8.8": + version "0.8.10" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" + integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== + +abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abstract-socket@^2.0.0: +abstract-socket@^2.0.0, "abstract-socket@github:deepak1556/node-abstractsocket#928cc591decd12aff7dad96449da8afc29832c19": version "2.1.1" - resolved "https://registry.yarnpkg.com/abstract-socket/-/abstract-socket-2.1.1.tgz#243a7e6e6ff65bb9eab16a22fa90699b91e528f7" - integrity sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA== + resolved "https://codeload.github.com/deepak1556/node-abstractsocket/tar.gz/928cc591decd12aff7dad96449da8afc29832c19" dependencies: bindings "^1.2.1" - nan "^2.12.1" + node-addon-api "8.0.0" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" -ajv@^6.5.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 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" + debug "4" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-regex@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - "@types/color-name" "^1.1.1" color-convert "^2.0.1" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: - safer-buffer "~2.1.0" + normalize-path "^3.0.0" + picomatch "^2.0.4" -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +author-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/author-regex/-/author-regex-1.0.0.tgz#d08885be6b9bbf9439fe087c76287245f0a81450" + integrity sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g== balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== basic-auth@^2.0.1: version "2.0.1" @@ -92,12 +519,10 @@ basic-auth@^2.0.1: dependencies: safe-buffer "5.1.2" -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bindings@^1.2.1: version "1.5.0" @@ -106,6 +531,34 @@ bindings@^1.2.1: dependencies: file-uri-to-path "1.0.0" +bluebird@^3.1.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +boolean@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" + integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -114,15 +567,84 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + 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" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +canvas@^2.11.2: + version "2.11.2" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.17.0" + simple-get "^3.0.3" chai-as-promised@^7.1.1: version "7.1.1" @@ -132,40 +654,78 @@ chai-as-promised@^7.1.1: check-error "^1.0.2" chai@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + version "4.4.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" + integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== dependencies: assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.0" - type-detect "^4.0.5" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + +chalk@^4.1.0, chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" -charenc@~0.0.1: +charenc@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" -cliui@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3" - integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ== +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + coffeescript@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.4.1.tgz#815fd337df0a34d49e74a98a6ebea9c3e7930f70" - integrity sha512-34GV1aHrsMpTaO3KfMJL40ZNuvKDR/g98THHnE9bQj8HjMaZvSrLik99WWqyMhRtbe8V5hpx5iLgdcSvM/S2wg== + version "2.7.0" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.7.0.tgz#a43ec03be6885d6d1454850ea70b9409c391279c" + integrity sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A== color-convert@^2.0.1: version "2.0.1" @@ -179,39 +739,76 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== +commander@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commander@^9.4.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +compare-version@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" + integrity sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A== concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -crypt@~0.0.1: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +cross-dirname@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cross-dirname/-/cross-dirname-0.1.0.tgz#b899599f30a5389f59e78c150e19f957ad16a37c" + integrity sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q== + +cross-spawn@^7.0.1: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: - assert-plus "^1.0.0" + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== "dbus-native@github:nornagon/dbus-native#master": version "0.4.0" @@ -234,46 +831,111 @@ debug@2.6.9, debug@^2.2.0: dependencies: ms "2.0.0" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: - ms "2.0.0" + ms "2.1.2" -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "^2.1.1" + ms "2.1.2" -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" -delayed-stream@~1.0.0: +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -depd@1.1.2, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +detect-libc@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dir-compare@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-4.2.0.tgz#d1d4999c14fbf55281071fdae4293b3b9ce86f19" + integrity sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ== + dependencies: + minimatch "^3.0.5" + p-limit "^3.1.0 " dirty-chai@^2.0.1: version "2.0.1" @@ -281,22 +943,14 @@ dirty-chai@^2.0.1: integrity sha512-ys79pWKvDMowIDEPC6Fig8d5THiC0DJ2gmTeGzVAoEH18J8OzLud0Jh7I9IWg3NSk8x2UocznUuFmfHCXYZx9w== duplexer@^0.1.1, duplexer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= - -ecc-jsbn@~0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== emoji-regex@^8.0.0: version "8.0.0" @@ -306,27 +960,78 @@ emoji-regex@^8.0.0: encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -escalade@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es6-error@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + +escalade@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@1.0.5: +escape-string-regexp@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== event-stream@^4.0.0: version "4.0.1" @@ -341,309 +1046,779 @@ event-stream@^4.0.0: stream-combiner "^0.2.2" through "^2.3.8" -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +express@^4.20.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.10" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extract-zip@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ== -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +filenamify@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106" + integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.1" + trim-repeated "^1.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flora-colossus@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-2.0.0.tgz#af1e85db0a8256ef05f3fb531c1235236c97220a" + integrity sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA== + dependencies: + debug "^4.3.4" + fs-extra "^10.1.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== from@^0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== + +fs-extra@^10.0.0, fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^11.1.0, fs-extra@^11.1.1: + version "11.2.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +galactus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/galactus/-/galactus-1.0.0.tgz#c2615182afa0c6d0859b92e56ae36d052827db7e" + integrity sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ== + dependencies: + debug "^4.3.4" + flora-colossus "^2.0.0" + fs-extra "^10.1.0" + +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - assert-plus "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" -glob@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== +get-package-info@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-package-info/-/get-package-info-1.0.0.tgz#6432796563e28113cd9474dbbd00052985a4999c" + integrity sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw== + dependencies: + bluebird "^3.1.1" + debug "^2.2.0" + lodash.get "^4.0.0" + read-pkg-up "^2.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" -glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@^7.1.3, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 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" -graceful-fs@^4.1.15: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +global-agent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" + integrity sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q== + dependencies: + boolean "^3.0.1" + es6-error "^4.1.1" + matcher "^3.0.0" + roarr "^2.15.3" + semver "^7.3.2" + serialize-error "^7.0.1" + +globalthis@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= +got@^11.8.5, got@^11.8.6: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" + es-define-property "^1.0.0" -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== hexy@^0.2.10: version "0.2.11" resolved "https://registry.yarnpkg.com/hexy/-/hexy-0.2.11.tgz#9939c25cb6f86a91302f22b8a8a72573518e25b4" integrity sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A== -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2, inherits@2.0.4, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-buffer@~1.1.1: +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" -is-valid-window@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/is-valid-window/-/is-valid-window-0.0.5.tgz#57935b35b8c3f30f077b16d54fe5c0d0e4ba8a03" - integrity sha512-bs7tIvCJyJ9BOFZP+U3yGWH9mMQVBDxtWTokrpvpSzEQfMHX+hlhuKqltbYnVkEfj+YSgQJgAW/Klx0qQH7zbQ== +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - nan "2.x" + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= +junk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" + integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= +just-extend@^4.0.2: + version "4.2.1" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" + integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +keyv@^4.0.0: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ== + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" + p-locate "^5.0.0" + +lodash.get@^4.0.0, lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== -lodash@^4.16.4: +lodash@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + map-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" - integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= + integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ== + +matcher@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" + integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng== + dependencies: + escape-string-regexp "^4.0.0" md5@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" - integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== dependencies: - charenc "~0.0.1" - crypt "~0.0.1" - is-buffer "~1.1.1" + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.40.0" + mime-db "1.52.0" -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimist@1.2.7, minimist@~0.0.1: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + +minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -mkdirp@0.5.1, mkdirp@^0.5.1, mkdirp@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: - minimist "0.0.8" + minipass "^3.0.0" + yallist "^4.0.0" -mocha-appveyor-reporter@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/mocha-appveyor-reporter/-/mocha-appveyor-reporter-0.4.2.tgz#feb1dcc77ca0bd11cbda3fd72e5ff187d1e4758d" - integrity sha512-toYTeM5GI4DPghD0Fh17wCDEXvrUZLB5zUkBUORUxxAf/XxJPZmyMVw0Xaue3gFjdTE4eR4IOZO1wloR2Cfniw== +mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - request-json "^0.6.4" + minimist "^1.2.6" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== mocha-junit-reporter@^1.18.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.22.0.tgz#4eee2f3318398bf424a64b7594ca7a39d924479c" - integrity sha512-nRBCVxzYYhOqQr2XlByLRj5MAAy7djArRkGUSx9dGc+B9NMu4yCeo74uXKALAnMhXjuLmtAL9F8WGe3wQV30IA== + version "1.23.3" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981" + integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA== dependencies: debug "^2.2.0" md5 "^2.1.0" @@ -652,77 +1827,266 @@ mocha-junit-reporter@^1.18.0: xml "^1.0.0" mocha-multi-reporters@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" - integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= + version "1.5.1" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676" + integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg== dependencies: - debug "^3.1.0" - lodash "^4.16.4" + debug "^4.1.1" + lodash "^4.17.15" -mocha@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== +mocha@^10.0.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" + integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== dependencies: + ansi-colors "4.1.1" browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" - diff "3.5.0" - escape-string-regexp "1.0.5" - glob "7.1.2" - growl "1.10.5" - he "1.1.1" - minimatch "3.0.4" - mkdirp "0.5.1" - supports-color "5.4.0" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "8.1.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nan@2.x, nan@^2.17.0, "nan@file:../../third_party/nan": + version "2.18.0" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +nise@^4.0.4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" + integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sinonjs/fake-timers" "^6.0.0" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + path-to-regexp "^1.7.0" -nan@2.x, nan@^2.12.1, "nan@github:jkleinsc/nan#remove_accessor_signature": - version "2.16.0" - resolved "https://codeload.github.com/jkleinsc/nan/tar.gz/6a2f95a6a2209d8aa7542fb18099fd808a802059" +node-addon-api@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.0.0.tgz#5453b7ad59dd040d12e0f1a97a6fa1c765c5c9d2" + integrity sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw== -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + integrity sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g== dependencies: minimist "~0.0.1" wordwrap "~0.0.2" +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^3.0.2, "p-limit@^3.1.0 ": + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== + dependencies: + p-limit "^1.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== + +parse-author@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-author/-/parse-author-2.0.0.tgz#d3460bf1ddd0dfaeed42da754242e65fb684a81f" + integrity sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw== + dependencies: + author-regex "^1.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + +path-to-regexp@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" + integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== + dependencies: + isarray "0.0.1" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ== + dependencies: + pify "^2.0.0" -pathval@^1.1.0: +path2d@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/path2d/-/path2d-0.2.1.tgz#faf98e5e2222541805a6ac232adc026332330765" + integrity sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA== + +pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== @@ -730,129 +2094,405 @@ pathval@^1.1.0: pause-stream@^0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== dependencies: through "~2.3" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +pdfjs-dist@^4.2.67: + version "4.2.67" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.2.67.tgz#dd2a65a4b00d95cd4bc2c1f6a27c5e9eb31d512a" + integrity sha512-rJmuBDFpD7cqC8WIkQUEClyB4UAH05K4AsyewToMTp2gSy3Rrx8c1ydAVqlJlGv3yZSOrhEERQU/4ScQQFlLHA== + optionalDependencies: + canvas "^2.11.2" + path2d "^0.2.0" + +pe-library@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pe-library/-/pe-library-1.0.1.tgz#02735430885a622576a53cd8827658b7d2fada0e" + integrity sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg== -psl@^1.1.24: +pend@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6" - integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA== + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +plist@^3.0.0, plist@^3.0.5, plist@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" + integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ== + dependencies: + "@xmldom/xmldom" "^0.8.8" + base64-js "^1.5.1" + xmlbuilder "^15.1.1" + +postject@^1.0.0-alpha.6: + version "1.0.0-alpha.6" + resolved "https://registry.yarnpkg.com/postject/-/postject-1.0.0-alpha.6.tgz#9d022332272e2cfce8dea4cfce1ee6dd1b2ee135" + integrity sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A== + dependencies: + commander "^9.4.0" -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= - -request-json@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/request-json/-/request-json-0.6.4.tgz#9eff076f105a445d5996d921b58b757ce5300a21" - integrity sha512-bLlMqD0RFG63ErZ/jS0wvKsIJyM2qq5j7Bw4+nubiDysCeinLrUPUmBXLmcflEYm5IO9tGlKJfRhzeDIUB8sjQ== - dependencies: - depd "1.1.2" - request "2.88.0" - -request@2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +ps-list@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0" + integrity sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +q@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== + +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w== + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA== + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resedit@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resedit/-/resedit-2.0.2.tgz#875adfb3eb975e27e4d0bec1214b8ccc37509d5d" + integrity sha512-UKTnq602iVe+W5SyRAQx/WdWMnlDiONfXBLFg/ur4QE4EQQ8eP7Jgm5mNXdK12kKawk1vvXPja2iXKqZiGDW6Q== + dependencies: + pe-library "^1.0.1" + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve@^1.1.6, resolve@^1.10.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1: +roarr@^2.15.3: + version "2.15.4" + resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" + integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A== + dependencies: + boolean "^3.0.1" + detect-node "^2.0.4" + globalthis "^1.0.1" + json-stringify-safe "^5.0.1" + semver-compare "^1.0.0" + sprintf-js "^1.1.2" + +safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== +safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + version "1.3.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== -send@^0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" - integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== + +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.0.0, semver@^6.2.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.1.3, semver@^7.3.2: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +send@0.19.0, send@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: 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.6.2" - mime "1.4.1" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-error@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" + integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw== + dependencies: + type-fest "^0.13.1" -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + 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" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + +sinon@^9.0.1: + version "9.2.4" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" + integrity sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg== + dependencies: + "@sinonjs/commons" "^1.8.1" + "@sinonjs/fake-timers" "^6.0.1" + "@sinonjs/samsam" "^5.3.1" + diff "^4.0.2" + nise "^4.0.4" + supports-color "^7.1.0" + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.17" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" + integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== split@^1.0.1: version "1.0.1" @@ -861,146 +2501,250 @@ split@^1.0.1: dependencies: through "2" -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +sprintf-js@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== stream-combiner@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" - integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + integrity sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ== dependencies: duplexer "~0.1.1" through "~2.3.4" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-outer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + +sumchecker@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" + integrity sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg== + dependencies: + debug "^4.1.0" + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: - ansi-regex "^5.0.0" + has-flag "^4.0.0" -supports-color@5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: - has-flag "^3.0.0" + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -temp@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.0.tgz#61391795a11bd9738d4c4d7f55f012cb8f55edaa" - integrity sha512-YfUhPQCJoNQE5N+FJQcdPz63O3x3sdT4Xju69Gj4iZe0lBKOtnAMi0SLj9xKhGkcGhsxThvTJ/usxtFPo438zQ== +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: - rimraf "~2.6.2" + 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" through@2, through@^2.3.8, through@~2.3, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: - psl "^1.1.24" - punycode "^1.4.1" + is-number "^7.0.0" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg== + dependencies: + escape-string-regexp "^1.0.2" -type-detect@^4.0.0, type-detect@^4.0.5: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: - punycode "^2.1.0" + media-typer "0.3.0" + mime-types "~2.1.24" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" + isexe "^2.0.0" -walkdir@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.3.2.tgz#ac8437a288c295656848ebc19981ebc677a5f590" - integrity sha512-0Twghia4Z5wDGDYWURlhZmI47GvERMCsXIu0QZWVVZyW9ZjpbbZvD9Zy9M6cWiQQRRbAcYajIyKNavaZZDt1Uw== +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" -winreg@^1.2.4: +winreg@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b" - integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs= + integrity sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA== wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + integrity sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== wrap-ansi@^7.0.0: version "7.0.0" @@ -1014,50 +2758,93 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -xml2js@^0.4.17: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== +xml2js@0.5.0, xml2js@^0.4.17: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== dependencies: sax ">=0.6.0" - xmlbuilder "~9.0.1" + xmlbuilder "~11.0.0" xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - -y18n@^5.0.1: - version "5.0.5" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" - integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== - -yargs-parser@^20.0.0: - version "20.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.0.0.tgz#c65a1daaa977ad63cebdd52159147b789a4e19a9" - integrity sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA== - -yargs@^16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" - integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA== - dependencies: - cliui "^7.0.0" - escalade "^3.0.2" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + +xmlbuilder@^15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0, yargs@^16.0.3: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" string-width "^4.2.0" - y18n "^5.0.1" - yargs-parser "^20.0.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/tsconfig.default_app.json b/tsconfig.default_app.json index 0c5ea6038764f..c4d604c9e04d0 100644 --- a/tsconfig.default_app.json +++ b/tsconfig.default_app.json @@ -1,7 +1,9 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "rootDir": "default_app" + "rootDir": "default_app", + "module": "ESNext", + "moduleResolution": "node" }, "include": [ "default_app", diff --git a/tsconfig.json b/tsconfig.json index f233f2c0f9400..9cba61b60390c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,8 +3,7 @@ "module": "commonjs", "target": "es2020", "lib": [ - "es2019", - "esnext.weakref", + "es2022", "dom", "dom.iterable" ], @@ -15,6 +14,7 @@ "allowJs": true, "noUnusedLocals": true, "outDir": "ts-gen", + "typeRoots" : ["./node_modules/@types", "./spec/node_modules/@types"], "paths": { "@electron/internal/*": ["lib/*"] } diff --git a/tsconfig.spec.json b/tsconfig.spec.json index a5e21627ebcf5..452690921e860 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "include": [ - "spec-main", + "spec", "typings" ] } diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 7fcd2ecb2acc2..25196e752f8cb 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -1,30 +1,22 @@ -/* eslint-disable no-var */ -declare var internalBinding: any; -declare var binding: { get: (name: string) => any; process: NodeJS.Process; createPreloadScript: (src: string) => Function }; - -declare var isolatedApi: { - guestViewInternal: any; - allowGuestViewElementDefinition: NodeJS.InternalWebFrame['allowGuestViewElementDefinition']; - setIsWebView: (iframe: HTMLIFrameElement) => void; -} - declare const BUILDFLAG: (flag: boolean) => boolean; -declare const ENABLE_DESKTOP_CAPTURER: boolean; -declare const ENABLE_VIEWS_API: boolean; - declare namespace NodeJS { + interface ModuleInternal extends NodeJS.Module { + new(id: string, parent?: NodeJS.Module | null): NodeJS.Module; + _load(request: string, parent?: NodeJS.Module | null, isMain?: boolean): any; + _resolveFilename(request: string, parent?: NodeJS.Module | null, isMain?: boolean, options?: { paths: string[] }): string; + _preloadModules(requests: string[]): void; + _nodeModulePaths(from: string): string[]; + _extensions: Record any>; + _cache: Record; + wrapper: [string, string]; + } + interface FeaturesBinding { isBuiltinSpellCheckerEnabled(): boolean; - isDesktopCapturerEnabled(): boolean; - isOffscreenRenderingEnabled(): boolean; isPDFViewerEnabled(): boolean; - isRunAsNodeEnabled(): boolean; isFakeLocationProviderEnabled(): boolean; - isViewApiEnabled(): boolean; - isTtsEnabled(): boolean; isPrintingEnabled(): boolean; - isPictureInPictureEnabled(): boolean; isExtensionsEnabled(): boolean; isComponentBuild(): boolean; } @@ -33,7 +25,6 @@ declare namespace NodeJS { send(internal: boolean, channel: string, args: any[]): void; sendSync(internal: boolean, channel: string, args: any[]): any; sendToHost(channel: string, args: any[]): void; - sendTo(webContentsId: number, channel: string, args: any[]): void; invoke(internal: boolean, channel: string, args: any[]): Promise<{ error: string, result: T }>; postMessage(channel: string, message: any, transferables: MessagePort[]): void; } @@ -41,17 +32,26 @@ declare namespace NodeJS { interface V8UtilBinding { getHiddenValue(obj: any, key: string): T; setHiddenValue(obj: any, key: string, value: T): void; - deleteHiddenValue(obj: any, key: string): void; requestGarbageCollectionForTesting(): void; runUntilIdle(): void; triggerFatalErrorForTesting(): void; } + type CrashReporterBinding = Omit & { + start(submitUrl: string, + uploadToServer: boolean, + ignoreSystemCrashHandler: boolean, + rateLimit: boolean, + compress: boolean, + globalExtra: Record, + extra: Record, + isNodeProcess: boolean): void; + } + interface EnvironmentBinding { getVar(name: string): string | null; hasVar(name: string): boolean; setVar(name: string, value: string): boolean; - unSetVar(name: string): boolean; } type AsarFileInfo = { @@ -67,9 +67,7 @@ declare namespace NodeJS { type AsarFileStat = { size: number; offset: number; - isFile: boolean; - isDirectory: boolean; - isLink: boolean; + type: number; } interface AsarArchive { @@ -90,7 +88,22 @@ declare namespace NodeJS { asarPath: string; filePath: string; }; - initAsarSupport(require: NodeJS.Require): void; + } + + interface NetBinding { + isOnline(): boolean; + isValidHeaderName: (headerName: string) => boolean; + isValidHeaderValue: (headerValue: string) => boolean; + fileURLToFilePath: (url: string) => string; + Net: any; + net: any; + createURLLoader(options: CreateURLLoaderOptions): URLLoader; + resolveHost(host: string, options?: Electron.ResolveHostOptions): Promise; + } + + interface NotificationBinding { + isSupported(): boolean; + Notification: typeof Electron.Notification; } interface PowerMonitorBinding extends Electron.PowerMonitor { @@ -98,11 +111,28 @@ declare namespace NodeJS { setListeningForShutdown(listening: boolean): void; } + interface ServiceWorkerMainBinding { + ServiceWorkerMain: typeof Electron.ServiceWorkerMain; + } + + interface SessionBinding { + fromPartition: typeof Electron.Session.fromPartition, + fromPath: typeof Electron.Session.fromPath, + Session: typeof Electron.Session + } + interface WebViewManagerBinding { addGuest(guestInstanceId: number, embedder: Electron.WebContents, guest: Electron.WebContents, webPreferences: Electron.WebPreferences): void; removeGuest(embedder: Electron.WebContents, guestInstanceId: number): void; } + interface WebFrameMainBinding { + WebFrameMain: typeof Electron.WebFrameMain; + fromId(processId: number, routingId: number): Electron.WebFrameMain; + _fromIdIfExists(processId: number, routingId: number): Electron.WebFrameMain | null; + _fromFtnIdIfExists(frameTreeNodeId: number): Electron.WebFrameMain | null; + } + interface InternalWebPreferences { isWebView: boolean; hiddenPage: boolean; @@ -130,21 +160,25 @@ declare namespace NodeJS { url: string; extraHeaders?: Record; useSessionCookies?: boolean; - credentials?: 'include' | 'omit'; + credentials?: 'include' | 'omit' | 'same-origin'; body: Uint8Array | BodyFunc; session?: Electron.Session; partition?: string; referrer?: string; + referrerPolicy?: string; + cache?: string; origin?: string; hasUserActivation?: boolean; mode?: string; destination?: string; + bypassCustomProtocolHandlers?: boolean; }; type ResponseHead = { statusCode: number; statusMessage: string; httpVersion: { major: number, minor: number }; rawHeaders: { key: string, value: string }[]; + headers: Record; }; type RedirectInfo = { @@ -178,67 +212,33 @@ declare namespace NodeJS { _linkedBinding(name: 'electron_common_environment'): EnvironmentBinding; _linkedBinding(name: 'electron_common_features'): FeaturesBinding; _linkedBinding(name: 'electron_common_native_image'): { nativeImage: typeof Electron.NativeImage }; + _linkedBinding(name: 'electron_common_net'): NetBinding; _linkedBinding(name: 'electron_common_shell'): Electron.Shell; _linkedBinding(name: 'electron_common_v8_util'): V8UtilBinding; _linkedBinding(name: 'electron_browser_app'): { app: Electron.App, App: Function }; _linkedBinding(name: 'electron_browser_auto_updater'): { autoUpdater: Electron.AutoUpdater }; - _linkedBinding(name: 'electron_browser_browser_view'): { BrowserView: typeof Electron.BrowserView }; - _linkedBinding(name: 'electron_browser_crash_reporter'): Omit & { - start(submitUrl: string, - uploadToServer: boolean, - ignoreSystemCrashHandler: boolean, - rateLimit: boolean, - compress: boolean, - globalExtra: Record, - extra: Record, - isNodeProcess: boolean): void; - }; - _linkedBinding(name: 'electron_browser_desktop_capturer'): { - createDesktopCapturer(): ElectronInternal.DesktopCapturer; - }; - _linkedBinding(name: 'electron_browser_event'): { - createWithSender(sender: Electron.WebContents): Electron.Event; - createEmpty(): Electron.Event; - }; - _linkedBinding(name: 'electron_browser_event_emitter'): { - setEventEmitterPrototype(prototype: Object): void; - }; + _linkedBinding(name: 'electron_browser_crash_reporter'): CrashReporterBinding; + _linkedBinding(name: 'electron_browser_desktop_capturer'): { createDesktopCapturer(): ElectronInternal.DesktopCapturer; isDisplayMediaSystemPickerAvailable(): boolean; }; + _linkedBinding(name: 'electron_browser_event_emitter'): { setEventEmitterPrototype(prototype: Object): void; }; _linkedBinding(name: 'electron_browser_global_shortcut'): { globalShortcut: Electron.GlobalShortcut }; _linkedBinding(name: 'electron_browser_image_view'): { ImageView: any }; _linkedBinding(name: 'electron_browser_in_app_purchase'): { inAppPurchase: Electron.InAppPurchase }; - _linkedBinding(name: 'electron_browser_message_port'): { - createPair(): { port1: Electron.MessagePortMain, port2: Electron.MessagePortMain }; - }; + _linkedBinding(name: 'electron_browser_message_port'): { createPair(): { port1: Electron.MessagePortMain, port2: Electron.MessagePortMain }; }; _linkedBinding(name: 'electron_browser_native_theme'): { nativeTheme: Electron.NativeTheme }; - _linkedBinding(name: 'electron_browser_net'): { - isOnline(): boolean; - isValidHeaderName: (headerName: string) => boolean; - isValidHeaderValue: (headerValue: string) => boolean; - fileURLToFilePath: (url: string) => string; - Net: any; - net: any; - createURLLoader(options: CreateURLLoaderOptions): URLLoader; - }; - _linkedBinding(name: 'electron_browser_notification'): { - isSupported(): boolean; - Notification: typeof Electron.Notification; - } + _linkedBinding(name: 'electron_browser_notification'): NotificationBinding; _linkedBinding(name: 'electron_browser_power_monitor'): PowerMonitorBinding; _linkedBinding(name: 'electron_browser_power_save_blocker'): { powerSaveBlocker: Electron.PowerSaveBlocker }; _linkedBinding(name: 'electron_browser_push_notifications'): { pushNotifications: Electron.PushNotifications }; _linkedBinding(name: 'electron_browser_safe_storage'): { safeStorage: Electron.SafeStorage }; - _linkedBinding(name: 'electron_browser_session'): typeof Electron.Session; + _linkedBinding(name: 'electron_browser_session'): SessionBinding; _linkedBinding(name: 'electron_browser_screen'): { createScreen(): Electron.Screen }; + _linkedBinding(name: 'electron_browser_service_worker_main'): ServiceWorkerMainBinding; _linkedBinding(name: 'electron_browser_system_preferences'): { systemPreferences: Electron.SystemPreferences }; _linkedBinding(name: 'electron_browser_tray'): { Tray: Electron.Tray }; _linkedBinding(name: 'electron_browser_view'): { View: Electron.View }; _linkedBinding(name: 'electron_browser_web_contents_view'): { WebContentsView: typeof Electron.WebContentsView }; _linkedBinding(name: 'electron_browser_web_view_manager'): WebViewManagerBinding; - _linkedBinding(name: 'electron_browser_web_frame_main'): { - WebFrameMain: typeof Electron.WebFrameMain; - fromId(processId: number, routingId: number): Electron.WebFrameMain; - fromIdOrNull(processId: number, routingId: number): Electron.WebFrameMain; - } + _linkedBinding(name: 'electron_browser_web_frame_main'): WebFrameMainBinding; _linkedBinding(name: 'electron_renderer_crash_reporter'): Electron.CrashReporter; _linkedBinding(name: 'electron_renderer_ipc'): { ipc: IpcRendererBinding }; _linkedBinding(name: 'electron_renderer_web_frame'): WebFrameBinding; @@ -251,9 +251,13 @@ declare namespace NodeJS { // Additional properties _firstFileName?: string; + _serviceStartupScript: string; + _getOrCreateArchive?: (path: string) => NodeJS.AsarArchive | null; helperExecPath: string; mainModule?: NodeJS.Module | undefined; + + appCodeLoaded?: () => void; } } @@ -297,6 +301,12 @@ declare interface Window { trustedTypes: TrustedTypePolicyFactory; } +// https://github.com/electron/electron/blob/main/docs/tutorial/message-ports.md#extension-close-event + +interface MessagePort { + onclose: () => void; +} + // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types type TrustedHTML = string; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 7789f297e55e4..c7cac707b56f8 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -9,33 +9,50 @@ declare namespace Electron { enum ProcessType { browser = 'browser', renderer = 'renderer', - worker = 'worker' + worker = 'worker', + utility = 'utility' } interface App { setVersion(version: string): void; setDesktopName(name: string): void; setAppPath(path: string | null): void; + _clientCertRequestPasswordHandler: ((params: ClientCertRequestParams) => Promise) | null; + on(event: '-client-certificate-request-password', listener: (event: Event, callback: (password: string) => void) => Promise): this; + } + + interface AutoUpdater { + isVersionAllowedForUpdate?(currentVersion: string, targetVersion: string): boolean; } type TouchBarItemType = NonNullable[0]; interface BaseWindow { _init(): void; - } - - interface BrowserWindow { - _init(): void; _touchBar: Electron.TouchBar | null; _setTouchBarItems: (items: TouchBarItemType[]) => void; _setEscapeTouchBarItem: (item: TouchBarItemType | {}) => void; _refreshTouchBarItem: (itemID: string) => void; + on(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this; + removeListener(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this; + } + + interface BrowserWindow extends BaseWindow { + _init(): void; _getWindowButtonVisibility: () => boolean; + _getAlwaysOnTopLevel: () => string; + devToolsWebContents: WebContents; frameName: string; + _browserViews: BrowserView[]; on(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this; removeListener(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this; } + interface BrowserView { + ownerWindow: BrowserWindow | null + webContentsView: WebContentsView + } + interface BrowserWindowConstructorOptions { webContents?: WebContents; } @@ -46,12 +63,23 @@ declare namespace Electron { overrideGlobalValueFromIsolatedWorld(keys: string[], value: any): void; overrideGlobalValueWithDynamicPropsFromIsolatedWorld(keys: string[], value: any): void; overrideGlobalPropertyFromIsolatedWorld(keys: string[], getter: Function, setter?: Function): void; - isInMainWorld(): boolean; } } + interface ServiceWorkers { + _getWorkerFromVersionIDIfExists(versionId: number): Electron.ServiceWorkerMain | undefined; + _stopAllWorkers(): Promise; + } + + interface ServiceWorkerMain { + _startExternalRequest(hasTimeout: boolean): { id: string, ok: boolean }; + _finishExternalRequest(uuid: string): void; + _countExternalRequests(): number; + } + + interface TouchBar { - _removeFromWindow: (win: BrowserWindow) => void; + _removeFromWindow: (win: BaseWindow) => void; } interface WebContents { @@ -59,28 +87,39 @@ declare namespace Electron { getOwnerBrowserWindow(): Electron.BrowserWindow | null; getLastWebPreferences(): Electron.WebPreferences | null; _getProcessMemoryInfo(): Electron.ProcessMemoryInfo; - _getPreloadPaths(): string[]; + _getPreloadScript(): Electron.PreloadScript | null; equal(other: WebContents): boolean; browserWindowOptions: BrowserWindowConstructorOptions; _windowOpenHandler: ((details: Electron.HandlerDetails) => any) | null; - _callWindowOpenHandler(event: any, details: Electron.HandlerDetails): {browserWindowConstructorOptions: Electron.BrowserWindowConstructorOptions | null, outlivesOpener: boolean}; + _callWindowOpenHandler(event: any, details: Electron.HandlerDetails): {browserWindowConstructorOptions: Electron.BrowserWindowConstructorOptions | null, outlivesOpener: boolean, createWindow?: Electron.CreateWindowFunction}; _setNextChildWebPreferences(prefs: Partial & Pick): void; _send(internal: boolean, channel: string, args: any): boolean; _sendInternal(channel: string, ...args: any[]): void; _printToPDF(options: any): Promise; _print(options: any, callback?: (success: boolean, failureReason: string) => void): void; - _getPrinters(): Electron.PrinterInfo[]; _getPrintersAsync(): Promise; _init(): void; + _getNavigationEntryAtIndex(index: number): Electron.NavigationEntry | null; + _getActiveIndex(): number; + _historyLength(): number; + _canGoBack(): boolean; + _canGoForward(): boolean; + _canGoToOffset(index: number): boolean; + _goBack(): void; + _goForward(): void; + _goToOffset(index: number): void; + _goToIndex(index: number): void; + _removeNavigationEntryAtIndex(index: number): boolean; + _getHistory(): Electron.NavigationEntry[]; + _clearHistory():void canGoToIndex(index: number): boolean; - getActiveIndex(): number; - length(): number; destroy(): void; // attachToIframe(embedderWebContents: Electron.WebContents, embedderFrameId: number): void; detachFromOuterFrame(): void; setEmbedder(embedder: Electron.WebContents): void; viewInstanceId: number; + _setOwnerWindow(w: BaseWindow | null): void; } interface WebFrameMain { @@ -99,6 +138,12 @@ declare namespace Electron { type?: 'backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'; } + interface Session { + _setDisplayMediaRequestHandler: Electron.Session['setDisplayMediaRequestHandler']; + } + + type CreateWindowFunction = (options: BrowserWindowConstructorOptions) => WebContents; + interface Menu { _init(): void; _isCommandIdChecked(id: string): boolean; @@ -109,12 +154,12 @@ declare namespace Electron { _shouldRegisterAcceleratorForCommandId(id: string): boolean; _getSharingItemForCommandId(id: string): SharingItem | null; _callMenuWillShow(): void; - _executeCommand(event: any, id: number): void; + _executeCommand(event: KeyboardEvent, id: number): void; _menuWillShow(): void; commandsMap: Record; groupsMap: Record; getItemCount(): number; - popupAt(window: BaseWindow, x: number, y: number, positioning: number, callback: () => void): void; + popupAt(window: BaseWindow, x: number, y: number, positioning: number, sourceType: Required['sourceType'], callback: () => void): void; closePopupAt(id: number): void; setSublabel(index: number, label: string): void; setToolTip(index: number, tooltip: string): void; @@ -137,36 +182,18 @@ declare namespace Electron { acceleratorWorksWhenHidden?: boolean; } - interface IpcMainEvent { - sendReply(value: any): void; - } - - interface IpcMainInvokeEvent { + interface ReplyChannel { sendReply(value: any): void; - _reply(value: any): void; - _throw(error: Error | string): void; } - const deprecate: ElectronInternal.DeprecationUtil; - - namespace Main { - const deprecate: ElectronInternal.DeprecationUtil; + interface IpcMainEvent { + _replyChannel: ReplyChannel; + frameTreeNodeId?: number; } - class View {} - - // Experimental views API - class BaseWindow { - constructor(args: {show: boolean}) - setContentView(view: View): void - static fromId(id: number): BaseWindow; - static getAllWindows(): BaseWindow[]; - isFocused(): boolean; - static getFocusedWindow(): BaseWindow | undefined; - setMenu(menu: Menu): void; - } - class WebContentsView { - constructor(options: BrowserWindowConstructorOptions) + interface IpcMainInvokeEvent { + _replyChannel: ReplyChannel; + frameTreeNodeId?: number; } // Deprecated / undocumented BrowserWindow methods @@ -185,29 +212,40 @@ declare namespace Electron { setBackgroundThrottling(allowed: boolean): void; } - namespace Main { - class BaseWindow extends Electron.BaseWindow {} - class View extends Electron.View {} - class WebContentsView extends Electron.WebContentsView {} + interface Protocol { + registerProtocol(scheme: string, handler: any): boolean; + interceptProtocol(scheme: string, handler: any): boolean; } -} -declare namespace ElectronInternal { - type DeprecationHandler = (message: string) => void; - interface DeprecationUtil { - warnOnce(oldName: string, newName?: string): () => void; - setHandler(handler: DeprecationHandler | null): void; - getHandler(): DeprecationHandler | null; - warn(oldName: string, newName: string): void; - log(message: string): void; - removeFunction(fn: T, removedName: string): T; - renameFunction(fn: T, newName: string): T; - event(emitter: NodeJS.EventEmitter, oldName: string, newName: string): void; - removeProperty(object: T, propertyName: K, onlyForValues?: any[]): T; - renameProperty(object: T, oldName: string, newName: K): T; - moveAPI(fn: T, oldUsage: string, newUsage: string): T; + interface WebContents { + on(event: '-new-window', listener: (event: Electron.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'], + rawFeatures: string, referrer: Electron.Referrer, postData: LoadURLOptions['postData']) => void): this; + on(event: '-add-new-contents', listener: (event: Event, webContents: Electron.WebContents, disposition: string, + _userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string, + referrer: Electron.Referrer, rawFeatures: string, postData: LoadURLOptions['postData']) => void): this; + on(event: '-will-add-new-contents', listener: (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: LoadURLOptions['postData']) => void): this; + on(event: '-ipc-message', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) => void): this; + on(event: '-ipc-message-sync', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) => void): this; + on(event: '-ipc-invoke', listener: (event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) => void): this; + on(event: '-ipc-ports', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) => void): this; + on(event: '-run-dialog', listener: (info: {frame: WebFrameMain, dialogType: 'prompt' | 'confirm' | 'alert', messageText: string, defaultPromptText: string}, callback: (success: boolean, user_input: string) => void) => void): this; + on(event: '-cancel-dialogs', listener: () => void): this; + on(event: 'ready-to-show', listener: () => void): this; + on(event: '-before-unload-fired', listener: (event: Electron.Event, proceed: boolean) => void): this; + + on(event: '-window-visibility-change', listener: (visibilityState: 'hidden' | 'visible') => void): this; + removeListener(event: '-window-visibility-change', listener: (visibilityState: 'hidden' | 'visible') => void): this; + + once(event: 'destroyed', listener: (event: Electron.Event) => void): this; + } + + interface WebContentsWillFrameNavigateEventParams { + processId: number; + routingId: number; } +} +declare namespace ElectronInternal { interface DesktopCapturer { startHandling(captureWindow: boolean, captureScreen: boolean, thumbnailSize: Electron.Size, fetchWindowIcons: boolean): void; _onerror?: (error: string) => void; @@ -242,10 +280,6 @@ declare namespace ElectronInternal { once(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this; } - interface Event extends Electron.Event { - sender: WebContents; - } - interface LoadURLOptions extends Electron.LoadURLOptions { reloadIgnoringCache?: boolean; } @@ -259,6 +293,10 @@ declare namespace ElectronInternal { custom_display_name: string, height_microns: number, width_microns: number, + imageable_area_left_microns?: number, + imageable_area_bottom_microns?: number, + imageable_area_right_microns?: number, + imageable_area_top_microns?: number, is_default?: 'true', } @@ -271,10 +309,21 @@ declare namespace ElectronInternal { interface ModuleEntry { name: string; - private?: boolean; loader: ModuleLoader; } + interface UtilityProcessWrapper extends NodeJS.EventEmitter { + readonly pid: (number) | (undefined); + kill(): boolean; + postMessage(message: any, transfer?: any[]): void; + } + + interface ParentPort extends NodeJS.EventEmitter { + start(): void; + pause(): void; + postMessage(message: any): void; + } + class WebViewElement extends HTMLElement { static observedAttributes: Array; @@ -290,7 +339,12 @@ declare namespace ElectronInternal { } class WebContents extends Electron.WebContents { - static create(opts: Electron.WebPreferences): Electron.WebContents; + static create(opts?: Electron.WebPreferences): Electron.WebContents; + } + + interface PreloadScript extends Electron.PreloadScript { + contents?: string; + error?: Error; } } diff --git a/yarn.lock b/yarn.lock index c9adc494cf72f..f7cfa58f0c4c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,39 +9,48 @@ dependencies: tslib "^2.0.0" +"@azure/abort-controller@^2.0.0", "@azure/abort-controller@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz#42fe0ccab23841d9905812c58f1082d27784566d" + integrity sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA== + dependencies: + tslib "^2.6.2" + "@azure/core-asynciterator-polyfill@^1.0.0": version "1.0.2" resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz#0dd3849fb8d97f062a39db0e5cadc9ffaf861fec" integrity sha512-3rkP4LnnlWawl0LZptJOdXNrT/fHp2eQMadoasa6afspXdpGrtPZuAQc2PD0cpgyuoXtUWyC3tv7xfntjGS5Dw== -"@azure/core-auth@^1.3.0": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.3.2.tgz#6a2c248576c26df365f6c7881ca04b7f6d08e3d0" - integrity sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA== - dependencies: - "@azure/abort-controller" "^1.0.0" - tslib "^2.2.0" +"@azure/core-auth@^1.4.0", "@azure/core-auth@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.8.0.tgz#281b4a6d3309c3e7b15bcd967f01d4c79ae4a1d6" + integrity sha512-YvFMowkXzLbXNM11yZtVLhUCmuG0ex7JKOH366ipjmHBhL3vpDcPAeWF+jf0X+jVXwFqo3UhsWUq4kH0ZPdu/g== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-util" "^1.1.0" + tslib "^2.6.2" + +"@azure/core-client@^1.3.0", "@azure/core-client@^1.6.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.2.tgz#6fc69cee2816883ab6c5cdd653ee4f2ff9774f74" + integrity sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.4.0" + "@azure/core-rest-pipeline" "^1.9.1" + "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.6.1" + "@azure/logger" "^1.0.0" + tslib "^2.6.2" -"@azure/core-http@^2.0.0": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@azure/core-http/-/core-http-2.2.4.tgz#df5a5b4138dbbc4299879f2fc6f257d0a5f0401e" - integrity sha512-QmmJmexXKtPyc3/rsZR/YTLDvMatzbzAypJmLzvlfxgz/SkgnqV/D4f6F2LsK6tBj1qhyp8BoXiOebiej0zz3A== +"@azure/core-http-compat@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz#d1585ada24ba750dc161d816169b33b35f762f0d" + integrity sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ== dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-asynciterator-polyfill" "^1.0.0" - "@azure/core-auth" "^1.3.0" - "@azure/core-tracing" "1.0.0-preview.13" - "@azure/logger" "^1.0.0" - "@types/node-fetch" "^2.5.0" - "@types/tunnel" "^0.0.3" - form-data "^4.0.0" - node-fetch "^2.6.7" - process "^0.11.10" - tough-cookie "^4.0.0" - tslib "^2.2.0" - tunnel "^0.0.6" - uuid "^8.3.0" - xml2js "^0.4.19" + "@azure/abort-controller" "^2.0.0" + "@azure/core-client" "^1.3.0" + "@azure/core-rest-pipeline" "^1.3.0" "@azure/core-lro@^2.2.0": version "2.2.4" @@ -61,6 +70,20 @@ "@azure/core-asynciterator-polyfill" "^1.0.0" tslib "^2.2.0" +"@azure/core-rest-pipeline@^1.10.1", "@azure/core-rest-pipeline@^1.3.0", "@azure/core-rest-pipeline@^1.9.1": + version "1.17.0" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz#55dafa1093553c549ed6d8dbca69aa505c7b3aa3" + integrity sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.8.0" + "@azure/core-tracing" "^1.0.1" + "@azure/core-util" "^1.9.0" + "@azure/logger" "^1.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + tslib "^2.6.2" + "@azure/core-tracing@1.0.0-preview.13": version "1.0.0-preview.13" resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz#55883d40ae2042f6f1e12b17dd0c0d34c536d644" @@ -69,6 +92,29 @@ "@opentelemetry/api" "^1.0.1" tslib "^2.2.0" +"@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1", "@azure/core-tracing@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.1.2.tgz#065dab4e093fb61899988a1cdbc827d9ad90b4ee" + integrity sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA== + dependencies: + tslib "^2.6.2" + +"@azure/core-util@^1.1.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.9.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.10.0.tgz#cf3163382d40343972848c914869864df5d44bdb" + integrity sha512-dqLWQsh9Nro1YQU+405POVtXnwrIVqPyfUzc4zXCbThTg7+vNNaiMkwbX9AMXKyoFYFClxmB3s25ZFr3+jZkww== + dependencies: + "@azure/abort-controller" "^2.0.0" + tslib "^2.6.2" + +"@azure/core-xml@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@azure/core-xml/-/core-xml-1.4.3.tgz#a74f37a0e584fee7e9adae19f51016d4b59e9ca2" + integrity sha512-D6G7FEmDiTctPKuWegX2WTrS1enKZwqYwdKTO6ZN6JMigcCehlT0/CYl+zWpI9vQ9frwwp7GQT3/owaEXgnOsA== + dependencies: + fast-xml-parser "^4.3.2" + tslib "^2.6.2" + "@azure/logger@^1.0.0": version "1.0.3" resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.0.3.tgz#6e36704aa51be7d4a1bae24731ea580836293c96" @@ -76,16 +122,21 @@ dependencies: tslib "^2.2.0" -"@azure/storage-blob@^12.9.0": - version "12.9.0" - resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.9.0.tgz#4cbd8b4c7a47dd064867430db892f4ef2d8f17ab" - integrity sha512-ank38FdCLfJ+EoeMzCz3hkYJuZAd63ARvDKkxZYRDb+beBYf+/+gx8jNTqkq/hfyUl4dJQ/a7tECU0Y0F98CHg== +"@azure/storage-blob@^12.25.0": + version "12.25.0" + resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.25.0.tgz#fa9a1d2456cdf6526450a8b73059d2f2e9b1ec76" + integrity sha512-oodouhA3nCCIh843tMMbxty3WqfNT+Vgzj3Xo5jqR9UPnzq3d7mzLjlHAYz7lW+b4km3SIgz+NAgztvhm7Z6kQ== dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-http" "^2.0.0" + "@azure/abort-controller" "^2.1.2" + "@azure/core-auth" "^1.4.0" + "@azure/core-client" "^1.6.2" + "@azure/core-http-compat" "^2.0.0" "@azure/core-lro" "^2.2.0" "@azure/core-paging" "^1.1.1" - "@azure/core-tracing" "1.0.0-preview.13" + "@azure/core-rest-pipeline" "^1.10.1" + "@azure/core-tracing" "^1.1.2" + "@azure/core-util" "^1.6.1" + "@azure/core-xml" "^1.4.3" "@azure/logger" "^1.0.0" events "^3.0.0" tslib "^2.2.0" @@ -97,6 +148,24 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.21.4": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.24.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + "@babel/highlight@^7.0.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" @@ -106,219 +175,640 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@electron/docs-parser@^0.12.4": - version "0.12.4" - resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.12.4.tgz#cca403c8c2200181339c3115cdd25f3fbfc7dea3" - integrity sha512-vdkjcvkI7zTd2v1A8qsl5+HY+9AQCrW5Eh60I9rhPtUPoxo2V1pQwogTW6kzc3XZ54crTa7R3KxwkZpSbcGCug== +"@dsanders11/vscode-markdown-languageservice@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@dsanders11/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.3.0.tgz#18a561711609651371961b66db4cb8473ab25564" + integrity sha512-aFNWtK23dNicyLczBwIKkGUSVuMoZMzUovlwqj/hVZ3zRIBlXWYunByDxI67Pf1maA0TbxPjVfRqBQFALWjVHg== dependencies: - "@types/markdown-it" "^10.0.0" - chai "^4.2.0" - chalk "^3.0.0" - fs-extra "^8.1.0" - lodash.camelcase "^4.3.0" - markdown-it "^10.0.0" - minimist "^1.2.0" - ora "^4.0.3" - pretty-ms "^5.1.0" + "@vscode/l10n" "^0.0.10" + picomatch "^2.3.1" + vscode-languageserver-textdocument "^1.0.5" + vscode-languageserver-types "^3.17.1" + vscode-uri "^3.0.3" -"@electron/typescript-definitions@^8.9.5": - version "8.9.5" - resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.9.5.tgz#e6cb08e0e7c9656e178b892eab50866a8a80bf7a" - integrity sha512-xDLFl6joGpA8c9cGSPWC3DFHyIGf9+OWZmDrPbGJW1URt6C1ukdQWKSmjb1Rttb94QQxBrGuUlSyz27IQgLFsw== +"@electron/asar@^3.2.13": + version "3.2.13" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.13.tgz#56565ea423ead184465adfa72663b2c70d9835f2" + integrity sha512-pY5z2qQSwbFzJsBdgfJIzXf5ElHTVMutC2dxh0FD60njknMu3n1NnTABOcQwbb5/v5soqE79m9UjaJryBf3epg== + dependencies: + "@types/glob" "^7.1.0" + commander "^5.0.0" + glob "^7.1.6" + minimatch "^3.0.4" + +"@electron/docs-parser@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-2.0.0.tgz#b82ff30c0df0be41f83622a0497b0f04f7297686" + integrity sha512-4yQELWBXQFdst9udJyL+ubqB9Ig61gvFpHG3V8uJzAILzMjAGCTCED60mL4MGRJ6vTGg9dkp/wcMVw1vd7bAig== + dependencies: + "@types/markdown-it" "^14.1.2" + chai "^5.1.1" + chalk "^5.3.0" + lodash.camelcase "^4.3.0" + markdown-it "^14.1.0" + ora "^8.1.0" + pretty-ms "^9.1.0" + +"@electron/fiddle-core@^1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@electron/fiddle-core/-/fiddle-core-1.3.4.tgz#29141a97ed0ec7ed1a96ee8bdcaacb60e1a39622" + integrity sha512-jjkZ1TTuyui/ZsEbUbrTllL5SUe1wIt91WANQTpiAygThcceQKy1756PUwHSy0WRKFL0VIke+WU+ki01vEVpQg== + dependencies: + "@electron/get" "^2.0.0" + debug "^4.3.3" + env-paths "^2.2.1" + extract-zip "^2.0.1" + fs-extra "^10.0.0" + getos "^3.2.1" + node-fetch "^2.6.1" + rimraf "^4.4.1" + semver "^7.3.5" + simple-git "^3.5.0" + +"@electron/get@^2.0.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@electron/get/-/get-2.0.2.tgz#ae2a967b22075e9c25aaf00d5941cd79c21efd7e" + integrity sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g== dependencies: - "@types/node" "^11.13.7" - chalk "^2.4.2" - colors "^1.1.2" debug "^4.1.1" - fs-extra "^7.0.1" - lodash "^4.17.11" - minimist "^1.2.0" - mkdirp "^0.5.1" - ora "^3.4.0" - pretty-ms "^5.0.0" + env-paths "^2.2.0" + fs-extra "^8.1.0" + got "^11.8.5" + progress "^2.0.3" + semver "^6.2.0" + sumchecker "^3.0.1" + optionalDependencies: + global-agent "^3.0.0" -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== +"@electron/github-app-auth@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@electron/github-app-auth/-/github-app-auth-2.2.1.tgz#ee43ee7495717ff1a459b60f486384a3f584e955" + integrity sha512-CRacgsDnkWIbvdo80XTq5+//CnVzWl1Hd5rVaj7MEZ1B44NwGbh2G9KxzWToOaCCCa09mYIKkHHqLAKUXEc7NA== dependencies: - "@jridgewell/set-array" "^1.0.1" + "@octokit/auth-app" "^4.0.13" + "@octokit/rest" "^19.0.11" + +"@electron/lint-roller@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@electron/lint-roller/-/lint-roller-2.4.0.tgz#67ab5911400ec1e6a842153acc59613a9522d233" + integrity sha512-U1FDBpNxVbu9TlL8O0F9mmaEimINtdr6RB6gGNVm1aBqOvLs579w0k4aqyYqDIV20HHcuWh/287sll6ou8Pfcw== + dependencies: + "@dsanders11/vscode-markdown-languageservice" "^0.3.0" + ajv "^8.16.0" + balanced-match "^2.0.0" + glob "^8.1.0" + hast-util-from-html "^2.0.1" + markdown-it "^13.0.1" + markdownlint-cli "^0.40.0" + mdast-util-from-markdown "^1.3.0" + minimist "^1.2.8" + rimraf "^4.4.1" + standard "^17.0.0" + unist-util-visit "^4.1.2" + vscode-languageserver "^8.1.0" + vscode-languageserver-textdocument "^1.0.8" + vscode-uri "^3.0.7" + yaml "^2.4.5" + +"@electron/typescript-definitions@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-9.0.0.tgz#1a8d9f36711ad93643af0662eef917189725c354" + integrity sha512-sK/e5ewiHZnpy0jzFW2NmH8KATkprwG962JzxJYw/GphxG/V55mP7UPJirmYUPeOA87TWhL910sjp5gdZ1SQmg== + dependencies: + "@types/node" "^20.11.25" + chalk "^5.3.0" + debug "^4.3.7" + lodash "^4.17.11" + ora "^8.1.0" + pretty-ms "^9.1.0" + +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.6.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + 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" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + 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" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.14" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" - integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@kwsites/file-exists@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" + integrity sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw== dependencies: - "@nodelib/fs.stat" "2.0.3" + debug "^4.1.1" + +"@kwsites/promise-deferred@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz#8ace5259254426ccef57f3175bc64ed7095ed919" + integrity sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.stat@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== -"@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@octokit/auth-app@^2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-app/-/auth-app-2.10.0.tgz#ad79369fca1cc3035859f797310d5e81cc6e49c4" - integrity sha512-mKFU7O5wI651iWgecs4fmJ2aLqOM3sWD1FJsUTm7nx21I4ePDhS+rGQmS5TZk5yz75Va6wEXesxUNFzuqCbP2A== +"@npmcli/config@^8.0.0": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-8.3.4.tgz#e2712c2215bb2659f39718b23bf7401f9ac1da59" + integrity sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw== + dependencies: + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/package-json" "^5.1.1" + ci-info "^4.0.0" + ini "^4.1.2" + nopt "^7.2.1" + proc-log "^4.2.0" + semver "^7.3.5" + walk-up-path "^3.0.1" + +"@npmcli/git@^5.0.0": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-5.0.8.tgz#8ba3ff8724192d9ccb2735a2aa5380a992c5d3d1" + integrity sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ== + dependencies: + "@npmcli/promise-spawn" "^7.0.0" + ini "^4.1.3" + lru-cache "^10.0.1" + npm-pick-manifest "^9.0.0" + proc-log "^4.0.0" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^4.0.0" + +"@npmcli/map-workspaces@^3.0.2": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz#27dc06c20c35ef01e45a08909cab9cb3da08cea6" + integrity sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA== + dependencies: + "@npmcli/name-from-folder" "^2.0.0" + glob "^10.2.2" + minimatch "^9.0.0" + read-package-json-fast "^3.0.0" + +"@npmcli/name-from-folder@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815" + integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg== + +"@npmcli/package-json@^5.1.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-5.2.1.tgz#df69477b1023b81ff8503f2b9db4db4faea567ed" + integrity sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ== + dependencies: + "@npmcli/git" "^5.0.0" + glob "^10.2.2" + hosted-git-info "^7.0.0" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + proc-log "^4.0.0" + semver "^7.5.3" + +"@npmcli/promise-spawn@^7.0.0": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz#1d53d34ffeb5d151bfa8ec661bcccda8bbdfd532" + integrity sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ== dependencies: - "@octokit/request" "^5.3.0" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^5.0.0" - "@types/lru-cache" "^5.1.0" + which "^4.0.0" + +"@octokit/auth-app@^4.0.13": + version "4.0.13" + resolved "https://registry.yarnpkg.com/@octokit/auth-app/-/auth-app-4.0.13.tgz#53323bee6bfefbb73ea544dd8e6a0144550e13e3" + integrity sha512-NBQkmR/Zsc+8fWcVIFrwDgNXS7f4XDrkd9LHdi9DPQw1NdGHLviLzRO2ZBwTtepnwHXW5VTrVU9eFGijMUqllg== + dependencies: + "@octokit/auth-oauth-app" "^5.0.0" + "@octokit/auth-oauth-user" "^2.0.0" + "@octokit/request" "^6.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^9.0.0" deprecation "^2.3.1" - lru-cache "^6.0.0" - universal-github-app-jwt "^1.0.1" + lru-cache "^9.0.0" + universal-github-app-jwt "^1.1.1" universal-user-agent "^6.0.0" -"@octokit/auth-token@^2.4.0": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a" - integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ== +"@octokit/auth-oauth-app@^5.0.0": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-5.0.5.tgz#be2a93d72835133b4866ac4721aa628849475525" + integrity sha512-UPX1su6XpseaeLVCi78s9droxpGtBWIgz9XhXAx9VXabksoF0MyI5vaa1zo1njyYt6VaAjFisC2A2Wchcu2WmQ== + dependencies: + "@octokit/auth-oauth-device" "^4.0.0" + "@octokit/auth-oauth-user" "^2.0.0" + "@octokit/request" "^6.0.0" + "@octokit/types" "^9.0.0" + "@types/btoa-lite" "^1.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" + +"@octokit/auth-oauth-device@^4.0.0": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-4.0.3.tgz#00ce77233517e0d7d39e42a02652f64337d9df81" + integrity sha512-KPTx5nMntKjNZzzltO3X4T68v22rd7Cp/TcLJXQE2U8aXPcZ9LFuww9q9Q5WUNSu3jwi3lRwzfkPguRfz1R8Vg== dependencies: - "@octokit/types" "^5.0.0" + "@octokit/oauth-methods" "^2.0.0" + "@octokit/request" "^6.0.0" + "@octokit/types" "^8.0.0" + universal-user-agent "^6.0.0" -"@octokit/core@^3.0.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.1.1.tgz#1856745aa8fb154cf1544a2a1b82586c809c5e66" - integrity sha512-cQ2HGrtyNJ1IBxpTP1U5m/FkMAJvgw7d2j1q3c9P0XUuYilEgF6e4naTpsgm4iVcQeOnccZlw7XHRIUBy0ymcg== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/graphql" "^4.3.1" - "@octokit/request" "^5.4.0" - "@octokit/types" "^5.0.0" - before-after-hook "^2.1.0" +"@octokit/auth-oauth-user@^2.0.0": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-2.0.4.tgz#88f060ec678d7d493695af8d827e115dd064e212" + integrity sha512-HrbDzTPqz6GcGSOUkR+wSeF3vEqsb9NMsmPja/qqqdiGmlk/Czkxctc3KeWYogHonp62Ml4kjz2VxKawrFsadQ== + dependencies: + "@octokit/auth-oauth-device" "^4.0.0" + "@octokit/oauth-methods" "^2.0.0" + "@octokit/request" "^6.0.0" + "@octokit/types" "^8.0.0" + btoa-lite "^1.0.0" universal-user-agent "^6.0.0" -"@octokit/endpoint@^6.0.1": - version "6.0.5" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.5.tgz#43a6adee813c5ffd2f719e20cfd14a1fee7c193a" - integrity sha512-70K5u6zd45ItOny6aHQAsea8HHQjlQq85yqOMe+Aj8dkhN2qSJ9T+Q3YjUjEYfPRBcuUWNgMn62DQnP/4LAIiQ== +"@octokit/auth-token@^3.0.0": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.3.tgz#ce7e48a3166731f26068d7a7a7996b5da58cbe0c" + integrity sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA== dependencies: - "@octokit/types" "^5.0.0" - is-plain-object "^4.0.0" + "@octokit/types" "^9.0.0" + +"@octokit/auth-token@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" + integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== + +"@octokit/core@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.1.tgz#fee6341ad0ce60c29cc455e056cd5b500410a588" + integrity sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw== + dependencies: + "@octokit/auth-token" "^3.0.0" + "@octokit/graphql" "^5.0.0" + "@octokit/request" "^6.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^9.0.0" + before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/graphql@^4.3.1": - version "4.5.3" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.5.3.tgz#d5ff0d4a8a33e98614a2a7359dac98bc285e062f" - integrity sha512-JyYvi3j2tOb5ofASEpcg1Advs07H+Ag+I+ez7buuZfNVAmh1IYcDTuxd4gnYH8S2PSGu+f5IdDGxMmkK+5zsdA== +"@octokit/core@^5.0.2": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.2.0.tgz#ddbeaefc6b44a39834e1bb2e58a49a117672a7ea" + integrity sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg== + dependencies: + "@octokit/auth-token" "^4.0.0" + "@octokit/graphql" "^7.1.0" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.0.0" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^7.0.0": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.3.tgz#0b96035673a9e3bedf8bab8f7335de424a2147ed" + integrity sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw== dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^5.0.0" + "@octokit/types" "^8.0.0" + is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/plugin-paginate-rest@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.3.0.tgz#7d1073e56cfd15d3f99dcfe81fa5d2b466f3a6f6" - integrity sha512-Ye2ZJreP0ZlqJQz8fz+hXvrEAEYK4ay7br1eDpWzr6j76VXs/gKqxFcH8qRzkB3fo/2xh4Vy9VtGii4ZDc9qlA== +"@octokit/endpoint@^9.0.1": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" + integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== dependencies: - "@octokit/types" "^5.2.0" + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" -"@octokit/plugin-request-log@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" - integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw== +"@octokit/graphql@^5.0.0": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.5.tgz#a4cb3ea73f83b861893a6370ee82abb36e81afd2" + integrity sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ== + dependencies: + "@octokit/request" "^6.0.0" + "@octokit/types" "^9.0.0" + universal-user-agent "^6.0.0" -"@octokit/plugin-rest-endpoint-methods@4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.2.tgz#546a8f3e0b514f434a4ad4ef926005f1c81a5a5a" - integrity sha512-PTI7wpbGEZ2IR87TVh+TNWaLcgX/RsZQalFbQCq8XxYUrQ36RHyERrHSNXFy5gkWpspUAOYRSV707JJv6BhqJA== +"@octokit/graphql@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.1.0.tgz#9bc1c5de92f026648131f04101cab949eeffe4e0" + integrity sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ== + dependencies: + "@octokit/request" "^8.3.0" + "@octokit/types" "^13.0.0" + universal-user-agent "^6.0.0" + +"@octokit/oauth-authorization-url@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz#029626ce87f3b31addb98cd0d2355c2381a1c5a1" + integrity sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg== + +"@octokit/oauth-methods@^2.0.0": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-2.0.4.tgz#6abd9593ca7f91fe5068375a363bd70abd5516dc" + integrity sha512-RDSa6XL+5waUVrYSmOlYROtPq0+cfwppP4VaQY/iIei3xlFb0expH6YNsxNrZktcLhJWSpm9uzeom+dQrXlS3A== + dependencies: + "@octokit/oauth-authorization-url" "^5.0.0" + "@octokit/request" "^6.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^8.0.0" + btoa-lite "^1.0.0" + +"@octokit/openapi-types@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-14.0.0.tgz#949c5019028c93f189abbc2fb42f333290f7134a" + integrity sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw== + +"@octokit/openapi-types@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-16.0.0.tgz#d92838a6cd9fb4639ca875ddb3437f1045cc625e" + integrity sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA== + +"@octokit/openapi-types@^17.2.0": + version "17.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-17.2.0.tgz#f1800b5f9652b8e1b85cc6dfb1e0dc888810bdb5" + integrity sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ== + +"@octokit/openapi-types@^22.2.0": + version "22.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-22.2.0.tgz#75aa7dcd440821d99def6a60b5f014207ae4968e" + integrity sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg== + +"@octokit/plugin-paginate-rest@11.3.1": + version "11.3.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.1.tgz#fe92d04b49f134165d6fbb716e765c2f313ad364" + integrity sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g== + dependencies: + "@octokit/types" "^13.5.0" + +"@octokit/plugin-paginate-rest@^6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz#f86456a7a1fe9e58fec6385a85cf1b34072341f8" + integrity sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ== + dependencies: + "@octokit/tsconfig" "^1.0.2" + "@octokit/types" "^9.2.3" + +"@octokit/plugin-request-log@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== + +"@octokit/plugin-request-log@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz#98a3ca96e0b107380664708111864cb96551f958" + integrity sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA== + +"@octokit/plugin-rest-endpoint-methods@13.2.2": + version "13.2.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.2.tgz#af8e5dd2cddfea576f92ffaf9cb84659f302a638" + integrity sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA== dependencies: - "@octokit/types" "^5.1.1" + "@octokit/types" "^13.5.0" + +"@octokit/plugin-rest-endpoint-methods@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.1.2.tgz#b77a8844601d3a394a02200cddb077f3ab841f38" + integrity sha512-R0oJ7j6f/AdqPLtB9qRXLO+wjI9pctUn8Ka8UGfGaFCcCv3Otx14CshQ89K4E88pmyYZS8p0rNTiprML/81jig== + dependencies: + "@octokit/types" "^9.2.3" deprecation "^2.3.1" -"@octokit/request-error@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0" - integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw== +"@octokit/request-error@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.2.tgz#f74c0f163d19463b87528efe877216c41d6deb0a" + integrity sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg== dependencies: - "@octokit/types" "^5.0.1" + "@octokit/types" "^8.0.0" deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.3.0", "@octokit/request@^5.4.0": - version "5.4.7" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.7.tgz#fd703ee092e0463ceba49ff7a3e61cb4cf8a0fde" - integrity sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A== +"@octokit/request-error@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" + integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^5.0.0" + "@octokit/types" "^13.1.0" deprecation "^2.0.0" - is-plain-object "^4.0.0" - node-fetch "^2.3.0" once "^1.4.0" + +"@octokit/request@^6.0.0": + version "6.2.4" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.4.tgz#b00a7185865c72bdd432e63168b1e900953ded0c" + integrity sha512-at92SYQstwh7HH6+Kf3bFMnHrle7aIrC0r5rTP+Bb30118B6j1vI2/M4walh6qcQgfuLIKs8NUO5CytHTnUI3A== + dependencies: + "@octokit/endpoint" "^7.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^9.0.0" + is-plain-object "^5.0.0" + node-fetch "^2.6.7" universal-user-agent "^6.0.0" -"@octokit/rest@^18.0.3": - version "18.0.3" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.0.3.tgz#96a15ddb3a38dca5de9d75121378d6aa4a234fa5" - integrity sha512-GubgemnLvUJlkhouTM2BtX+g/voYT/Mqh0SASGwTnLvSkW1irjt14N911/ABb6m1Hru0TwScOgFgMFggp3igfQ== +"@octokit/request@^8.3.0", "@octokit/request@^8.3.1": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" + integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== dependencies: - "@octokit/core" "^3.0.0" - "@octokit/plugin-paginate-rest" "^2.2.0" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "4.1.2" + "@octokit/endpoint" "^9.0.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" -"@octokit/types@^5.0.0", "@octokit/types@^5.0.1", "@octokit/types@^5.1.1", "@octokit/types@^5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.2.0.tgz#d075dc23bf293f540739250b6879e2c1be2fc20c" - integrity sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A== +"@octokit/rest@^19.0.11": + version "19.0.11" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.11.tgz#2ae01634fed4bd1fca5b642767205ed3fd36177c" + integrity sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw== dependencies: - "@types/node" ">= 8" + "@octokit/core" "^4.2.1" + "@octokit/plugin-paginate-rest" "^6.1.2" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^7.1.2" + +"@octokit/rest@^20.0.2": + version "20.1.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-20.1.1.tgz#ec775864f53fb42037a954b9a40d4f5275b3dc95" + integrity sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw== + dependencies: + "@octokit/core" "^5.0.2" + "@octokit/plugin-paginate-rest" "11.3.1" + "@octokit/plugin-request-log" "^4.0.0" + "@octokit/plugin-rest-endpoint-methods" "13.2.2" + +"@octokit/tsconfig@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@octokit/tsconfig/-/tsconfig-1.0.2.tgz#59b024d6f3c0ed82f00d08ead5b3750469125af7" + integrity sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA== + +"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" + integrity sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ== + dependencies: + "@octokit/openapi-types" "^22.2.0" + +"@octokit/types@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-8.0.0.tgz#93f0b865786c4153f0f6924da067fe0bb7426a9f" + integrity sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg== + dependencies: + "@octokit/openapi-types" "^14.0.0" + +"@octokit/types@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.0.0.tgz#6050db04ddf4188ec92d60e4da1a2ce0633ff635" + integrity sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw== + dependencies: + "@octokit/openapi-types" "^16.0.0" + +"@octokit/types@^9.2.3": + version "9.2.3" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.2.3.tgz#d0af522f394d74b585cefb7efd6197ca44d183a9" + integrity sha512-MMeLdHyFIALioycq+LFcA71v0S2xpQUX2cw6pPbHQjaibcHYwLnmK/kMZaWuGfGfjBJZ3wRUq+dOaWsvrPJVvA== + dependencies: + "@octokit/openapi-types" "^17.2.0" "@opentelemetry/api@^1.0.1": version "1.0.4" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924" integrity sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@primer/octicons@^10.0.0": version "10.0.0" resolved "https://registry.yarnpkg.com/@primer/octicons/-/octicons-10.0.0.tgz#81e94ed32545dfd3472c8625a5b345f3ea4c153d" @@ -326,22 +816,20 @@ dependencies: object-assign "^4.1.1" -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" +"@sindresorhus/merge-streams@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" + integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== "@szmarczak/http-timer@^4.0.5": version "4.0.6" @@ -350,27 +838,10 @@ dependencies: defer-to-connect "^2.0.0" -"@types/basic-auth@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@types/basic-auth/-/basic-auth-1.1.3.tgz#a787ede8310804174fbbf3d6c623ab1ccedb02cd" - integrity sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg== - dependencies: - "@types/node" "*" - -"@types/body-parser@*": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" - integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== - dependencies: - "@types/connect" "*" - "@types/node" "*" - -"@types/busboy@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@types/busboy/-/busboy-0.2.3.tgz#6697ad29873246c530f09a3ff5a40861824230d5" - integrity sha1-ZpetKYcyRsUw8Jo/9aQIYYJCMNU= - dependencies: - "@types/node" "*" +"@types/btoa-lite@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.0.tgz#e190a5a548e0b348adb0df9ac7fa5f1151c7cca4" + integrity sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg== "@types/cacheable-request@^6.0.1": version "6.0.2" @@ -382,46 +853,15 @@ "@types/node" "*" "@types/responselike" "*" -"@types/chai-as-promised@*": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.1.tgz#004c27a4ac640e9590e25d8b0980cb0a6609bfd8" - integrity sha512-dberBxQW/XWv6BMj0su1lV9/C9AUx5Hqu2pisuS6S4YK/Qt6vurcj/BmcbEsobIWWCQzhesNY8k73kIxx4X7Mg== - dependencies: - "@types/chai" "*" - -"@types/chai-as-promised@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.3.tgz#779166b90fda611963a3adbfd00b339d03b747bd" - integrity sha512-FQnh1ohPXJELpKhzjuDkPLR2BZCAqed+a6xV4MI/T3XzHfd2FlarfUGUdZYgqYe8oxkYn0fchHEeHfHqdZ96sg== - dependencies: - "@types/chai" "*" - -"@types/chai@*": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" - integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== - -"@types/chai@^4.2.12": - version "4.2.12" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.12.tgz#6160ae454cd89dae05adc3bb97997f488b608201" - integrity sha512-aN5IAC8QNtSUdQzxu7lGBgYAOuU1tmRU4c9dIq5OKGf/SBVjXo+ffM2wEjudAWbgpOhy60nLoAGH1xm8fpCKFQ== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/concat-stream@^1.0.0": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.1.tgz#24bcfc101ecf68e886aaedce60dfd74b632a1b74" - integrity sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA== - dependencies: - "@types/node" "*" - -"@types/connect@*": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== +"@types/concat-stream@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-2.0.3.tgz#1f5c2ad26525716c181191f7ed53408f78eb758e" + integrity sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ== dependencies: "@types/node" "*" @@ -432,84 +872,25 @@ dependencies: "@types/ms" "*" -"@types/dirty-chai@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/dirty-chai/-/dirty-chai-2.0.2.tgz#eeac4802329a41ed7815ac0c1a6360335bf77d0c" - integrity sha512-BruwIN/UQEU0ePghxEX+OyjngpOfOUKJQh3cmfeq2h2Su/g001iljVi3+Y2y2EFp3IPgjf4sMrRU33Hxv1FUqw== - dependencies: - "@types/chai" "*" - "@types/chai-as-promised" "*" - -"@types/eslint-scope@^3.7.3": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" - integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.4.5" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4" - integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== - -"@types/estree@^0.0.51": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== - -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - -"@types/express-serve-static-core@^4.17.18": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/express@^4.17.13": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" - integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/fs-extra@^9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.1.tgz#91c8fc4c51f6d5dbe44c2ca9ab09310bd00c7918" - integrity sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg== - dependencies: - "@types/node" "*" +"@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== +"@types/glob@^7.1.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: - "@types/events" "*" "@types/minimatch" "*" "@types/node" "*" -"@types/highlight.js@^9.7.0": - version "9.12.4" - resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.4.tgz#8c3496bd1b50cc04aeefd691140aa571d4dbfa34" - integrity sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww== +"@types/hast@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" "@types/http-cache-semantics@*": version "4.0.1" @@ -521,40 +902,25 @@ resolved "https://registry.yarnpkg.com/@types/is-empty/-/is-empty-1.2.0.tgz#16bc578060c9b0b6953339eea906c255a375bf86" integrity sha512-brJKf2boFhUxTDxlpI7cstwiUtA2ovm38UzFTi9aZI6//ARncaV+Q5ALjCaJqXaMtdZk/oPTJnSutugsZR6h8A== -"@types/js-yaml@^4.0.0": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.2.tgz#4117a7a378593a218e9d6f0ef44ce6d5d9edf7fa" - integrity sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA== - "@types/json-buffer@~3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/json-buffer/-/json-buffer-3.0.0.tgz#85c1ff0f0948fc159810d4b5be35bf8c20875f64" integrity sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ== -"@types/json-schema@*", "@types/json-schema@^7.0.8": +"@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/json-schema@^7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" - integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== - -"@types/json-schema@^7.0.4": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" - integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/jsonwebtoken@^8.3.3": - version "8.5.0" - resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#2531d5e300803aa63279b232c014acf780c981c5" - integrity sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg== +"@types/jsonwebtoken@^9.0.0": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz#29b1369c4774200d6d6f63135bf3d1ba3ef997a4" + integrity sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw== dependencies: "@types/node" "*" @@ -565,32 +931,18 @@ dependencies: "@types/node" "*" -"@types/klaw@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/klaw/-/klaw-3.0.1.tgz#29f90021c0234976aa4eb97efced9cb6db9fa8b3" - integrity sha512-acnF3n9mYOr1aFJKFyvfNX0am9EtPUsYPq22QUCGdJE+MVt6UyAN1jwo+PmOPqXD4K7ZS9MtxDEp/un0lxFccA== - dependencies: - "@types/node" "*" - -"@types/linkify-it@*": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806" - integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw== - -"@types/lru-cache@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" - integrity sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w== +"@types/linkify-it@^5": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== -"@types/markdown-it@^10.0.0": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-10.0.3.tgz#a9800d14b112c17f1de76ec33eff864a4815eec7" - integrity sha512-daHJk22isOUvNssVGF2zDnnSyxHhFYhtjeX4oQaKD6QzL3ZR1QSgiD1g+Q6/WSWYVogNXYDXODtbgW/WiFCtyw== +"@types/markdown-it@^14.1.2": + version "14.1.2" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-14.1.2.tgz#57f2532a0800067d9b934f3521429a2e8bfb4c61" + integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog== dependencies: - "@types/highlight.js" "^9.7.0" - "@types/linkify-it" "*" - "@types/mdurl" "*" - highlight.js "^9.7.0" + "@types/linkify-it" "^5" + "@types/mdurl" "^2" "@types/mdast@^3.0.0": version "3.0.7" @@ -599,94 +951,69 @@ dependencies: "@types/unist" "*" -"@types/mdurl@*": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" - integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== - -"@types/mime@*": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" - integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== +"@types/mdast@^4.0.0": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" + integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== + dependencies: + "@types/unist" "*" -"@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/mdurl@^2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/minimist@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" - integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= - -"@types/mocha@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" - integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w== +"@types/minimist@^1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e" + integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== "@types/ms@*": version "0.7.31" resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node-fetch@^2.5.0": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - "@types/node@*": version "12.6.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.1.tgz#d5544f6de0aae03eefbb63d5120f6c8be0691946" integrity sha512-rp7La3m845mSESCgsJePNL/JQyhkOJA6G4vcwvVgkDAwHhGdq5GCumxmPjEk1MZf+8p5ZQAUE7tqgQRQTXN7uQ== -"@types/node@>= 8": - version "14.0.27" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1" - integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g== +"@types/node@^20.0.0": + version "20.16.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.12.tgz#61cc9be049584b472fa31e465aa0ab3c090dac56" + integrity sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA== + dependencies: + undici-types "~6.19.2" -"@types/node@^11.13.7": - version "11.13.22" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.22.tgz#91ee88ebfa25072433497f6f3150f84fa8c3a91b" - integrity sha512-rOsaPRUGTOXbRBOKToy4cgZXY4Y+QSVhxcLwdEveozbk7yuudhWMpxxcaXqYizLMP3VY7OcWCFtx9lGFh5j5kg== +"@types/node@^20.11.25": + version "20.16.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.9.tgz#1217c6cc77c4f3aaf4a6c76fb56b790e81e48120" + integrity sha512-rkvIVJxsOfBejxK7I0FO5sa2WxFmJCzoDwcd88+fq/CUfynNywTo/1/T6hyFz22CyztsnLS9nVlHOnTI36RH5w== + dependencies: + undici-types "~6.19.2" -"@types/node@^16.0.0": - version "16.4.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d" - integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg== +"@types/node@^22.7.7": + version "22.7.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.7.tgz#6cd9541c3dccb4f7e8b141b491443f4a1570e307" + integrity sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q== + dependencies: + undici-types "~6.19.2" -"@types/node@^16.11.26": - version "16.11.26" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.26.tgz#63d204d136c9916fb4dcd1b50f9740fe86884e47" - integrity sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ== +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/qs@*": - version "6.9.3" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03" - integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA== - -"@types/range-parser@*": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" - integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== - -"@types/repeat-string@^1.0.0": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@types/repeat-string/-/repeat-string-1.6.1.tgz#8bb5686e662ce1d962271b0b043623bf51404cdc" - integrity sha512-vdna8kjLGljgtPnYN6MBD2UwX62QE0EFLj9QlLXvg6dEu66NksXB900BNguBCMZZY2D9SSqncUskM23vT3uvWQ== - "@types/responselike@*", "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" @@ -694,319 +1021,305 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.3.tgz#3ad6ed949e7487e7bda6f886b4a2434a2c3d7b1a" - integrity sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q== - -"@types/send@^0.14.5": - version "0.14.5" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.14.5.tgz#653f7d25b93c3f7f51a8994addaf8a229de022a7" - integrity sha512-0mwoiK3DXXBu0GIfo+jBv4Wo5s1AcsxdpdwNUtflKm99VEMvmBPJ+/NBNRZy2R5JEYfWL/u4nAHuTUTA3wFecQ== - dependencies: - "@types/mime" "*" - "@types/node" "*" - -"@types/serve-static@*": - version "1.13.10" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" - integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== - dependencies: - "@types/mime" "^1" - "@types/node" "*" - -"@types/split@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/split/-/split-1.0.0.tgz#24f7c35707450b002f203383228f5a2bc1e6c228" - integrity sha512-pm9S1mkr+av0j7D6pFyqhBxXDbnbO9gqj4nb8DtGtCewvj0XhIv089SSwXrjrIizT1UquO8/h83hCut0pa3u8A== - dependencies: - "@types/node" "*" - "@types/through" "*" - -"@types/stream-chain@*": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/stream-chain/-/stream-chain-2.0.0.tgz#aed7fc21ac3686bc721aebbbd971f5a857e567e4" - integrity sha512-O3IRJcZi4YddlS8jgasH87l+rdNmad9uPAMmMZCfRVhumbWMX6lkBWnIqr9kokO5sx8LHp8peQ1ELhMZHbR0Gg== - dependencies: - "@types/node" "*" - -"@types/stream-json@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@types/stream-json/-/stream-json-1.5.1.tgz#ae8d1133f9f920e18c6e94b233cb57d014a47b8d" - integrity sha512-Blg6GJbKVEB1J/y/2Tv+WrYiMzPTIqyuZ+zWDJtAF8Mo8A2XQh/lkSX4EYiM+qtS+GY8ThdGi6gGA9h4sjvL+g== - dependencies: - "@types/node" "*" - "@types/stream-chain" "*" - -"@types/supports-color@^8.0.0": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@types/supports-color/-/supports-color-8.1.1.tgz#1b44b1b096479273adf7f93c75fc4ecc40a61ee4" - integrity sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw== - -"@types/temp@^0.8.34": - version "0.8.34" - resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.8.34.tgz#03e4b3cb67cbb48c425bbf54b12230fef85540ac" - integrity sha512-oLa9c5LHXgS6UimpEVp08De7QvZ+Dfu5bMQuWyMhf92Z26Q10ubEMOWy9OEfUdzW7Y/sDWVHmUaLFtmnX/2j0w== - dependencies: - "@types/node" "*" - -"@types/text-table@^0.2.0": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@types/text-table/-/text-table-0.2.2.tgz#774c90cfcfbc8b4b0ebb00fecbe861dc8b1e8e26" - integrity sha512-dGoI5Af7To0R2XE8wJuc6vwlavWARsCh3UKJPjWs1YEqGUqfgBI/j/4GX0yf19/DsDPPf0YAXWAp8psNeIehLg== - -"@types/through@*": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93" - integrity sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w== - dependencies: - "@types/node" "*" - -"@types/tunnel@^0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.3.tgz#f109e730b072b3136347561fc558c9358bb8c6e9" - integrity sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA== - dependencies: - "@types/node" "*" - -"@types/unist@*", "@types/unist@^2.0.0": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== - -"@types/unist@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" - integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== - -"@types/uuid@^3.4.6": - version "3.4.6" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016" - integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw== - dependencies: - "@types/node" "*" - -"@types/webpack-env@^1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.17.0.tgz#f99ce359f1bfd87da90cc4a57cab0a18f34a48d0" - integrity sha512-eHSaNYEyxRA5IAG0Ym/yCyf86niZUIF/TpWKofQI/CVfh5HsMEUyfE2kwFxha4ow0s5g0LfISQxpDKjbRDrizw== - -"@types/webpack@^5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.0.tgz#78dde06212f038d77e54116cfe69e88ae9ed2c03" - integrity sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w== - dependencies: - "@types/node" "*" - tapable "^2.2.0" - webpack "^5" - -"@typescript-eslint/eslint-plugin@^4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.4.1.tgz#b8acea0373bd2a388ac47df44652f00bf8b368f5" - integrity sha512-O+8Utz8pb4OmcA+Nfi5THQnQpHSD2sDUNw9AxNHpuYOo326HZTtG8gsfT+EAYuVrFNaLyNb2QnUNkmTRDskuRA== - dependencies: - "@typescript-eslint/experimental-utils" "4.4.1" - "@typescript-eslint/scope-manager" "4.4.1" - debug "^4.1.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.4.1.tgz#40613b9757fa0170de3e0043254dbb077cafac0c" - integrity sha512-Nt4EVlb1mqExW9cWhpV6pd1a3DkUbX9DeyYsdoeziKOpIJ04S2KMVDO+SEidsXRH/XHDpbzXykKcMTLdTXH6cQ== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.4.1" - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/typescript-estree" "4.4.1" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.4.1.tgz#25fde9c080611f303f2f33cedb145d2c59915b80" - integrity sha512-S0fuX5lDku28Au9REYUsV+hdJpW/rNW0gWlc4SXzF/kdrRaAVX9YCxKpziH7djeWT/HFAjLZcnY7NJD8xTeUEg== - dependencies: - "@typescript-eslint/scope-manager" "4.4.1" - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/typescript-estree" "4.4.1" - debug "^4.1.1" - -"@typescript-eslint/scope-manager@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.4.1.tgz#d19447e60db2ce9c425898d62fa03b2cce8ea3f9" - integrity sha512-2oD/ZqD4Gj41UdFeWZxegH3cVEEH/Z6Bhr/XvwTtGv66737XkR4C9IqEkebCuqArqBJQSj4AgNHHiN1okzD/wQ== - dependencies: - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/visitor-keys" "4.4.1" - -"@typescript-eslint/types@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.4.1.tgz#c507b35cf523bc7ba00aae5f75ee9b810cdabbc1" - integrity sha512-KNDfH2bCyax5db+KKIZT4rfA8rEk5N0EJ8P0T5AJjo5xrV26UAzaiqoJCxeaibqc0c/IvZxp7v2g3difn2Pn3w== +"@types/semver@^7.5.8": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== -"@typescript-eslint/typescript-estree@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.4.1.tgz#598f6de488106c2587d47ca2462c60f6e2797cb8" - integrity sha512-wP/V7ScKzgSdtcY1a0pZYBoCxrCstLrgRQ2O9MmCUZDtmgxCO/TCqOTGRVwpP4/2hVfqMz/Vw1ZYrG8cVxvN3g== +"@types/stream-chain@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/stream-chain/-/stream-chain-2.0.0.tgz#aed7fc21ac3686bc721aebbbd971f5a857e567e4" + integrity sha512-O3IRJcZi4YddlS8jgasH87l+rdNmad9uPAMmMZCfRVhumbWMX6lkBWnIqr9kokO5sx8LHp8peQ1ELhMZHbR0Gg== dependencies: - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/visitor-keys" "4.4.1" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + "@types/node" "*" -"@typescript-eslint/visitor-keys@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.4.1.tgz#1769dc7a9e2d7d2cfd3318b77ed8249187aed5c3" - integrity sha512-H2JMWhLaJNeaylSnMSQFEhT/S/FsJbebQALmoJxMPMxLtlVAMy2uJP/Z543n9IizhjRayLSqoInehCeNW9rWcw== +"@types/stream-json@^1.7.7": + version "1.7.7" + resolved "https://registry.yarnpkg.com/@types/stream-json/-/stream-json-1.7.7.tgz#8660101e15ee52e9a2370727334269ad7ec6a759" + integrity sha512-hHG7cLQ09H/m9i0jzL6UJAeLLxIWej90ECn0svO4T8J0nGcl89xZDQ2ujT4WKlvg0GWkcxJbjIDzW/v7BYUM6Q== dependencies: - "@typescript-eslint/types" "4.4.1" - eslint-visitor-keys "^2.0.0" + "@types/node" "*" + "@types/stream-chain" "*" -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== +"@types/supports-color@^8.0.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/supports-color/-/supports-color-8.1.1.tgz#1b44b1b096479273adf7f93c75fc4ecc40a61ee4" + integrity sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw== + +"@types/temp@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.9.4.tgz#69bd4b0e8fc4d54db06bd1b613c19292d333350b" + integrity sha512-+VfWIwrlept2VBTj7Y2wQnI/Xfscy1u8Pyj/puYwss6V1IblXn1x7S0S9eFh6KyBolgLCm+rUFzhFAbdkR691g== dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@types/node" "*" -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== +"@types/text-table@^0.2.0": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@types/text-table/-/text-table-0.2.2.tgz#774c90cfcfbc8b4b0ebb00fecbe861dc8b1e8e26" + integrity sha512-dGoI5Af7To0R2XE8wJuc6vwlavWARsCh3UKJPjWs1YEqGUqfgBI/j/4GX0yf19/DsDPPf0YAXWAp8psNeIehLg== -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== +"@types/unist@*", "@types/unist@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== +"@types/unist@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" + integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@xtuc/long" "4.2.2" +"@types/unist@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" + integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== +"@types/webpack-env@^1.18.5": + version "1.18.5" + resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.5.tgz#eccda0b04fe024bed505881e2e532f9c119169bf" + integrity sha512-wz7kjjRRj8/Lty4B+Kr0LN6Ypc/3SymeCCGSbaXp2leH0ZVg/PriNiOwNj4bD4uphI7A8NXS4b6Gl373sfO5mA== -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== +"@types/webpack@^5.28.5": + version "5.28.5" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.5.tgz#0e9d9a15efa09bbda2cef41356ca4ac2031ea9a2" + integrity sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" + "@types/node" "*" + tapable "^2.2.0" + webpack "^5" -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== +"@types/yauzl@^2.9.1": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" + integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== dependencies: - "@xtuc/ieee754" "^1.2.0" + "@types/node" "*" -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== - dependencies: +"@typescript-eslint/eslint-plugin@^8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz#d0070f206daad26253bf00ca5b80f9b54f9e2dd0" + integrity sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/type-utils" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.7.0.tgz#a567b0890d13db72c7348e1d88442ea8ab4e9173" + integrity sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ== + dependencies: + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz#90ee7bf9bc982b9260b93347c01a8bc2b595e0b8" + integrity sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + +"@typescript-eslint/type-utils@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz#d56b104183bdcffcc434a23d1ce26cde5e42df93" + integrity sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.7.0.tgz#21d987201c07b69ce7ddc03451d7196e5445ad19" + integrity sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w== + +"@typescript-eslint/typescript-estree@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz#6c7db6baa4380b937fa81466c546d052f362d0e8" + integrity sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.7.0.tgz#cef3f70708b5b5fd7ed8672fc14714472bd8a011" + integrity sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" + +"@typescript-eslint/visitor-keys@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz#5e46f1777f9d69360a883c1a56ac3c511c9659a8" + integrity sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ== + dependencies: + "@typescript-eslint/types" "8.7.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vscode/l10n@^0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@vscode/l10n/-/l10n-0.0.10.tgz#9c513107c690c0dd16e3ec61e453743de15ebdb0" + integrity sha512-E1OCmDcDWa0Ya7vtSjp/XfHFGqYJfh+YPC1RkATU71fTac+j1JjCcB3qwSzmlKAighx2WxhLlfhS0RwAN++PFQ== + +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" - -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" + "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== - dependencies: - "@webassemblyjs/ast" "1.11.1" +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" - integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== -"@webpack-cli/info@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" - integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== - dependencies: - envinfo "^7.7.3" +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== -"@webpack-cli/serve@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" - integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1018,33 +1331,32 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.1.1, acorn@^7.2.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== +acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -acorn@^8.4.1, acorn@^8.5.0: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" aggregate-error@^3.0.0: version "3.0.1" @@ -1054,17 +1366,12 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.5: +ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1074,34 +1381,39 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.16.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^4.3.0: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== dependencies: type-fest "^0.11.0" -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.0.tgz#ecc7f5933cbe5ac7b33e209a5ff409ab1669c6b2" - integrity sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1116,6 +1428,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.0.3.tgz#2fb624fe0e84bccab00afee3d0006ed310f22f09" @@ -1144,102 +1461,158 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-includes@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" - integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - -array-includes@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - is-string "^1.0.5" + call-bind "^1.0.2" + is-array-buffer "^3.0.1" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.5, array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + 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" array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.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" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + 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" arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asar@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/asar/-/asar-3.1.0.tgz#70b0509449fe3daccc63beb4d3c7d2e24d3c6473" - integrity sha512-vyxPxP5arcAqN4F/ebHd/HhwnAiZtwhglvdmc7BR2f0ywbVNTOpSeyhLDbGXtE/y58hv1oC75TaNIXutnsOZsQ== - dependencies: - chromium-pickle-js "^0.2.0" - commander "^5.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - optionalDependencies: - "@types/glob" "^7.1.1" - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +async@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -aws-sdk@^2.814.0: - version "2.814.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.814.0.tgz#7a1c36006e0b5826f14bd2511b1d229ef6814bb0" - integrity sha512-empd1m/J/MAkL6d9OeRpmg9thobULu0wk4v8W3JToaxGi2TD7PIdvE6yliZKyOVAdJINhBWEBhxR4OUIHhcGbQ== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.15.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.3.2" - xml2js "0.4.19" +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" bail@^2.0.0: version "2.0.1" @@ -1251,20 +1624,20 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== +balanced-match@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" + integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -before-after-hook@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" - integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== +before-after-hook@^2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" + integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== big.js@^5.2.2: version "5.2.2" @@ -1276,21 +1649,10 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" +boolean@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" + integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== brace-expansion@^1.1.7: version "1.1.11" @@ -1300,22 +1662,39 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" -browserslist@^4.14.5: - version "4.21.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.2.tgz#59a400757465535954946a400b841ed37e2b4ecf" - integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA== +browserslist@^4.21.10, browserslist@^4.23.3: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001366" - electron-to-chromium "^1.4.188" - node-releases "^2.0.6" - update-browserslist-db "^1.0.4" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== buffer-equal-constant-time@1.0.1: version "1.0.1" @@ -1332,15 +1711,6 @@ buffer-from@^1.1.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -buffer@4.9.2: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -1349,36 +1719,23 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -builtins@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-4.0.0.tgz#a8345420de82068fdc4d6559d0456403a8fb1905" - integrity sha512-qC0E2Dxgou1IHhvJSLwGDSTvokbRovU5zZFuDY6oY8Y2lF3nGt5Ad8YZK7GMtqzY84Wu7pXTPeHQeHcXSXsRhw== +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== dependencies: semver "^7.0.0" -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - cacheable-request@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" @@ -1392,34 +1749,47 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + 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" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - -caniuse-lite@^1.0.30001366: - version "1.0.30001367" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz#2b97fe472e8fa29c78c5970615d7cd2ee414108a" - integrity sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw== +caniuse-lite@^1.0.30001646: + version "1.0.30001659" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001659.tgz#f370c311ffbc19c4965d8ec0064a3625c8aaa7af" + integrity sha512-Qxxyfv3RdHAfJcXelgf0hU4DFUVXBGTjqrBUZLUh8AtlGnsDo+CnncYtTd95+ZKfnANUOzxyIQCuU/UeBZBYoA== -chai@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== +chai@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.1.tgz#f035d9792a22b481ead1c65908d14bb62ec1c82c" + integrity sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA== dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.0" - type-detect "^4.0.5" + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1428,22 +1798,27 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.0.0, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + character-entities-legacy@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-2.0.0.tgz#57f4d00974c696e8f74e9f493e7fcb75b44d7ee7" @@ -1459,15 +1834,10 @@ character-reference-invalid@^2.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.0.tgz#a0bdeb89c051fe7ed5d3158b2f06af06984f2813" integrity sha512-pE3Z15lLRxDzWJy7bBHBopRwfI20sbrMVLQTC7xsPglCHf4Wv1e167OgYAFP78co2XlhojDyAqA+IAJse27//g== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== check-for-leaks@^1.2.1: version "1.2.1" @@ -1479,13 +1849,6 @@ check-for-leaks@^1.2.1: parse-gitignore "^0.4.0" walk-sync "^0.3.2" -checksum@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/checksum/-/checksum-0.1.1.tgz#dc6527d4c90be8560dbd1ed4cecf3297d528e9e9" - integrity sha1-3GUn1MkL6FYNvR7Uzs8yl9Uo6ek= - dependencies: - optimist "~0.3.5" - chokidar@^3.0.0: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -1501,10 +1864,10 @@ chokidar@^3.0.0: optionalDependencies: fsevents "~2.3.2" -chownr@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: version "1.0.2" @@ -1513,23 +1876,23 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromium-pickle-js@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" - integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw== + dependencies: + escape-string-regexp "^1.0.5" clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -1537,10 +1900,17 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.0.0, cli-spinners@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77" - integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-spinners@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== cli-truncate@2.1.0, cli-truncate@^2.1.0: version "2.1.0" @@ -1550,11 +1920,6 @@ cli-truncate@2.1.0, cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -1571,11 +1936,6 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - co@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/co/-/co-3.1.0.tgz#4ea54ea5a08938153185e15210c68d9092bc1b78" @@ -1610,47 +1970,30 @@ colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -colors@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - -colors@^1.1.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" - integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -commander@^2.20.0, commander@^2.9.0: +commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - commander@^5.0.0, commander@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -commander@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" - integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== +commander@~12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.0.0.tgz#b929db6df8546080adfd004ab215ed48cf6f2592" + integrity sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA== compress-brotli@^1.3.8: version "1.3.8" @@ -1663,7 +2006,7 @@ compress-brotli@^1.3.8: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^2.0.0: version "2.0.0" @@ -1675,32 +2018,12 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== +core-js-compat@^3.37.0: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" + integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + browserslist "^4.23.3" core-util-is@~1.0.0: version "1.0.2" @@ -1718,65 +2041,62 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -debug-log@^1.0.0: +data-view-buffer@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" - integrity sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8= + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" -debug@2.6.9, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== dependencies: - ms "2.0.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== dependencies: - ms "^2.1.1" + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" -debug@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" -debug@^4.0.1, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@^3.1.0, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= +decode-named-character-reference@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" + integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== dependencies: - mimic-response "^1.0.0" + character-entities "^2.0.0" decompress-response@^6.0.0: version "6.0.0" @@ -1790,98 +2110,83 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== -deep-extend@^0.6.0, deep-extend@~0.6.0: +deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@^0.1.3, deep-is@~0.1.3: +deep-is@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - defer-to-connect@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - object-keys "^1.0.12" + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" -deglob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/deglob/-/deglob-4.0.1.tgz#0685c6383992fd6009be10653a2b1116696fad55" - integrity sha512-/g+RDZ7yf2HvoW+E5Cy+K94YhgcFgr6C8LuHZD1O5HoNPkf3KY6RfXJ0DBGlB/NkLi5gml+G9zqRzk9S0mHZCg== +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== dependencies: - find-root "^1.0.0" - glob "^7.0.5" - ignore "^5.0.0" - pkg-config "^1.1.0" - run-parallel "^1.1.2" - uniq "^1.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +dequal@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +devlop@^1.0.0, devlop@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== doctrine@^2.1.0: version "2.1.0" @@ -1897,40 +2202,24 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dotenv-safe@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/dotenv-safe/-/dotenv-safe-4.0.4.tgz#8b0e7ced8e70b1d3c5d874ef9420e406f39425b3" - integrity sha1-iw587Y5wsdPF2HTvlCDkBvOUJbM= - dependencies: - dotenv "^4.0.0" - -dotenv@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" - integrity sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0= - -dugite@^1.103.0: - version "1.103.0" - resolved "https://registry.yarnpkg.com/dugite/-/dugite-1.103.0.tgz#2229c83790782116f96b87763d9ea1a0f2a55842" - integrity sha512-8rKO/jQX2HKfSd5wNG/l3HnUfQPKqyC3+D+3CR5Go4+BJOyCPScQwiAVW+eeKLqHFOvjq/w67+ymMyPGxUqhIA== +dugite@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/dugite/-/dugite-2.7.1.tgz#277275fd490bddf20180e124d119f84f708dfb32" + integrity sha512-X7v7JngMG6RGHKCKKF0fdqYC9Xcw0CDes43an6dQW2N2dYNd/OOLq3BFszCOyOObgKnrmNVvyggk3O4WGJMpcA== dependencies: - checksum "^0.1.1" - got "^9.6.0" - mkdirp "^0.5.1" progress "^2.0.3" - rimraf "^2.5.4" - tar "^4.4.7" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + tar "^6.1.11" duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" @@ -1938,20 +2227,15 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.4.188: - version "1.4.195" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.195.tgz#139b2d95a42a3f17df217589723a1deac71d1473" - integrity sha512-vefjEh0sk871xNmR5whJf9TEngX+KTKS3hOHpjoMpauKkwlGwtMz1H8IaIjAT/GNnX0TbGwAdmVoXCAzXf+PPg== +electron-to-chromium@^1.5.4: + version "1.5.18" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz#5fe62b9d21efbcfa26571066502d94f3ed97e495" + integrity sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^10.2.1, emoji-regex@^10.3.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== emoji-regex@^8.0.0: version "8.0.0" @@ -1963,21 +2247,11 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1994,10 +2268,10 @@ enhanced-resolve@^4.0.0: memory-fs "^0.4.0" tapable "^1.0.0" -enhanced-resolve@^5.9.3: - version "5.10.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" - integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -2014,16 +2288,31 @@ ensure-posix-path@^1.0.0: resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw== -entities@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" - integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +entities@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" + integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== + +env-paths@^2.2.0, env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.3: version "7.8.1" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + errno@^0.1.3: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -2031,55 +2320,160 @@ errno@^0.1.3: dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1, error-ex@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.6" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" - integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.0" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-regex "^1.1.0" - object-inspect "^1.7.0" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + 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.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.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^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" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-abstract@^1.7.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" - integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" has "^1.0.3" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-keys "^1.0.12" + has-tostringtag "^1.0.0" -es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + has "^1.0.3" + +es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -2090,59 +2484,88 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es6-object-assign@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" - integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +es6-error@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= +escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -eslint-config-standard-jsx@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-8.1.0.tgz#314c62a0e6f51f75547f89aade059bec140edfc7" - integrity sha512-ULVC8qH8qCqbU792ZOO6DaiaZyHNS/5CZt3hKqHkEhVlhPEPN3nfBqqxJCyp59XrjIBZPu1chMYe9T2DXZ7TMw== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-standard@14.1.1, eslint-config-standard@^14.1.1: - version "14.1.1" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" - integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== +eslint-compat-utils@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4" + integrity sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q== + dependencies: + semver "^7.5.4" -eslint-import-resolver-node@^0.3.2, eslint-import-resolver-node@^0.3.3: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== +eslint-config-standard-jsx@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz#70852d395731a96704a592be5b0bfaccfeded239" + integrity sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ== + +eslint-config-standard@17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz#fd5b6cf1dcf6ba8d29f200c461de2e19069888cf" + integrity sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg== + +eslint-config-standard@^17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== + +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== dependencies: - debug "^2.6.9" - resolve "^1.13.1" + debug "^3.2.7" + is-core-module "^2.11.0" + resolve "^1.22.1" -eslint-module-utils@^2.4.0, eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" -eslint-plugin-es@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz#0f5f5da5f18aa21989feebe8a73eadefb3432976" - integrity sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ== +eslint-module-utils@^2.7.4: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== dependencies: - eslint-utils "^1.4.2" - regexpp "^3.0.0" + debug "^3.2.7" + +eslint-module-utils@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4" + integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ== + dependencies: + debug "^3.2.7" + +eslint-plugin-es-x@^7.5.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz#a207aa08da37a7923f2a9599e6d3eb73f3f92b74" + integrity sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.11.0" + eslint-compat-utils "^0.5.1" eslint-plugin-es@^3.0.0: version "3.0.1" @@ -2152,49 +2575,98 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@^2.22.0: - version "2.22.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" - integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== - dependencies: - 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.3" - 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" - -eslint-plugin-import@~2.18.0: - version "2.18.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6" - integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ== - dependencies: - array-includes "^3.0.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.0" - read-pkg-up "^2.0.0" - resolve "^1.11.0" - -eslint-plugin-mocha@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-7.0.1.tgz#b2e9e8ebef7836f999a83f8bab25d0e0c05f0d28" - integrity sha512-zkQRW9UigRaayGm/pK9TD5RjccKXSgQksNtpsXbG9b6L5I+jNx7m98VUbZ4w1H1ArlNA+K7IOH+z8TscN6sOYg== +eslint-plugin-es@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9" + integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ== dependencies: eslint-utils "^2.0.0" - ramda "^0.27.0" + regexpp "^3.0.0" + +eslint-plugin-import@^2.26.0: + version "2.27.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" + has "^1.0.3" + is-core-module "^2.11.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-import@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" + integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.9.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +eslint-plugin-mocha@^10.5.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz#0aca8d709e7cddef566e0dc252f6b02e307a2b7e" + integrity sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw== + dependencies: + eslint-utils "^3.0.0" + globals "^13.24.0" + rambda "^7.4.0" + +eslint-plugin-n@^15.1.0: + version "15.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz#e29221d8f5174f84d18f2eb94765f2eeea033b90" + integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== + dependencies: + builtins "^5.0.1" + eslint-plugin-es "^4.1.0" + eslint-utils "^3.0.0" + ignore "^5.1.1" + is-core-module "^2.11.0" + minimatch "^3.1.2" + resolve "^1.22.1" + semver "^7.3.8" + +eslint-plugin-n@^16.6.2: + version "16.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz#6a60a1a376870064c906742272074d5d0b412b0b" + integrity sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + globals "^13.24.0" + ignore "^5.2.4" + is-builtin-module "^3.2.1" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" eslint-plugin-node@^11.1.0: version "11.1.0" @@ -2208,54 +2680,63 @@ eslint-plugin-node@^11.1.0: resolve "^1.10.1" semver "^6.1.0" -eslint-plugin-node@~10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz#fd1adbc7a300cf7eb6ac55cf4b0b6fc6e577f5a6" - integrity sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ== - dependencies: - eslint-plugin-es "^2.0.0" - eslint-utils "^1.4.2" - ignore "^5.1.1" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" +eslint-plugin-promise@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" + integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== -eslint-plugin-promise@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" - integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== +eslint-plugin-promise@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" + integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== -eslint-plugin-react@~7.14.2: - version "7.14.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13" - integrity sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA== +eslint-plugin-react@^7.28.0: + version "7.32.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" + integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== dependencies: - array-includes "^3.0.3" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.1.0" - object.entries "^1.1.0" - object.fromentries "^2.0.0" - object.values "^1.1.0" - prop-types "^15.7.2" - resolve "^1.10.1" - -eslint-plugin-standard@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" - integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== - -eslint-plugin-standard@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz#f845b45109c99cd90e77796940a344546c8f6b5c" - integrity sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA== - -eslint-plugin-typescript@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-typescript/-/eslint-plugin-typescript-0.14.0.tgz#068549c3f4c7f3f85d88d398c29fa96bf500884c" - integrity sha512-2u1WnnDF2mkWWgU1lFQ2RjypUlmRoBEvQN02y9u+IL12mjWlkKFGEBnVsjs9Y8190bfPQCvWly1c2rYYUSOxWw== - dependencies: - requireindex "~1.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" + resolve "^2.0.0-next.4" + semver "^6.3.0" + string.prototype.matchall "^4.0.8" + +eslint-plugin-standard@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz#c43f6925d669f177db46f095ea30be95476b1ee4" + integrity sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg== + +eslint-plugin-unicorn@^55.0.0: + version "55.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz#e2aeb397914799895702480970e7d148df5bcc7b" + integrity sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA== + dependencies: + "@babel/helper-validator-identifier" "^7.24.5" + "@eslint-community/eslint-utils" "^4.4.0" + ci-info "^4.0.0" + clean-regexp "^1.0.0" + core-js-compat "^3.37.0" + esquery "^1.5.0" + globals "^15.7.0" + indent-string "^4.0.0" + is-builtin-module "^3.2.1" + jsesc "^3.0.2" + pluralize "^8.0.0" + read-pkg-up "^7.0.1" + regexp-tree "^0.1.27" + regjsparser "^0.10.0" + semver "^7.6.1" + strip-indent "^3.0.0" eslint-scope@5.1.1: version "5.1.1" @@ -2265,28 +2746,13 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" - integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" - integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.4.2, eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^2.0.0: version "2.1.0" @@ -2295,149 +2761,99 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint-visitor-keys@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.4.0.tgz#4e35a2697e6c1972f9d6ef2b690ad319f80f206f" - integrity sha512-gU+lxhlPHu45H3JkEGgYhWhkR9wLHHEXC9FbWFnTlEkbKyZKWgWRLgf61E8zWmBuI6g5xKBph9ltg3NtZMVF8g== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.13.0, eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@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.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" - esquery "^1.2.0" + 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-parent "^5.0.0" - globals "^12.1.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" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.14" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -eslint@~6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" + optionator "^0.9.3" + strip-ansi "^6.0.1" text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" -espree@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" - integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^7.2.0" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.2.0" + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== - dependencies: - estraverse "^4.0.0" - -esquery@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: - estraverse "^4.1.0" + estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" @@ -2446,7 +2862,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -2456,7 +2872,7 @@ estraverse@^5.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== -estraverse@^5.2.0: +estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -2466,27 +2882,12 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= -events@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= - -events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== - -events@^3.2.0: +events@^3.0.0, events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -2506,83 +2907,60 @@ execa@^4.0.1: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -express@^4.16.4: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== +extract-zip@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1: - version "3.2.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" - integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" + glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + micromatch "^4.0.4" fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + +fast-xml-parser@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz#2882b7d01a6825dfdf909638f2de0256351def37" + integrity sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg== + dependencies: + strnum "^1.0.5" + fastest-levenshtein@^1.0.12: version "1.0.14" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz#9054384e4b7a78c88d01a4432dc18871af0ac859" @@ -2595,64 +2973,34 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fault@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fault/-/fault-2.0.0.tgz#ad2198a6e28e344dcda76a7b32406b1039f0b707" - integrity sha512-JsDj9LFcoC+4ChII1QpXPA7YIaY8zmqPYw7h9j5n7St7a0BBKfNnwEBAUQRBx70o2q4rs+BeSNHk8Exm6xE7fQ== +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== dependencies: - format "^0.2.0" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + pend "~1.2.0" -figures@^3.0.0, figures@^3.2.0: +figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-root@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -2660,7 +3008,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.0.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -2668,19 +3016,26 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" - integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== folder-hash@^2.1.1: version "2.1.2" @@ -2691,47 +3046,29 @@ folder-hash@^2.1.1: graceful-fs "~4.1.11" minimatch "~3.0.4" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" + is-callable "^1.1.3" -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -format@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" - integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + cross-spawn "^7.0.0" + signal-exit "^4.0.1" -fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" fs-extra@^8.1.0: version "8.1.0" @@ -2742,22 +3079,12 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" - integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^1.0.0" - -fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: - minipass "^2.6.0" + minipass "^3.0.0" fs.realpath@^1.0.0: version "1.0.0" @@ -2769,42 +3096,86 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.2, functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-east-asian-width@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" + integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== + +get-func-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + 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" get-own-enumerable-property-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== -get-stdin@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - -get-stdin@~8.0.0: +get-stdin@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" +get-stdin@~9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" + integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" @@ -2813,26 +3184,69 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== dependencies: - is-glob "^4.0.1" + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +get-tsconfig@^4.7.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" -glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^7.0.0, glob@^7.0.5, glob@^7.1.3, glob@^7.1.6: +glob@^10.0.0, glob@^10.2.2: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + 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" + +glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -2844,36 +3258,94 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@~7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== +glob@^9.2.0: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== dependencies: - type-fest "^0.8.1" + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + +glob@~10.3.12: + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + +global-agent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" + integrity sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q== + dependencies: + boolean "^3.0.1" + es6-error "^4.1.1" + matcher "^3.0.0" + roarr "^2.15.3" + semver "^7.3.2" + serialize-error "^7.0.1" -globby@^11.0.0, globby@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" - integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" + type-fest "^0.20.2" + +globals@^13.24.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globals@^15.7.0: + version "15.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.9.0.tgz#e9de01771091ffbc37db5714dab484f9f69ff399" + integrity sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA== + +globalthis@^1.0.1, globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-14.0.1.tgz#a1b44841aa7f4c6d8af2bc39951109d77301959b" + integrity sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ== + dependencies: + "@sindresorhus/merge-streams" "^2.1.0" + fast-glob "^3.3.2" + ignore "^5.2.4" + path-type "^5.0.0" + slash "^5.1.0" + unicorn-magic "^0.1.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" got@^11.8.5: version "11.8.5" @@ -2892,43 +3364,26 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.9: - version "4.2.0" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" - integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.2.4, graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graceful-fs@~4.1.11: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2944,59 +3399,131 @@ has-flag@^5.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-5.0.1.tgz#5483db2ae02a472d1d0691462fc587d1843cd940" integrity sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA== -has-symbols@^1.0.0: +has-property-descriptors@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" -has-symbols@^1.0.1: +has-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" -has@^1.0.1, has@^1.0.3: +has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" -highlight.js@^9.7.0: - version "9.18.5" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825" - integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hast-util-from-html@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz#9cd38ee81bf40b2607368b92a04b0905fa987488" + integrity sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.1.0" + hast-util-from-parse5 "^8.0.0" + parse5 "^7.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + +hast-util-from-parse5@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz#654a5676a41211e14ee80d1b1758c399a0327651" + integrity sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + hastscript "^8.0.0" + property-information "^6.0.0" + vfile "^6.0.0" + vfile-location "^5.0.0" + web-namespaces "^2.0.0" + +hast-util-parse-selector@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" + integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== + dependencies: + "@types/hast" "^3.0.0" + +hastscript@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-8.0.0.tgz#4ef795ec8dee867101b9f23cc830d4baf4fd781a" + integrity sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^4.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" @@ -3006,6 +3533,14 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +https-proxy-agent@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -3016,45 +3551,25 @@ husky@^8.0.1: resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@1.1.13, ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.0.0, ignore@^5.1.1, ignore@^5.1.4, ignore@~5.1.8: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.0.0, ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4, ignore@~5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== -import-fresh@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" - integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -import-fresh@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== +import-fresh@^3.1.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -3067,12 +3582,10 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" -import-meta-resolve@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-1.1.1.tgz#244fd542fd1fae73550d4f8b3cde3bba1d7b2b18" - integrity sha512-JiTuIvVyPaUg11eTrNDx5bgQ/yMKMZffc7YSjvQeSMXy58DO2SQ8BtAf3xteZvmzvjYh14wnqNjL8XVeDy2o9A== - dependencies: - builtins "^4.0.0" +import-meta-resolve@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" + integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== imurmurhash@^0.1.4: version "0.1.4" @@ -3092,54 +3605,48 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +ini@^4.1.2, ini@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.3.tgz#4c359675a6071a46985eb39b14e4a2c0ec98a795" + integrity sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg== + +ini@~4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.2.tgz#7f646dbd9caea595e61f88ef60bfff8b01f8130a" + integrity sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw== -ini@^1.3.5, ini@~1.3.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== +internal-slot@^1.0.3, internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" -inquirer@^7.0.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.0.tgz#aa3e7cb0c18a410c3c16cdd2bc9dcbe83c4d333e" - integrity sha512-K+LZp6L/6eE5swqIcVXrxl21aGDU4S50gKH0/d96OMQnSBCyGyZl/oZhbkVmdp5sBoINHd4xZvFSARh2dk6DWA== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== - -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== is-alphabetical@^2.0.0: version "2.0.0" @@ -3154,11 +3661,35 @@ is-alphanumerical@^2.0.0: is-alphabetical "^2.0.0" is-decimal "^2.0.0" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3166,20 +3697,39 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" -is-callable@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" - integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + +is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" is-core-module@^2.8.0: version "2.8.1" @@ -3195,10 +3745,19 @@ is-core-module@^2.9.0: dependencies: has "^1.0.3" -is-date-object@^1.0.1: +is-data-view@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-decimal@^2.0.0: version "2.0.0" @@ -3213,23 +3772,13 @@ is-empty@^1.0.0: is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -3237,10 +3786,10 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -3249,10 +3798,27 @@ is-hexadecimal@^2.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.0.tgz#8e1ec9f48fe3eabd90161109856a23e0907a65d5" integrity sha512-vGOtYkiaxwIiR0+Ng/zNId+ZZehGfINwTzdrDqc6iubbnQWhnPuYymOzOKUDqa2cSl59yHnEh2h6MvRLQsyNug== -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" is-number@^7.0.0: version "7.0.0" @@ -3264,6 +3830,11 @@ is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.0.0.tgz#06c0999fd7574edf5a906ba5644ad0feb3a84d22" @@ -3276,48 +3847,98 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-4.1.1.tgz#1a14d6452cbd50790edc7fdaa0aed5a40a35ebb5" - integrity sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA== - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -is-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" - integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - has-symbols "^1.0.1" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-unicode-supported@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== + +is-unicode-supported@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" + integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== -is-symbol@^1.0.2: +is-weakref@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: - has-symbols "^1.0.0" + call-bind "^1.0.2" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@^1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -3327,11 +3948,34 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -3341,43 +3985,35 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jmespath@0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" - integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1, js-yaml@^3.2.7: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.0.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" -js-yaml@~3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== +js-yaml@^3.2.7: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== dependencies: argparse "^1.0.7" esprima "^4.0.0" -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== json-buffer@3.0.1, json-buffer@~3.0.1: version "3.0.1" @@ -3394,41 +4030,47 @@ json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-parse-even-better-errors@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz#b43d35e89c0f3be6b5fbbe9dc6c82467b30c28da" + integrity sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== +json5@^1.0.1, json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: - minimist "^1.2.5" + minimist "^1.2.0" -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" +json5@^2.0.0, json5@^2.1.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" - integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== +jsonc-parser@3.2.1, jsonc-parser@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" + integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== jsonfile@^4.0.0: version "4.0.0" @@ -3446,29 +4088,28 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonwebtoken@^8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== +jsonpointer@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== + +jsonwebtoken@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== dependencies: jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" + lodash "^4.17.21" ms "^2.1.1" - semver "^5.6.0" + semver "^7.3.8" -jsx-ast-utils@^2.1.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" - integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== dependencies: - array-includes "^3.1.1" - object.assign "^4.1.0" + array-includes "^3.1.5" + object.assign "^4.1.3" jwa@^1.4.1: version "1.4.1" @@ -3487,13 +4128,6 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - keyv@^4.0.0: version "4.3.1" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.3.1.tgz#7970672f137d987945821b1a07b524ce5a4edd27" @@ -3503,24 +4137,14 @@ keyv@^4.0.0: json-buffer "3.0.1" kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -klaw@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" - integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== - dependencies: - graceful-fs "^4.1.9" + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" +kleur@^4.0.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== levn@^0.4.1: version "0.4.1" @@ -3530,33 +4154,29 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libnpmconfig@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0" - integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA== - dependencies: - figgy-pudding "^3.5.1" - find-up "^3.0.0" - ini "^1.3.5" - lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -linkify-it@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" - integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== +lines-and-columns@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.4.tgz#d00318855905d2660d8c0822e3f5a4715855fc42" + integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== + +linkify-it@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" + integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw== dependencies: uc.micro "^1.0.1" -linkify-it@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8" - integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== dependencies: - uc.micro "^1.0.1" + uc.micro "^2.0.0" lint-staged@^10.2.11: version "10.2.11" @@ -3579,11 +4199,6 @@ lint-staged@^10.2.11: string-argv "0.3.1" stringify-object "^3.3.0" -lint@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/lint/-/lint-1.1.2.tgz#35ed064f322547c331358d899868664968ba371f" - integrity sha1-Ne0GTzIlR8MxNY2JmGhmSWi6Nx8= - listr2@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/listr2/-/listr2-2.2.0.tgz#cb88631258abc578c7fb64e590fe5742f28e4aac" @@ -3598,16 +4213,6 @@ listr2@^2.1.0: rxjs "^6.5.5" through "^2.3.8" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-5.3.0.tgz#4d3c1e01fa1c03ea78a60ac7af932c9ce53403f3" @@ -3619,13 +4224,13 @@ load-json-file@^5.2.0: strip-bom "^3.0.0" type-fest "^0.3.0" -load-plugin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/load-plugin/-/load-plugin-4.0.1.tgz#9a239b0337064c9b8aac82b0c9f89b067db487c5" - integrity sha512-4kMi+mOSn/TR51pDo4tgxROHfBHXsrcyEYSGHcJ1o6TtRaP2PsRM5EwmYbj1uiLDvbfA/ohwuSWZJzqGiai8Dw== +load-plugin@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/load-plugin/-/load-plugin-6.0.3.tgz#b0eb8ea2361744f0e54850ccbc4c8a2d94ffabe3" + integrity sha512-kc0X2FEUZr145odl68frm+lMJuQ23+rTXYmR6TImqPtbpmXC4vVXbWKDQ9IzndA0HfyQamWfKLhzsqGSTxE63w== dependencies: - import-meta-resolve "^1.0.0" - libnpmconfig "^1.0.0" + "@npmcli/config" "^8.0.0" + import-meta-resolve "^4.0.0" loader-runner@^4.2.0: version "4.3.0" @@ -3633,31 +4238,23 @@ loader-runner@^4.2.0: integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== loader-utils@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + version "1.4.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3" + integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg== dependencies: big.js "^5.2.2" - emojis-list "^2.0.0" + emojis-list "^3.0.0" json5 "^1.0.1" loader-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" json5 "^2.1.2" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -3673,80 +4270,28 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.differencewith@~4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7" - integrity sha1-uvr7yRi1UVTheRdqALsK76rIVLc= - -lodash.flatten@^4.4.0, lodash.flatten@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - -lodash.range@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.range/-/lodash.range-3.2.0.tgz#f461e588f66683f7eadeade513e38a69a565a15d" - integrity sha1-9GHliPZmg/fq3q3lE+OKaaVloV0= +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15: +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -log-symbols@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== - dependencies: - chalk "^2.4.2" - log-symbols@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" @@ -3754,6 +4299,14 @@ log-symbols@^4.0.0: dependencies: chalk "^4.0.0" +log-symbols@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-6.0.0.tgz#bb95e5f05322651cac30c0feb6404f9f2a8a9439" + integrity sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw== + dependencies: + chalk "^5.3.0" + is-unicode-supported "^1.3.0" + log-update@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" @@ -3776,16 +4329,28 @@ loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== +loupe@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.1.tgz#71d038d59007d890e3247c5db97c1ec5a92edc54" + integrity sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw== + dependencies: + get-func-name "^2.0.1" lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lru-cache@^10.0.1: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^10.2.0: + version "10.2.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3793,64 +4358,90 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^9.0.0, lru-cache@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1" + integrity sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A== + make-error@^1.1.1: version "1.3.5" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== -markdown-it@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-11.0.0.tgz#dbfc30363e43d756ebc52c38586b91b90046b876" - integrity sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg== +markdown-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-2.0.0.tgz#34bebc83e9938cae16e0e017e4a9814a8330d3c4" + integrity sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q== + +markdown-it@14.1.0, markdown-it@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== dependencies: - argparse "^1.0.7" - entities "~2.0.0" - linkify-it "^3.0.1" - mdurl "^1.0.1" - uc.micro "^1.0.5" + 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" -markdown-it@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" - integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg== +markdown-it@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430" + integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q== dependencies: - argparse "^1.0.7" - entities "~2.0.0" - linkify-it "^2.0.0" + argparse "^2.0.1" + entities "~3.0.1" + linkify-it "^4.0.1" mdurl "^1.0.1" uc.micro "^1.0.5" -markdownlint-cli@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/markdownlint-cli/-/markdownlint-cli-0.25.0.tgz#806b2c234259fa621af27673644506d447bdb6a1" - integrity sha512-pmiXJgPQtAx6YOMXPCCO3AudMWv8Gnhfrprn0raqevofOhO95nJZ6bTEXkUVbzEwvYhvGxE0Yl888aZwuRGMGw== - dependencies: - commander "~6.2.0" - deep-extend "~0.6.0" - get-stdin "~8.0.0" - glob "~7.1.6" - ignore "~5.1.8" - js-yaml "~3.14.0" - jsonc-parser "~2.3.1" - lodash.differencewith "~4.5.0" - lodash.flatten "~4.4.0" - markdownlint "~0.21.1" - markdownlint-rule-helpers "~0.12.0" - minimatch "~3.0.4" - minimist "~1.2.5" - rc "~1.2.8" - -markdownlint-rule-helpers@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.12.0.tgz#c41d9b990c50911572e8eb2fba3e6975a5514b7e" - integrity sha512-Q7qfAk+AJvx82ZY52OByC4yjoQYryOZt6D8TKrZJIwCfhZvcj8vCQNuwDqILushtDBTvGFmUPq+uhOb1KIMi6A== - -markdownlint@^0.21.1, markdownlint@~0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.21.1.tgz#9442afcf12bf65ce9d613212028cf85741677421" - integrity sha512-8kc88w5dyEzlmOWIElp8J17qBgzouOQfJ0LhCcpBFrwgyYK6JTKvILsk4FCEkiNqHkTxwxopT2RS2DYb/10qqg== - dependencies: - markdown-it "11.0.0" +markdownlint-cli2-formatter-default@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.4.tgz#81e26b0a50409c0357c6f0d38d8246946b236fab" + integrity sha512-xm2rM0E+sWgjpPn1EesPXx5hIyrN2ddUnUwnbCsD/ONxYtw3PX6LydvdH6dciWAoFDpwzbHM1TO7uHfcMd6IYg== + +markdownlint-cli2@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/markdownlint-cli2/-/markdownlint-cli2-0.13.0.tgz#691cab01994295b4b8c87aa0485c0b1e0f792289" + integrity sha512-Pg4nF7HlopU97ZXtrcVISWp3bdsuc5M0zXyLp2/sJv2zEMlInrau0ZKK482fQURzVezJzWBpNmu4u6vGAhij+g== + dependencies: + globby "14.0.1" + js-yaml "4.1.0" + jsonc-parser "3.2.1" + markdownlint "0.34.0" + markdownlint-cli2-formatter-default "0.0.4" + micromatch "4.0.5" + +markdownlint-cli@^0.40.0: + version "0.40.0" + resolved "https://registry.yarnpkg.com/markdownlint-cli/-/markdownlint-cli-0.40.0.tgz#57678cabd543c654d2ea88f752e9ac058b31c207" + integrity sha512-JXhI3dRQcaqwiFYpPz6VJ7aKYheD53GmTz9y4D/d0F1MbZDGOp9pqKlbOfUX/pHP/iAoeiE4wYRmk8/kjLakxA== + dependencies: + commander "~12.0.0" + get-stdin "~9.0.0" + glob "~10.3.12" + ignore "~5.3.1" + js-yaml "^4.1.0" + jsonc-parser "~3.2.1" + jsonpointer "5.0.1" + markdownlint "~0.34.0" + minimatch "~9.0.4" + run-con "~1.3.2" + toml "~3.0.0" + +markdownlint-micromark@0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/markdownlint-micromark/-/markdownlint-micromark-0.1.9.tgz#4876996b60d4dceb3a02f4eee2d3a366eb9569fa" + integrity sha512-5hVs/DzAFa8XqYosbEAEg6ok6MF2smDj89ztn9pKkCtdKHVdPQuGMH7frFfYL9mLkvfFe4pTyAMffLbjf3/EyA== + +markdownlint@0.34.0, markdownlint@~0.34.0: + version "0.34.0" + resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.34.0.tgz#bbc2047c952d1644269009a69ba227ed597b23fa" + integrity sha512-qwGyuyKwjkEMOJ10XN6OTKNOVYvOIi35RNvDLNxTof5s8UmyGHlCdpngRHoRGNvQVGuxO3BJ7uNSgdeX166WXw== + dependencies: + markdown-it "14.1.0" + markdownlint-micromark "0.1.9" matcher-collection@^1.0.0: version "1.1.2" @@ -3859,42 +4450,79 @@ matcher-collection@^1.0.0: dependencies: minimatch "^3.0.2" +matcher@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" + integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng== + dependencies: + escape-string-regexp "^4.0.0" + mdast-comment-marker@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/mdast-comment-marker/-/mdast-comment-marker-1.1.1.tgz#9c9c18e1ed57feafc1965d92b028f37c3c8da70d" integrity sha512-TWZDaUtPLwKX1pzDIY48MkSUQRDwX/HqbTB4m3iYdL/zosi/Z6Xqfdv0C0hNVKvzrPjZENrpWDt4p4odeVO0Iw== -mdast-util-from-markdown@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.0.0.tgz#c517313cd999ec2b8f6d447b438c5a9d500b89c9" - integrity sha512-uj2G60sb7z1PNOeElFwCC9b/Se/lFXuLhVKFOAY2EHz/VvgbupTQRNXPoZl7rGpXYL6BNZgcgaybrlSWbo7n/g== +mdast-util-from-markdown@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894" + integrity sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g== dependencies: "@types/mdast" "^3.0.0" "@types/unist" "^2.0.0" - mdast-util-to-string "^3.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" micromark "^3.0.0" micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" micromark-util-normalize-identifier "^1.0.0" micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" - parse-entities "^3.0.0" unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + +mdast-util-from-markdown@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc" + integrity sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + mdast-util-to-string "^4.0.0" + micromark "^4.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-decode-string "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-stringify-position "^4.0.0" mdast-util-heading-style@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/mdast-util-heading-style/-/mdast-util-heading-style-1.0.5.tgz#81b2e60d76754198687db0e8f044e42376db0426" integrity sha512-8zQkb3IUwiwOdUw6jIhnwM6DPyib+mgzQuHAe7j2Hy1rIarU4VUxe472bp9oktqULW3xqZE+Kz6OD4Gi7IA3vw== -mdast-util-to-markdown@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.1.1.tgz#545ccc4dcc6672614b84fd1064482320dd689b12" - integrity sha512-4puev/CxuxVdlsx5lVmuzgdqfjkkJJLS1Zm/MnejQ8I7BLeeBlbkwp6WOGJypEcN8g56LbVbhNmn84MvvcAvSQ== +mdast-util-phrasing@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" + integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + +mdast-util-to-markdown@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" + integrity sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" longest-streak "^3.0.0" - mdast-util-to-string "^3.0.0" - parse-entities "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" zwitch "^2.0.0" mdast-util-to-string@^1.0.2: @@ -3902,20 +4530,27 @@ mdast-util-to-string@^1.0.2: resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.6.tgz#7d85421021343b33de1552fc71cb8e5b4ae7536d" integrity sha512-868pp48gUPmZIhfKrLbaDneuzGiw3OTDjHc5M1kAepR2CWBJ+HpEsm252K4aXdiP5coVZaJPOqGtVU6Po8xnXg== -mdast-util-to-string@^3.0.0: +mdast-util-to-string@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== +mdast-util-to-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" + integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== + dependencies: + "@types/mdast" "^4.0.0" + mdurl@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== memory-fs@^0.4.0: version "0.4.1" @@ -3925,11 +4560,6 @@ memory-fs@^0.4.0: errno "^0.1.3" readable-stream "^2.0.1" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -3940,11 +4570,6 @@ merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - micromark-core-commonmark@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.0.tgz#b767fa7687c205c224175bf067796360a3830350" @@ -3966,6 +4591,28 @@ micromark-core-commonmark@^1.0.0: micromark-util-types "^1.0.0" parse-entities "^3.0.0" +micromark-core-commonmark@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" + integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== + dependencies: + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-factory-destination "^2.0.0" + micromark-factory-label "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-factory-title "^2.0.0" + micromark-factory-whitespace "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-html-tag-name "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-destination@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" @@ -3975,6 +4622,15 @@ micromark-factory-destination@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-destination@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" + integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-label@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.0.tgz#b316ec479b474232973ff13b49b576f84a6f2cbb" @@ -3984,6 +4640,16 @@ micromark-factory-label@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-label@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" + integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== + dependencies: + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-space@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" @@ -3992,6 +4658,14 @@ micromark-factory-space@^1.0.0: micromark-util-character "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-space@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" + integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-title@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.0.tgz#708f7a8044f34a898c0efdb4f55e4da66b537273" @@ -4002,6 +4676,16 @@ micromark-factory-title@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-title@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" + integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-whitespace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" @@ -4012,6 +4696,16 @@ micromark-factory-whitespace@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" + integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-character@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" @@ -4020,6 +4714,14 @@ micromark-util-character@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-util-character@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" + integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-chunked@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" @@ -4027,6 +4729,13 @@ micromark-util-chunked@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-chunked@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" + integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-classify-character@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" @@ -4036,6 +4745,15 @@ micromark-util-classify-character@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-util-classify-character@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" + integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-combine-extensions@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" @@ -4044,6 +4762,14 @@ micromark-util-combine-extensions@^1.0.0: micromark-util-chunked "^1.0.0" micromark-util-types "^1.0.0" +micromark-util-combine-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" + integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== + dependencies: + micromark-util-chunked "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-decode-numeric-character-reference@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" @@ -4051,16 +4777,53 @@ micromark-util-decode-numeric-character-reference@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-decode-numeric-character-reference@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" + integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" + integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-encode@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.0.tgz#c409ecf751a28aa9564b599db35640fccec4c068" integrity sha512-cJpFVM768h6zkd8qJ1LNRrITfY4gwFt+tziPcIf71Ui8yFzY9wG3snZQqiWVq93PG4Sw6YOtcNiKJfVIs9qfGg== +micromark-util-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" + integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== + micromark-util-html-tag-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== +micromark-util-html-tag-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" + integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== + micromark-util-normalize-identifier@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" @@ -4068,6 +4831,13 @@ micromark-util-normalize-identifier@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-normalize-identifier@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" + integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-resolve-all@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" @@ -4075,6 +4845,13 @@ micromark-util-resolve-all@^1.0.0: dependencies: micromark-util-types "^1.0.0" +micromark-util-resolve-all@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" + integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== + dependencies: + micromark-util-types "^2.0.0" + micromark-util-sanitize-uri@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" @@ -4084,6 +4861,15 @@ micromark-util-sanitize-uri@^1.0.0: micromark-util-encode "^1.0.0" micromark-util-symbol "^1.0.0" +micromark-util-sanitize-uri@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" + integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-subtokenize@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.0.tgz#6f006fa719af92776c75a264daaede0fb3943c6a" @@ -4093,16 +4879,36 @@ micromark-util-subtokenize@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-util-subtokenize@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" + integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-symbol@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.0.tgz#91cdbcc9b2a827c0129a177d36241bcd3ccaa34d" integrity sha512-NZA01jHRNCt4KlOROn8/bGi6vvpEmlXld7EHcRH+aYWUfL3Wc8JLUNNlqUMKa0hhz6GrpUWsHtzPmKof57v0gQ== +micromark-util-symbol@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" + integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== + micromark-util-types@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.0.tgz#0ebdfaea3fa7c15fc82b1e06ea1ef0152d0fb2f0" integrity sha512-psf1WAaP1B77WpW4mBGDkTr+3RsPuDAgsvlP47GJzbH1jmjH8xjOx7Z6kp84L8oqHmy5pYO3Ev46odosZV+3AA== +micromark-util-types@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" + integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== + micromark@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.3.tgz#4c9f76fce8ba68eddf8730bb4fee2041d699d5b7" @@ -4125,54 +4931,68 @@ micromark@^3.0.0: micromark-util-types "^1.0.0" parse-entities "^3.0.0" -micromatch@^4.0.0, micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== +micromark@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" + integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromatch@4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27: +mime-types@^2.1.27: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== - dependencies: - mime-db "1.40.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + +mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -4182,97 +5002,166 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.1.tgz#6c9dffcf9927ff2a31e74b5af11adf8b9604b022" + integrity sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.0, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.1, minimatch@~9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimatch@~3.0.4: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== dependencies: brace-expansion "^1.1.7" -minimist@^1.0.0, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0, minimist@~1.2.5: +minimist@^1.0.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" + yallist "^4.0.0" + +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" + integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: + version "7.1.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.0.tgz#b545f84af94e567386770159302ca113469c80b8" + integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig== + +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: - minipass "^2.9.0" + minipass "^3.0.0" + yallist "^4.0.0" -mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@^0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== dependencies: minimist "^1.2.5" -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.1.2, ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nan@nodejs/nan#16fa32231e2ccd89d2804b3f765319128b20c4ac: - version "2.15.0" - resolved "https://codeload.github.com/nodejs/nan/tar.gz/16fa32231e2ccd89d2804b3f765319128b20c4ac" +nan@nodejs/nan#e14bdcd1f72d62bca1d541b66da43130384ec213: + version "2.18.0" + resolved "https://codeload.github.com/nodejs/nan/tar.gz/e14bdcd1f72d62bca1d541b66da43130384ec213" natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-fetch@^2.6.1: + version "2.6.8" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e" + integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg== + dependencies: + whatwg-url "^5.0.0" -node-fetch@^2.3.0, node-fetch@^2.6.7: +node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +nopt@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== + dependencies: + abbrev "^2.0.0" -normalize-package-data@^2.3.2: +normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -4282,21 +5171,57 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-package-data@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== + dependencies: + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +npm-install-checks@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" + integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== + dependencies: + semver "^7.1.1" + +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + +npm-package-arg@^11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.3.tgz#dae0c21199a99feca39ee4bfb074df3adac87e2d" + integrity sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw== + dependencies: + hosted-git-info "^7.0.0" + proc-log "^4.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + +npm-pick-manifest@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz#83562afde52b0b07cb6244361788d319ce7e8636" + integrity sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA== + dependencies: + npm-install-checks "^6.0.0" + npm-normalize-package-bin "^3.0.0" + npm-package-arg "^11.0.0" + semver "^7.3.5" + npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -4304,74 +5229,116 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -null-loader@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-4.0.0.tgz#8e491b253cd87341d82c0e84b66980d806dfbd04" - integrity sha512-vSoBF6M08/RHwc6r0gvB/xBJBtmbvvEkf6+IiadUCoNYchjxE8lwzCGFg0Qp2D25xPiJxUBh2iNWzlzGMILp7Q== +null-loader@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-4.0.1.tgz#8e63bd3a2dd3c64236a4679428632edd0a6dbc6a" + integrity sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg== dependencies: loader-utils "^2.0.0" - schema-utils "^2.6.5" + schema-utils "^3.0.0" object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-inspect@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== +object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" -object.entries@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add" - integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - has "^1.0.3" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.fromentries@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" - integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" -object.values@^1.1.0, object.values@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" + define-properties "^1.1.4" + es-abstract "^1.20.4" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= +object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - ee-first "1.1.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -4380,13 +5347,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - onetime@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" @@ -4394,85 +5354,45 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -optimist@~0.3.5: - version "0.3.7" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.7.tgz#c90941ad59e4273328923074d2cf2e7cbc6ec0d9" - integrity sha1-yQlBrVnkJzMokjB00s8ufLxuwNk= - dependencies: - wordwrap "~0.0.2" - -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== dependencies: - 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" + mimic-function "^5.0.0" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" - -ora@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" - integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== - dependencies: - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-spinners "^2.0.0" - log-symbols "^2.2.0" - strip-ansi "^5.2.0" - wcwidth "^1.0.1" - -ora@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.3.tgz#752a1b7b4be4825546a7a3d59256fa523b6b6d05" - integrity sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg== - dependencies: - chalk "^3.0.0" - cli-cursor "^3.1.0" - cli-spinners "^2.2.0" - is-interactive "^1.0.0" - log-symbols "^3.0.0" - mute-stream "0.0.8" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" + word-wrap "^1.2.5" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +ora@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-8.1.0.tgz#c3db2f9f83a2bec9e8ab71fe3b9ae234d65ca3a8" + integrity sha512-GQEkNkH/GHOhPFXcqZs3IDahXEQcQxsSjEkK4KvEEST4t7eNzoMjxTzef+EZ+JluDEV+Raoi3WQ2CflnRdSVnQ== + dependencies: + chalk "^5.3.0" + cli-cursor "^5.0.0" + cli-spinners "^2.9.2" + is-interactive "^2.0.0" + is-unicode-supported "^2.0.0" + log-symbols "^6.0.0" + stdin-discarder "^0.2.2" + string-width "^7.2.0" + strip-ansi "^7.1.0" p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" @@ -4487,12 +5407,12 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - p-limit "^1.1.0" + yocto-queue "^0.1.0" p-locate@^3.0.0: version "3.0.0" @@ -4508,6 +5428,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -4515,16 +5442,16 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -4552,13 +5479,6 @@ parse-gitignore@^0.4.0: array-unique "^0.3.2" is-glob "^3.1.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -4577,15 +5497,28 @@ parse-json@^5.0.0: json-parse-better-errors "^1.0.1" lines-and-columns "^1.1.6" -parse-ms@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" - integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== +parse-json@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-7.1.1.tgz#68f7e6f0edf88c54ab14c00eb700b753b14e2120" + integrity sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw== + dependencies: + "@babel/code-frame" "^7.21.4" + error-ex "^1.3.2" + json-parse-even-better-errors "^3.0.0" + lines-and-columns "^2.0.3" + type-fest "^3.8.0" + +parse-ms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-4.0.0.tgz#c0c058edd47c2a590151a718990533fd62803df4" + integrity sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw== -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" path-exists@^3.0.0: version "3.0.0" @@ -4602,11 +5535,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -4617,34 +5545,61 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-scurry@^1.6.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.9.2.tgz#90f9d296ac5e37e608028e28a447b11d385b3f63" + integrity sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg== dependencies: - pify "^2.0.0" + lru-cache "^9.1.1" + minipass "^5.0.0 || ^6.0.2" path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pathval@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +path-type@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8" + integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg== + +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picocolors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== -picomatch@^2.0.4, picomatch@^2.0.5: +picomatch@^2.0.4: version "2.0.7" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== @@ -4654,10 +5609,10 @@ picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^4.0.1: version "4.0.1" @@ -4672,22 +5627,6 @@ pkg-conf@^3.1.0: find-up "^3.0.0" load-json-file "^5.2.0" -pkg-config@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" - integrity sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q= - dependencies: - debug-log "^1.0.0" - find-root "^1.0.0" - xtend "^4.0.1" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -4707,43 +5646,35 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== -pre-flight@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pre-flight/-/pre-flight-1.1.1.tgz#482fb1649fb400616a86b2706b11591f5cc8402d" - integrity sha512-glqyc2Hh3K+sYeSsVs+HhjyUVf8j6xwuFej0yjYjRYfSnOK8P3Na9GznkoPn48fR+9kTOfkocYIWrtWktp4AqA== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +pre-flight@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pre-flight/-/pre-flight-2.0.0.tgz#5e7c09aa49dbaeb28b21cc5c7d49b0ad1ee63a78" + integrity sha512-uqrCBHAzVogOyI/79jsxbveioqA9GUK5MBbrwifEHlCFhi3BkEkDYxFEzNxxfkUBl43Gnqkniw1ZKGaTf/YvAA== dependencies: - colors "^1.1.2" - commander "^2.9.0" - semver "^5.1.0" + chalk "^5.3.0" + semver "^7.6.3" prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -pretty-ms@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-5.0.0.tgz#6133a8f55804b208e4728f6aa7bf01085e951e24" - integrity sha512-94VRYjL9k33RzfKiGokPBPpsmloBYSf5Ri+Pq19zlsEcUKFob+admeXr5eFDRuPjFmEOcjJvPGdillYOJyvZ7Q== +pretty-ms@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.1.0.tgz#0ad44de6086454f48a168e5abb3c26f8db1b3253" + integrity sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw== dependencies: - parse-ms "^2.1.0" + parse-ms "^4.0.0" -pretty-ms@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-5.1.0.tgz#b906bdd1ec9e9799995c372e2b1c34f073f95384" - integrity sha512-4gaK1skD2gwscCfkswYQRmddUb2GJZtzDGRjHWadVHtK/DIKFufa12MvES6/xu1tVbUYeia5bmLcwJtZJQUqnw== - dependencies: - parse-ms "^2.1.0" +proc-log@^4.0.0, proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== process-nextick-args@~2.0.0: version "2.0.1" @@ -4755,38 +5686,43 @@ process@^0.11.10, process@~0.11.0: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" -proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.0" +property-information@^6.0.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" + integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= -psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -4795,35 +5731,37 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +qs@^6.12.3: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" quick-lru@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -ramda@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.0.tgz#915dc29865c0800bf3f69b8fd6c279898b59de43" - integrity sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA== +rambda@^7.4.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe" + integrity sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA== randombytes@^2.1.0: version "2.1.0" @@ -4832,52 +5770,37 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -rc@~1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== +read-package-json-fast@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" + integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" + json-parse-even-better-errors "^3.0.0" + npm-normalize-package-bin "^3.0.0" -react-is@^16.8.1: - version "16.8.6" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" - integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" readable-stream@^2, readable-stream@^2.0.1, readable-stream@~2.3.6: version "2.3.6" @@ -4915,35 +5838,58 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -rechoir@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" - integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== dependencies: - resolve "^1.9.0" + resolve "^1.20.0" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +regexp-tree@^0.1.27: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + +regexp.prototype.flags@^1.4.3: + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + functions-have-names "^1.2.3" + +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" regexpp@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== +regjsparser@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.10.0.tgz#b1ed26051736b436f22fdec1c8f72635f9f44892" + integrity sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA== + dependencies: + jsesc "~0.5.0" -remark-cli@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/remark-cli/-/remark-cli-10.0.0.tgz#3b0e20f2ad3909f35c7a6fb3f721c82f6ff5beac" - integrity sha512-Yc5kLsJ5vgiQJl6xMLLJHqPac6OSAC5DOqKQrtmzJxSdJby2Jgr+OpIAkWQYwvbNHEspNagyoQnuwK2UCWg73g== +remark-cli@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/remark-cli/-/remark-cli-12.0.1.tgz#991ede01adfdf0471177c381168105da4b93f99a" + integrity sha512-2NAEOACoTgo+e+YAaCTODqbrWyhMVmlUyjxNCkTrDRHHQvH6+NbrnqVvQaLH/Q8Ket3v90A43dgAJmXv8y5Tkw== dependencies: - remark "^14.0.0" - unified-args "^9.0.0" + import-meta-resolve "^4.0.0" + markdown-extensions "^2.0.0" + remark "^15.0.0" + unified-args "^11.0.0" remark-lint-blockquote-indentation@^2.0.0: version "2.0.1" @@ -5389,14 +6335,15 @@ remark-message-control@^6.0.0: mdast-comment-marker "^1.0.0" unified-message-control "^3.0.0" -remark-parse@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.0.tgz#65e2b2b34d8581d36b97f12a2926bb2126961cb4" - integrity sha512-07ei47p2Xl7Bqbn9H2VYQYirnAFJPwdMuypdozWsSbnmrkgA2e2sZLZdnDNrrsxR4onmIzH/J6KXqKxCuqHtPQ== +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" remark-preset-lint-markdown-style-guide@^4.0.0: version "4.0.0" @@ -5449,34 +6396,29 @@ remark-preset-lint-markdown-style-guide@^4.0.0: remark-lint-table-pipes "^3.0.0" remark-lint-unordered-list-marker-style "^2.0.0" -remark-stringify@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.0.tgz#7f23659d92b2d5da489e3c858656d7bbe045f161" - integrity sha512-3LAQqJ/qiUxkWc7fUcVuB7RtIT38rvmxfmJG8z1TiE/D8zi3JGQ2tTcTJu9Tptdpb7gFwU0whRi5q1FbFOb9yA== +remark-stringify@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3" + integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-markdown "^2.0.0" + unified "^11.0.0" -remark@^14.0.0: - version "14.0.1" - resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.1.tgz#a97280d4f2a3010a7d81e6c292a310dcd5554d80" - integrity sha512-7zLG3u8EUjOGuaAS9gUNJPD2j+SqDqAFHv2g6WMpE5CU9rZ6e3IKDM12KHZ3x+YNje+NMAuN55yx8S5msGSx7Q== +remark@^15.0.0: + version "15.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-15.0.1.tgz#ac7e7563260513b66426bc47f850e7aa5862c37c" + integrity sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A== dependencies: - "@types/mdast" "^3.0.0" - remark-parse "^10.0.0" - remark-stringify "^10.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" -repeat-string@^1.0.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -requireindex@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" - integrity sha1-5UBLgVV+91225JxacgBIk/4D4WI= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== resolve-alpn@^1.0.0: version "1.2.1" @@ -5500,6 +6442,11 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve@^1.1.6: version "1.21.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" @@ -5509,35 +6456,39 @@ resolve@^1.1.6: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.10.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" - integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== +resolve@^1.10.0, resolve@^1.22.1: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - path-parse "^1.0.6" + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.17.0: +resolve@^1.10.1: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: path-parse "^1.0.6" -resolve@^1.9.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== +resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= +resolve@^2.0.0-next.4: + version "2.0.0-next.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== dependencies: - lowercase-keys "^1.0.0" + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" responselike@^2.0.0: version "2.0.0" @@ -5546,14 +6497,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -5562,78 +6505,128 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== + dependencies: + onetime "^7.0.0" + signal-exit "^4.1.0" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3, rimraf@^2.5.4: +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rimraf@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" + integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== + dependencies: + glob "^9.2.0" + +rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= +roarr@^2.15.3: + version "2.15.4" + resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" + integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A== + dependencies: + boolean "^3.0.1" + detect-node "^2.0.4" + globalthis "^1.0.1" + json-stringify-safe "^5.0.1" + semver-compare "^1.0.0" + sprintf-js "^1.1.2" -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-con@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/run-con/-/run-con-1.3.2.tgz#755860a10ce326a96b509485fcea50b4d03754e8" + integrity sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg== + dependencies: + deep-extend "^0.6.0" + ini "~4.1.0" + minimist "^1.2.8" + strip-json-comments "~3.1.1" -run-parallel@^1.1.2, run-parallel@^1.1.9: +run-parallel@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== -rxjs@^6.5.5, rxjs@^6.6.0: +rxjs@^6.5.5: version "6.6.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84" integrity sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg== dependencies: tslib "^1.9.0" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" -schema-utils@^2.6.5: - version "2.7.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" -schema-utils@^3.1.0, schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== dependencies: "@types/json-schema" "^7.0.8" ajv "^6.12.5" @@ -5644,78 +6637,63 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", semver@^5.6.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^5.1.0, semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" - integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== +semver@^7.0.0, semver@^7.3.2, semver@^7.3.5, semver@^7.3.8: + version "7.5.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" + integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ== + dependencies: + lru-cache "^6.0.0" -semver@^6.1.0, semver@^6.1.2: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.1.1, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.1, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -semver@^7.0.0: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== +serialize-error@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" + integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw== dependencies: - lru-cache "^6.0.0" + type-fest "^0.13.1" -semver@^7.2.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" + 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" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" shallow-clone@^3.0.0: version "3.0.1" @@ -5724,13 +6702,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -5738,17 +6709,12 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shelljs@^0.8.1: +shelljs@^0.8.5: version "0.8.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== @@ -5757,33 +6723,56 @@ shelljs@^0.8.1: interpret "^1.0.0" rechoir "^0.6.2" -shx@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.2.tgz#40501ce14eb5e0cbcac7ddbd4b325563aad8c123" - integrity sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA== +shx@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02" + integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== dependencies: - es6-object-assign "^1.0.3" - minimist "^1.2.0" - shelljs "^0.8.1" + minimist "^1.2.3" + shelljs "^0.8.5" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== +simple-git@^3.5.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.16.0.tgz#421773e24680f5716999cc4a1d60127b4b6a9dec" + integrity sha512-zuWYsOLEhbJRWVxpjdiXl6eyAyGo/KzVW+KFhhw9MqEEJttcq+32jTWSGyxTdf9e/YCohxRE+9xpWFj9FdiJNw== dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" + "@kwsites/file-exists" "^1.1.1" + "@kwsites/promise-deferred" "^1.1.1" + debug "^4.3.4" + +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== slice-ansi@^3.0.0: version "3.0.0" @@ -5829,104 +6818,101 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" - integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +sprintf-js@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -standard-engine@^12.0.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-12.1.0.tgz#b13dbae583de54c06805207b991ef48a582c0e62" - integrity sha512-DVJnWM1CGkag4ucFLGdiYWa5/kJURPONmMmk17p8FT5NE4UnPZB1vxWnXnRo2sPSL78pWJG8xEM+1Tu19z0deg== +standard-engine@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-15.0.0.tgz#e37ca2e1a589ef85431043a3e87cb9ce95a4ca4e" + integrity sha512-4xwUhJNo1g/L2cleysUqUv7/btn7GEbYJvmgKrQ2vd/8pkTmN8cpqAZg+BT8Z1hNeEH787iWUdOpL8fmApLtxA== dependencies: - deglob "^4.0.1" - get-stdin "^7.0.0" - minimist "^1.2.5" + get-stdin "^8.0.0" + minimist "^1.2.6" pkg-conf "^3.1.0" + xdg-basedir "^4.0.0" + +standard@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/standard/-/standard-17.0.0.tgz#85718ecd04dc4133908434660788708cca855aa1" + integrity sha512-GlCM9nzbLUkr+TYR5I2WQoIah4wHA2lMauqbyPLV/oI5gJxqhHzhjl9EG2N0lr/nRqI3KCbCvm/W3smxvLaChA== + dependencies: + eslint "^8.13.0" + eslint-config-standard "17.0.0" + eslint-config-standard-jsx "^11.0.0" + eslint-plugin-import "^2.26.0" + eslint-plugin-n "^15.1.0" + eslint-plugin-promise "^6.0.0" + eslint-plugin-react "^7.28.0" + standard-engine "^15.0.0" + +stdin-discarder@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.2.2.tgz#390037f44c4ae1a1ae535c5fe38dc3aba8d997be" + integrity sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ== -standard-markdown@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/standard-markdown/-/standard-markdown-6.0.0.tgz#bb7519a86275900eaa7a951d98937723c7010ed6" - integrity sha512-9lQs4ZfGukyalFVputnN4IxfbMIAECjf+BqC4gvY8eBUvYcotYIWj4MZyMiXBkN/OJwmMi5jVSnzIexKZQqQYA== - dependencies: - commander "^4.1.0" - globby "^11.0.0" - lodash.flatten "^4.4.0" - lodash.range "^3.2.0" - ora "^4.0.3" - standard "^14.3.1" - -standard@^14.3.1: - version "14.3.4" - resolved "https://registry.yarnpkg.com/standard/-/standard-14.3.4.tgz#748e80e8cd7b535844a85a12f337755a7e3a0f6e" - integrity sha512-+lpOkFssMkljJ6eaILmqxHQ2n4csuEABmcubLTb9almFi1ElDzXb1819fjf/5ygSyePCq4kU2wMdb2fBfb9P9Q== - dependencies: - eslint "~6.8.0" - eslint-config-standard "14.1.1" - eslint-config-standard-jsx "8.1.0" - eslint-plugin-import "~2.18.0" - eslint-plugin-node "~10.0.0" - eslint-plugin-promise "~4.2.1" - eslint-plugin-react "~7.14.2" - eslint-plugin-standard "~4.0.0" - standard-engine "^12.0.0" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stream-chain@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.3.tgz#44cfa21ab673e53a3f1691b3d1665c3aceb1983b" - integrity sha512-w+WgmCZ6BItPAD3/4HD1eDiDHRLhjSSyIV+F0kcmmRyz8Uv9hvQF22KyaiAUmOlmX3pJ6F95h+C191UbS8Oe/g== +stream-chain@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09" + integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== -stream-json@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.7.1.tgz#ec7e414c2eba456c89a4b4e5223794eabc3860c4" - integrity sha512-I7g0IDqvdJXbJ279/D3ZoTx0VMhmKnEF7u38CffeWdF8bfpMPsLo+5fWnkNjO2GU/JjWaRjdH+zmH03q+XGXFw== +stream-json@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.8.0.tgz#53f486b2e3b4496c506131f8d7260ba42def151c" + integrity sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw== dependencies: - stream-chain "^2.2.3" + stream-chain "^2.2.5" string-argv@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" @@ -5937,30 +6923,101 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.0.0.tgz#19191f152f937b96f4ec54ba0986a5656660c5a2" - integrity sha512-zwXcRmLUdiWhMPrHz6EXITuyTgcEnUqDzspTkCLhQovxywWz6NP9VHgqfVg20V/1mUg0B95AKbXxNT+ALRmqCw== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: + eastasianwidth "^0.2.0" emoji-regex "^9.2.2" - is-fullwidth-code-point "^4.0.0" - strip-ansi "^7.0.0" + strip-ansi "^7.0.1" -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== +string-width@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-6.1.0.tgz#96488d6ed23f9ad5d82d13522af9e4c4c3fd7518" + integrity sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" + eastasianwidth "^0.2.0" + emoji-regex "^10.2.1" + strip-ansi "^7.0.1" -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== +string-width@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + +string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -5985,46 +7042,60 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^4.1.0" + ansi-regex "^5.0.1" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" -strip-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0" - integrity sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg== +strip-ansi@^7.0.0, strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - ansi-regex "^6.0.0" + ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.0.1, strip-json-comments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" - integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + +sumchecker@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" + integrity sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg== + dependencies: + debug "^4.1.0" supports-color@^5.3.0: version "5.5.0" @@ -6059,16 +7130,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - tap-parser@~1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-1.2.2.tgz#5e2f6970611f079c7cf857de1dc7aa1b480de7a5" @@ -6102,45 +7163,44 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar@^4.4.7: - version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== - dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" - -temp@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= - dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" - -terser-webpack-plugin@^5.1.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" - integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== - dependencies: - "@jridgewell/trace-mapping" "^0.3.7" +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + 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" + +temp@^0.9.4: + version "0.9.4" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.4.tgz#cd20a8580cb63635d0e4e9d4bd989d44286e7620" + integrity sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA== + dependencies: + mkdirp "^0.5.1" + rimraf "~2.6.2" + +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" jest-worker "^27.4.5" schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - terser "^5.7.2" + serialize-javascript "^6.0.1" + terser "^5.26.0" -terser@^5.7.2: - version "5.14.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" - integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== +terser@^5.26.0: + version "5.32.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.32.0.tgz#ee811c0d2d6b741c1cc34a2bc5bcbfc1b5b1f96c" + integrity sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -6157,7 +7217,7 @@ through2@~2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6, through@^2.3.8: +through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -6169,18 +7229,6 @@ timers-browserify@1.4.2: dependencies: process "~0.11.0" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6188,27 +7236,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-vfile@^7.0.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/to-vfile/-/to-vfile-7.2.1.tgz#fe42892024f724177ba81076f98ee74b0888c293" - integrity sha512-biljADNq2n+AZn/zX+/87zStnIqctKr/q5OaOD8+qSKINokUGPbWBShvxa1iLUgHz6dGGjVnQPNoFRtVBzMkVg== - dependencies: - is-buffer "^2.0.0" - vfile "^5.0.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" +toml@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== tr46@~0.0.3: version "0.0.3" @@ -6220,6 +7251,11 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.0.2.tgz#94a3aa9d5ce379fc561f6244905b3f36b7458d96" integrity sha512-FnHq5sTMxC0sk957wHDzRnemFnNBvt/gSY99HzK8F7UP5WAbvP70yX5bd7CjEQkN+TjdxwI7g7lJ6podqrG2/w== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-loader@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.2.tgz#ee73ca9350f745799396fff8578ba29b1e95616b" @@ -6245,17 +7281,27 @@ ts-node@6.2.0: source-map-support "^0.5.6" yn "^2.0.0" -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== +tsconfig-paths@^3.14.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== 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" + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== @@ -6265,17 +7311,10 @@ tslib@^2.0.0, tslib@^2.2.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -tunnel@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +tslib@^2.6.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -6284,99 +7323,175 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - type-fest@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== +type-fest@^3.8.0: + version "3.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" + integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== + +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + 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" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + 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" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" + 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" typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.5.5: - version "4.5.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" - integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== +typescript@^5.6.2: + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== -unified-args@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/unified-args/-/unified-args-9.0.2.tgz#0c14f555e73ee29c23f9a567942e29069f56e5a2" - integrity sha512-qSqryjoqfJSII4E4Z2Jx7MhXX2MuUIn6DsrlmL8UnWFdGtrWvEtvm7Rx5fKT5TPUz7q/Fb4oxwIHLCttvAuRLQ== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + +unified-args@^11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/unified-args/-/unified-args-11.0.1.tgz#5c82564616288b8d99feed7326c2223097d30726" + integrity sha512-WEQghE91+0s3xPVs0YW6a5zUduNLjmANswX7YbBfksHNDGMjHxaWCql4SR7c9q0yov/XiIEdk6r/LqfPjaYGcw== dependencies: "@types/text-table" "^0.2.0" - camelcase "^6.0.0" - chalk "^4.0.0" + chalk "^5.0.0" chokidar "^3.0.0" - fault "^2.0.0" + comma-separated-tokens "^2.0.0" json5 "^2.0.0" minimist "^1.0.0" + strip-ansi "^7.0.0" text-table "^0.2.0" - unified-engine "^9.0.0" + unified-engine "^11.0.0" -unified-engine@^9.0.0: - version "9.0.3" - resolved "https://registry.yarnpkg.com/unified-engine/-/unified-engine-9.0.3.tgz#c1d57e67d94f234296cbfa9364f43e0696dae016" - integrity sha512-SgzREcCM2IpUy3JMFUcPRZQ2Py6IwvJ2KIrg2AiI7LnGge6E6OPFWpcabHrEXG0IvO2OI3afiD9DOcQvvZfXDQ== +unified-engine@^11.0.0: + version "11.2.1" + resolved "https://registry.yarnpkg.com/unified-engine/-/unified-engine-11.2.1.tgz#8f9c05b3f262930666b1cdb83108c15dd39d6cdd" + integrity sha512-xBAdZ8UY2X4R9Hm6X6kMne4Nz0PlpOc1oE6DPeqJnewr5Imkb8uT5Eyvy1h7xNekPL3PSWh3ZJyNrMW6jnNQBg== dependencies: - "@types/concat-stream" "^1.0.0" + "@types/concat-stream" "^2.0.0" "@types/debug" "^4.0.0" "@types/is-empty" "^1.0.0" - "@types/js-yaml" "^4.0.0" - "@types/node" "^16.0.0" - "@types/unist" "^2.0.0" + "@types/node" "^20.0.0" + "@types/unist" "^3.0.0" concat-stream "^2.0.0" debug "^4.0.0" - fault "^2.0.0" - glob "^7.0.0" + extend "^3.0.0" + glob "^10.0.0" ignore "^5.0.0" - is-buffer "^2.0.0" is-empty "^1.0.0" is-plain-obj "^4.0.0" - js-yaml "^4.0.0" - load-plugin "^4.0.0" - parse-json "^5.0.0" - to-vfile "^7.0.0" + load-plugin "^6.0.0" + parse-json "^7.0.0" trough "^2.0.0" - unist-util-inspect "^7.0.0" - vfile-message "^3.0.0" - vfile-reporter "^7.0.0" - vfile-statistics "^2.0.0" + unist-util-inspect "^8.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + vfile-reporter "^8.0.0" + vfile-statistics "^3.0.0" + yaml "^2.0.0" unified-lint-rule@^1.0.0: version "1.0.4" @@ -6393,23 +7508,18 @@ unified-message-control@^3.0.0: unist-util-visit "^2.0.0" vfile-location "^3.0.0" -unified@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.0.tgz#4e65eb38fc2448b1c5ee573a472340f52b9346fe" - integrity sha512-4U3ru/BRXYYhKbwXV6lU6bufLikoAavTwev89H5UxY8enDFaAT2VXmIXYNm6hb5oHPng/EXr77PVyDFcptbk5g== +unified@^11.0.0: + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" bail "^2.0.0" + devlop "^1.0.0" extend "^3.0.0" - is-buffer "^2.0.0" is-plain-obj "^4.0.0" trough "^2.0.0" - vfile "^5.0.0" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + vfile "^6.0.0" unist-util-generated@^1.0.0: version "1.1.6" @@ -6421,18 +7531,30 @@ unist-util-generated@^1.1.0: resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.4.tgz#2261c033d9fc23fae41872cdb7663746e972c1a7" integrity sha512-SA7Sys3h3X4AlVnxHdvN/qYdr4R38HzihoEVY2Q2BZu8NHWDnw5OGcC/tXWjQfd4iG+M6qRFNIRGqJmp2ez4Ww== -unist-util-inspect@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/unist-util-inspect/-/unist-util-inspect-7.0.0.tgz#98426f0219e24d011a27e32539be0693d9eb973e" - integrity sha512-2Utgv78I7PUu461Y9cdo+IUiiKSKpDV5CE/XD6vTj849a3xlpDAScvSJ6cQmtFBGgAmCn2wR7jLuXhpg1XLlJw== +unist-util-inspect@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/unist-util-inspect/-/unist-util-inspect-8.1.0.tgz#ff2729b543c483041b3c29cbe04c5460a406ee25" + integrity sha512-mOlg8Mp33pR0eeFpo5d2902ojqFFOKMMG2hF8bmH7ZlhnmjFgh0NI3/ZDwdaBJNbvrS7LZFVrBVtIE9KZ9s7vQ== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" unist-util-is@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== +unist-util-is@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" + integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== + +unist-util-is@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" + integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-position@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.0.3.tgz#fff942b879538b242096c148153826664b1ca373" @@ -6452,6 +7574,13 @@ unist-util-stringify-position@^3.0.0: dependencies: "@types/unist" "^2.0.0" +unist-util-stringify-position@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" + integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== + dependencies: + "@types/unist" "^3.0.0" + unist-util-visit-parents@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" @@ -6460,6 +7589,22 @@ unist-util-visit-parents@^3.0.0: "@types/unist" "^2.0.0" unist-util-is "^4.0.0" +unist-util-visit-parents@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz#868f353e6fce6bf8fa875b251b0f4fec3be709bb" + integrity sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit-parents@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" + integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" @@ -6469,20 +7614,38 @@ unist-util-visit@^2.0.0: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" -universal-github-app-jwt@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.0.tgz#0abaa876101cdf1d3e4c546be2768841c0c1b514" - integrity sha512-3b+ocAjjz4JTyqaOT+NNBd5BtTuvJTxWElIoeHSVelUV9J3Jp7avmQTdLKCaoqi/5Ox2o/q+VK19TJ233rVXVQ== +unist-util-visit@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2" + integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.1.1" + +unist-util-visit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" + integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + +universal-github-app-jwt@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.1.tgz#d57cee49020662a95ca750a057e758a1a7190e6e" + integrity sha512-G33RTLrIBMFmlDV4u4CBF7dh71eWwykck4XgaxaIVeZKOYZRAAxvcGMRFTUclVY6xoUPQvO4Ne5wKGxYm/Yy9w== dependencies: - "@types/jsonwebtoken" "^8.3.3" - jsonwebtoken "^8.5.1" + "@types/jsonwebtoken" "^9.0.0" + jsonwebtoken "^9.0.0" universal-user-agent@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -universalify@^0.1.0, universalify@^0.1.2: +universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== @@ -6492,18 +7655,18 @@ universalify@^1.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -update-browserslist-db@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" - integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2: version "4.4.1" @@ -6512,47 +7675,30 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" - integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= +url@^0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.4.tgz#adca77b3562d56b72746e76b330b7f27b6721f3c" + integrity sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg== dependencies: - punycode "1.3.2" - querystring "0.2.0" + punycode "^1.4.1" + qs "^6.12.3" util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== +uvu@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" + integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" -validate-npm-package-license@^3.0.1: +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== @@ -6560,61 +7706,120 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== vfile-location@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA== -vfile-message@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.0.1.tgz#b9bcf87cb5525e61777e0c6df07e816a577588a3" - integrity sha512-gYmSHcZZUEtYpTmaWaFJwsuUD70/rTY4v09COp8TGtOkix6gGxb/a8iTQByIY9ciTk9GwAwIXd/J9OPfM4Bvaw== +vfile-location@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3" + integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^3.0.0" + "@types/unist" "^3.0.0" + vfile "^6.0.0" -vfile-reporter@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-7.0.1.tgz#759bfebb995f3dc8c644284cb88ac4b310ebd168" - integrity sha512-pof+cQSJCUNmHG6zoBOJfErb6syIWHWM14CwKjsugCixxl4CZdrgzgxwLBW8lIB6czkzX0Agnnhj33YpKyLvmA== +vfile-message@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" + integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-stringify-position "^4.0.0" + +vfile-reporter@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-8.1.1.tgz#ac06a5a68f1b480609c443062dffea1cfa2d11b1" + integrity sha512-qxRZcnFSQt6pWKn3PAk81yLK2rO2i7CDXpy8v8ZquiEOMLSnPw6BMSi9Y1sUCwGGl7a9b3CJT1CKpnRF7pp66g== dependencies: - "@types/repeat-string" "^1.0.0" "@types/supports-color" "^8.0.0" - repeat-string "^1.0.0" - string-width "^5.0.0" + string-width "^6.0.0" supports-color "^9.0.0" - unist-util-stringify-position "^3.0.0" - vfile-sort "^3.0.0" - vfile-statistics "^2.0.0" + unist-util-stringify-position "^4.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + vfile-sort "^4.0.0" + vfile-statistics "^3.0.0" + +vfile-sort@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vfile-sort/-/vfile-sort-4.0.0.tgz#fa1929065b62fe5311e5391c9434f745e8641703" + integrity sha512-lffPI1JrbHDTToJwcq0rl6rBmkjQmMuXkAxsZPRS9DXbaJQvc642eCg6EGxcX2i1L+esbuhq+2l9tBll5v8AeQ== + dependencies: + vfile "^6.0.0" + vfile-message "^4.0.0" -vfile-sort@^3.0.0: +vfile-statistics@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/vfile-sort/-/vfile-sort-3.0.0.tgz#ee13d3eaac0446200a2047a3b45d78fad6b106e6" - integrity sha512-fJNctnuMi3l4ikTVcKpxTbzHeCgvDhnI44amA3NVDvA6rTC6oKCFpCVyT5n2fFMr3ebfr+WVQZedOCd73rzSxg== + resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-3.0.0.tgz#0f5cd00c611c1862b13a9b5bc5599efaf465f2cf" + integrity sha512-/qlwqwWBWFOmpXujL/20P+Iuydil0rZZNglR+VNm6J0gpLHwuVM5s7g2TfVoswbXjZ4HuIhLMySEyIw5i7/D8w== dependencies: - vfile-message "^3.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" -vfile-statistics@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-2.0.0.tgz#f04ee3e3c666809a3c10c06021becd41ea9c8037" - integrity sha512-foOWtcnJhKN9M2+20AOTlWi2dxNfAoeNIoxD5GXcO182UJyId4QrXa41fWrgcfV3FWTjdEDy3I4cpLVcQscIMA== +vfile@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.2.tgz#ef49548ea3d270097a67011921411130ceae7deb" + integrity sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg== dependencies: - vfile-message "^3.0.0" + "@types/unist" "^3.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" -vfile@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.0.2.tgz#57773d1d91478b027632c23afab58ec3590344f0" - integrity sha512-5cV+K7tX83MT3bievROc+7AvHv0GXDB0zqbrTjbOe+HRbkzvY4EP+wS3IR77kUBCoWFMdG9py18t0sesPtQ1Rw== +vscode-jsonrpc@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz#cb9989c65e219e18533cc38e767611272d274c94" + integrity sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw== + +vscode-languageserver-protocol@3.17.3: + version "3.17.3" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz#6d0d54da093f0c0ee3060b81612cce0f11060d57" + integrity sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA== dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" + vscode-jsonrpc "8.1.0" + vscode-languageserver-types "3.17.3" + +vscode-languageserver-textdocument@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz#16df468d5c2606103c90554ae05f9f3d335b771b" + integrity sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg== + +vscode-languageserver-textdocument@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz#9eae94509cbd945ea44bca8dcfe4bb0c15bb3ac0" + integrity sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q== + +vscode-languageserver-types@3.17.3: + version "3.17.3" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz#72d05e47b73be93acb84d6e311b5786390f13f64" + integrity sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA== + +vscode-languageserver-types@^3.17.1: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== + +vscode-languageserver@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.1.0.tgz#5024253718915d84576ce6662dd46a791498d827" + integrity sha512-eUt8f1z2N2IEUDBsKaNapkz7jl5QpskN2Y0G01T/ItMxBxw1fJwvtySGB9QMecatne8jFIWJGWI61dWjyTLQsw== + dependencies: + vscode-languageserver-protocol "3.17.3" + +vscode-uri@^3.0.3: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== + +vscode-uri@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8" + integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA== walk-sync@^0.3.2: version "0.3.4" @@ -6624,42 +7829,46 @@ walk-sync@^0.3.2: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -watchpack@^2.3.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +walk-up-path@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" + integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== + +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" +web-namespaces@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" + integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= -webpack-cli@^4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" - integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.2.0" - "@webpack-cli/info" "^1.5.0" - "@webpack-cli/serve" "^1.7.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" colorette "^2.0.14" - commander "^7.0.0" + commander "^10.0.1" cross-spawn "^7.0.3" + envinfo "^7.7.3" fastest-levenshtein "^1.0.12" import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" + interpret "^3.1.1" + rechoir "^0.8.0" webpack-merge "^5.7.3" webpack-merge@^5.7.3: @@ -6675,34 +7884,33 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5, webpack@^5.73.0: - version "5.73.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38" - integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^0.0.51" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.4.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" +webpack@^5, webpack@^5.95.0: + version "5.95.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.95.0.tgz#8fd8c454fa60dad186fbe36c400a55848307b4c0" + integrity sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q== + dependencies: + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.9.3" - es-module-lexer "^0.9.0" + enhanced-resolve "^5.17.1" + es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.1.0" + schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.3.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" webpack-sources "^3.2.3" whatwg-url@^5.0.0: @@ -6713,12 +7921,39 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - isexe "^2.0.0" + 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" + +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + 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" + +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" which@^2.0.1: version "2.0.2" @@ -6727,20 +7962,31 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + wildcard@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^6.2.0: version "6.2.0" @@ -6751,6 +7997,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrapped@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wrapped/-/wrapped-1.0.1.tgz#c783d9d807b273e9b01e851680a938c87c907242" @@ -6769,33 +8024,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -xml2js@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xml2js@^0.4.19: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== xmlbuilder@~4.2.0: version "4.2.1" @@ -6804,21 +8036,11 @@ xmlbuilder@~4.2.0: dependencies: lodash "^4.0.0" -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - -xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -yallist@^3.0.0, yallist@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -6829,11 +8051,34 @@ yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== +yaml@^2.0.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.0.tgz#14059ad9d0b1680d0f04d3a60fe00f3a857303c3" + integrity sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ== + +yaml@^2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" + integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg== + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zwitch@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1"