From fdd82e800e34c71ecf9766a4c0981cf02433dc9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 03:15:36 +0000 Subject: [PATCH 01/43] build(deps): bump gradle/actions from 4.4.3 to 5.0.0 Bumps [gradle/actions](https://github.com/gradle/actions) from 4.4.3 to 5.0.0. - [Release notes](https://github.com/gradle/actions/releases) - [Commits](https://github.com/gradle/actions/compare/ed408507eac070d1f99cc633dbcf757c94c7933a...4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2) --- updated-dependencies: - dependency-name: gradle/actions dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7d50bbf326..f0a1816a33 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -77,4 +77,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: gradle/actions/wrapper-validation@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/wrapper-validation@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 From a5298209d7383386901f39c2b587b16e2ecbe090 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 03:15:47 +0000 Subject: [PATCH 02/43] build(deps): bump ossf/scorecard-action from 2.4.2 to 2.4.3 Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.2 to 2.4.3. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/05b42c624433fc40578a4040d5cf5e36ddca8cde...4eaacf0543bb3f2c246792bd56e8cdeffafb205a) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-version: 2.4.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7d50bbf326..22f3d682d3 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif From 0b6bf6ba58018d205156ede87736482e18e7db44 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Sun, 12 Oct 2025 13:30:49 +0100 Subject: [PATCH 03/43] Use Maze Runner v10 [full ci] --- docker-compose.yml | 4 ++-- dockerfiles/Dockerfile.browser | 2 +- dockerfiles/Dockerfile.node | 2 +- test/aws-lambda/Gemfile | 2 +- test/browser/Gemfile | 2 +- test/node/Gemfile | 2 +- test/react-native-cli/Gemfile | 2 +- test/react-native/Gemfile | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 800cf12031..550a97d8b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -115,7 +115,7 @@ services: - ./reports/:/app/test/node/reports/ react-native-maze-runner: - image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v9-cli + image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v10-cli environment: <<: *common-environment BITBAR_USERNAME: @@ -139,7 +139,7 @@ services: - ./reports/:/app/reports react-native-cli-maze-runner: - image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v9-cli + image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v10-cli environment: <<: *common-environment BITBAR_USERNAME: diff --git a/dockerfiles/Dockerfile.browser b/dockerfiles/Dockerfile.browser index 251d42028d..f249209a51 100644 --- a/dockerfiles/Dockerfile.browser +++ b/dockerfiles/Dockerfile.browser @@ -55,7 +55,7 @@ RUN find . -name package.json -type f -mindepth 2 -maxdepth 3 ! -path "./node_mo RUN rm -fr **/*/node_modules/ # The maze-runner browser tests (W3C protocol) -FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v9-cli AS browser-maze-runner +FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v10-cli AS browser-maze-runner COPY --from=browser-feature-builder /app/test/browser /app/test/browser/ WORKDIR /app/test/browser diff --git a/dockerfiles/Dockerfile.node b/dockerfiles/Dockerfile.node index 09275fa94b..1b09c18c2c 100644 --- a/dockerfiles/Dockerfile.node +++ b/dockerfiles/Dockerfile.node @@ -22,7 +22,7 @@ RUN npm pack --verbose packages/plugin-restify/ RUN npm pack --verbose packages/plugin-hono/ # The maze-runner node tests -FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v9-cli as node-maze-runner +FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v10-cli as node-maze-runner WORKDIR /app/ COPY packages/node/ . COPY test/node/features test/node/features diff --git a/test/aws-lambda/Gemfile b/test/aws-lambda/Gemfile index 2c6a8f9ddf..3be2e6f61c 100644 --- a/test/aws-lambda/Gemfile +++ b/test/aws-lambda/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'bugsnag-maze-runner', '~>9.0' +gem 'bugsnag-maze-runner', '~>10.0' # Use a branch of Maze Runner # gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' diff --git a/test/browser/Gemfile b/test/browser/Gemfile index c1ff00ee7b..5066a995c9 100644 --- a/test/browser/Gemfile +++ b/test/browser/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'bugsnag-maze-runner', '~> 9.0' +gem 'bugsnag-maze-runner', '~> 10.0' # Use a branch of Maze Runner #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' diff --git a/test/node/Gemfile b/test/node/Gemfile index 29d3f3cccb..a911459674 100644 --- a/test/node/Gemfile +++ b/test/node/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'bugsnag-maze-runner', '~>8.0' +gem 'bugsnag-maze-runner', '~>10.0' # Use a branch of Maze Runner #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' diff --git a/test/react-native-cli/Gemfile b/test/react-native-cli/Gemfile index 9eb0d7678d..44c25e95eb 100644 --- a/test/react-native-cli/Gemfile +++ b/test/react-native-cli/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' gem 'cocoapods' gem 'xcodeproj', '< 1.26.0' -gem 'bugsnag-maze-runner', '~>9.0' +gem 'bugsnag-maze-runner', '~>10.0' # Use a branch of Maze Runner #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' diff --git a/test/react-native/Gemfile b/test/react-native/Gemfile index 206ecd5fde..2c9de72294 100644 --- a/test/react-native/Gemfile +++ b/test/react-native/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' gem 'cocoapods' gem 'xcodeproj', '< 1.26.0' -gem 'bugsnag-maze-runner', '~>9.0' +gem 'bugsnag-maze-runner', '~>10.0' # Use a branch of Maze Runner #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' From 56712b060bd821a3d082d0ce21cb9ac197b595e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 03:19:10 +0000 Subject: [PATCH 04/43] build(deps): bump ruby/setup-ruby from 1.263.0 to 1.265.0 Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.263.0 to 1.265.0. - [Release notes](https://github.com/ruby/setup-ruby/releases) - [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb) - [Commits](https://github.com/ruby/setup-ruby/compare/0481980f17b760ef6bca5e8c55809102a0af1e5a...ab177d40ee5483edb974554986f56b33477e21d0) --- updated-dependencies: - dependency-name: ruby/setup-ruby dependency-version: 1.265.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/update-dependencies.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index 1e24dcfc37..649a4235fd 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 - name: Install Ruby - uses: ruby/setup-ruby@0481980f17b760ef6bca5e8c55809102a0af1e5a + uses: ruby/setup-ruby@ab177d40ee5483edb974554986f56b33477e21d0 with: ruby-version: '3.1' diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index c7b01021f5..0b26069e77 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -40,7 +40,7 @@ jobs: - run: git submodule update --init --recursive - name: Install ruby - uses: ruby/setup-ruby@0481980f17b760ef6bca5e8c55809102a0af1e5a # v1.263.0 + uses: ruby/setup-ruby@ab177d40ee5483edb974554986f56b33477e21d0 # v1.265.0 with: ruby-version: 2.7 From b95a30dbb57e72f9f5281c0905005b2ec6b8d6dc Mon Sep 17 00:00:00 2001 From: Milo Clack Date: Mon, 13 Oct 2025 10:19:25 +0100 Subject: [PATCH 05/43] Fix `undefined is not a function` for `String.prototype.startsWith` (#2568) * Fix `undefined is not a function` for `String.prototype.startsWith` * Changelog entry added --------- Co-authored-by: Romain Menke <11521496+romainmenke@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/core/client.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee3a6adfbe..8482cfd9dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Update bugsnag-cocoa to [v6.33.1](https//github.com/bugsnag/bugsnag-cocoa/releases/tag/v6.33.1) [#2552](https://github.com/bugsnag/bugsnag-js/pull/2552) - Update bugsnag-android to [v6.18.0](https//github.com/bugsnag/bugsnag-android/releases/tag/v6.18.0) [#2556](https://github.com/bugsnag/bugsnag-js/pull/2556) +- (core): Change `startsWith()` to `indexOf() === 0` to support older browsers [#2568](https://github.com/bugsnag/bugsnag-js/pull/2568) ### Fixed diff --git a/packages/core/client.js b/packages/core/client.js index bb58111b95..04ec54eabc 100644 --- a/packages/core/client.js +++ b/packages/core/client.js @@ -169,7 +169,7 @@ class Client { // warn about an apikey that is not of the expected format if (!/^[0-9a-f]{32}$/i.test(config.apiKey)) errors.apiKey = 'should be a string of 32 hexadecimal characters' - if (opts.endpoints === undefined && config.apiKey.startsWith(HUB_PREFIX)) { + if (opts.endpoints === undefined && config.apiKey.indexOf(HUB_PREFIX) === 0) { config.endpoints = { notify: HUB_NOTIFY, sessions: HUB_SESSION From ebae0107e638b61830bae72f64896e9abe7b3f4d Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Thu, 16 Oct 2025 16:09:32 +0100 Subject: [PATCH 06/43] ci(react-native): add 0.81 and 0.82 to test matrix (#2594) * ci(react-native): add 0.82 to test matrix * ci(react-native): bump react-navigation dependencies for test fixtures --- .../react-native-android-full-pipeline.yml | 24 ++++-- .../basic/react-native-android-pipeline.yml | 73 ++----------------- .../basic/react-native-cli-pipeline.yml | 36 ++++----- .../basic/react-native-ios-full-pipeline.yml | 41 +++++++---- .../basic/react-native-ios-pipeline.yml | 70 +----------------- scripts/generate-react-native-fixture.js | 8 +- scripts/react-native/android-utils.js | 11 ++- 7 files changed, 84 insertions(+), 179 deletions(-) diff --git a/.buildkite/basic/react-native-android-full-pipeline.yml b/.buildkite/basic/react-native-android-full-pipeline.yml index a46747f7e7..6a5ba2aa9d 100644 --- a/.buildkite/basic/react-native-android-full-pipeline.yml +++ b/.buildkite/basic/react-native-android-full-pipeline.yml @@ -12,10 +12,10 @@ steps: key: "build-react-native-android-fixture-old-arch-full" timeout_in_minutes: 15 agents: - queue: macos-node-18 + queue: macos-15 env: JAVA_VERSION: "{{matrix.java}}" - NODE_VERSION: "18" + NODE_VERSION: "{{matrix.node}}" RN_VERSION: "{{matrix.reactnative}}" RCT_NEW_ARCH_ENABLED: "0" BUILD_ANDROID: "true" @@ -31,16 +31,21 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" java: - "17" + node: + - "22" adjustments: - with: reactnative: "0.68" java: "11" + node: "18" - with: reactnative: "0.69" java: "11" + node: "18" retry: automatic: - exit_status: "*" @@ -50,10 +55,10 @@ steps: key: "build-react-native-android-fixture-new-arch-full" timeout_in_minutes: 15 agents: - queue: macos-node-18 + queue: macos-15 env: JAVA_VERSION: "17" - NODE_VERSION: "18" + NODE_VERSION: "22" RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_ANDROID: "true" @@ -71,7 +76,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" - label: ':android: Build react-native-navigation {{matrix}} test fixture APK (Old Arch)' skip: true # Skipped pending PLAT-15027 @@ -169,7 +175,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" # current latest version (v7.40.1) of react-native-navigation's autolinking tool doesn't support RN 0.73+, # causing a build failure - see https://github.com/wix/react-native-navigation/issues/7821 @@ -215,7 +222,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" - label: ":bitbar: :android: react-native-navigation {{matrix}} Android 12 (Old Arch) end-to-end tests" skip: true # Skipped pending PLAT-15027 diff --git a/.buildkite/basic/react-native-android-pipeline.yml b/.buildkite/basic/react-native-android-pipeline.yml index 6072caf0e9..e576843085 100644 --- a/.buildkite/basic/react-native-android-pipeline.yml +++ b/.buildkite/basic/react-native-android-pipeline.yml @@ -5,37 +5,13 @@ steps: - group: "React Native (Android) Tests" steps: - - label: ':android: Build RN {{matrix}} test fixture APK (Old Arch)' - key: "build-react-native-android-fixture-old-arch" - timeout_in_minutes: 15 - agents: - queue: macos-node-18 - env: - JAVA_VERSION: "17" - NODE_VERSION: "18" - RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" - BUILD_ANDROID: "true" - artifact_paths: - - "test/react-native/features/fixtures/generated/old-arch/**/reactnative.apk" - commands: - - "bundle install" - - "node scripts/generate-react-native-fixture.js" - matrix: - - "0.80" - retry: - automatic: - - exit_status: "*" - limit: 1 - - - label: ':android: Build RN {{matrix}} test fixture APK (New Arch)' + - label: ':android: Build RN {{matrix}} test fixture APK' key: "build-react-native-android-fixture-new-arch" timeout_in_minutes: 15 agents: - queue: macos-node-18 + queue: macos-15 env: JAVA_VERSION: "17" - NODE_VERSION: "18" RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_ANDROID: "true" @@ -49,51 +25,12 @@ steps: - exit_status: "*" limit: 1 matrix: - - "0.80" + - "0.82" # # End-to-end tests # - - label: ":bitbar: :android: RN {{matrix}} Android 12 (Old Arch) end-to-end tests" - depends_on: "build-react-native-android-fixture-old-arch" - timeout_in_minutes: 30 - plugins: - artifacts#v1.9.0: - download: "test/react-native/features/fixtures/generated/old-arch/{{matrix}}/reactnative.apk" - upload: ./test/react-native/maze_output/**/* - docker-compose#v4.12.0: - pull: react-native-maze-runner - run: react-native-maze-runner - service-ports: true - command: - - --app=/app/features/fixtures/generated/old-arch/{{matrix}}/reactnative.apk - - --farm=bb - - --device=ANDROID_12 - - --appium-version=1.22 - - --fail-fast - - --no-tunnel - - --aws-public-ip - test-collector#v1.10.2: - files: "reports/TEST-*.xml" - format: "junit" - branch: "^main|next$$" - api-token-env-name: "REACT_NATIVE_BUILDKITE_ANALYTICS_TOKEN" - retry: - manual: - permit_on_passed: true - automatic: - - exit_status: 103 # Appium session failed - limit: 2 - env: - RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" - concurrency: 25 - concurrency_group: "bitbar" - concurrency_method: eager - matrix: - - "0.80" - - - label: ":bitbar: :android: RN {{matrix}} Android 12 (New Arch) end-to-end tests" + - label: ":bitbar: :android: RN {{matrix}} Android 12 end-to-end tests" depends_on: "build-react-native-android-fixture-new-arch" timeout_in_minutes: 30 plugins: @@ -130,5 +67,5 @@ steps: concurrency_group: "bitbar" concurrency_method: eager matrix: - - "0.80" + - "0.82" diff --git a/.buildkite/basic/react-native-cli-pipeline.yml b/.buildkite/basic/react-native-cli-pipeline.yml index 23dc951235..68a4ce8630 100644 --- a/.buildkite/basic/react-native-cli-pipeline.yml +++ b/.buildkite/basic/react-native-cli-pipeline.yml @@ -13,21 +13,21 @@ steps: queue: "macos-15-isolated" env: JAVA_VERSION: "17" - NODE_VERSION: "18" + NODE_VERSION: "22" RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" + RCT_NEW_ARCH_ENABLED: "1" BUILD_ANDROID: "true" INIT_RN_CLI: "true" artifact_paths: - - "test/react-native-cli/features/fixtures/generated/old-arch/**/reactnative.apk" + - "test/react-native-cli/features/fixtures/generated/new-arch/**/reactnative.apk" commands: - "cd test/react-native-cli" - "bundle install" - "bundle exec maze-runner features/build-app-tests/build-android-app.feature" matrix: + - "0.82" + - "0.81" - "0.80" - - "0.79" - - "0.78" retry: automatic: - exit_status: "*" @@ -40,23 +40,23 @@ steps: agents: queue: "macos-15-isolated" env: - NODE_VERSION: "18" + NODE_VERSION: "22" RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" + RCT_NEW_ARCH_ENABLED: "1" BUILD_IOS: "true" XCODE_VERSION: "16.2.0" INIT_RN_CLI: "true" EXPORT_ARCHIVE: "0" artifact_paths: - - "test/react-native-cli/features/fixtures/generated/old-arch/**/output/reactnative.ipa" + - "test/react-native-cli/features/fixtures/generated/new-arch/**/output/reactnative.ipa" commands: - "cd test/react-native-cli" - "bundle install" - "bundle exec maze-runner features/build-app-tests/build-ios-app.feature" matrix: + - "0.82" + - "0.81" - "0.80" - - "0.79" - - "0.78" retry: automatic: - exit_status: "*" @@ -70,13 +70,13 @@ steps: timeout_in_minutes: 30 plugins: artifacts#v1.9.0: - download: "test/react-native-cli/features/fixtures/generated/old-arch/{{matrix}}/reactnative.apk" + download: "test/react-native-cli/features/fixtures/generated/new-arch/{{matrix}}/reactnative.apk" upload: ./test/react-native-cli/maze_output/**/* docker-compose#v4.12.0: pull: react-native-cli-maze-runner run: react-native-cli-maze-runner command: - - --app=/app/features/fixtures/generated/old-arch/{{matrix}}/reactnative.apk + - --app=/app/features/fixtures/generated/new-arch/{{matrix}}/reactnative.apk - --farm=bs - --device=ANDROID_12 - features/run-app-tests @@ -92,9 +92,9 @@ steps: concurrency_group: "browserstack-app" concurrency_method: eager matrix: + - "0.82" + - "0.81" - "0.80" - - "0.79" - - "0.78" retry: automatic: - exit_status: 103 # Appium session failed @@ -105,13 +105,13 @@ steps: timeout_in_minutes: 30 plugins: artifacts#v1.9.0: - download: "test/react-native-cli/features/fixtures/generated/old-arch/{{matrix}}/output/reactnative.ipa" + download: "test/react-native-cli/features/fixtures/generated/new-arch/{{matrix}}/output/reactnative.ipa" upload: ./test/react-native-cli/maze_output/**/* docker-compose#v4.12.0: pull: react-native-cli-maze-runner run: react-native-cli-maze-runner command: - - --app=/app/features/fixtures/generated/old-arch/{{matrix}}/output/reactnative.ipa + - --app=/app/features/fixtures/generated/new-arch/{{matrix}}/output/reactnative.ipa - --farm=bs - --device=IOS_16 - features/run-app-tests @@ -127,9 +127,9 @@ steps: concurrency_group: "browserstack-app" concurrency_method: eager matrix: + - "0.82" + - "0.81" - "0.80" - - "0.79" - - "0.78" retry: automatic: - exit_status: 103 # Appium session failed diff --git a/.buildkite/basic/react-native-ios-full-pipeline.yml b/.buildkite/basic/react-native-ios-full-pipeline.yml index ddb95f5c5a..6dcd2f855a 100644 --- a/.buildkite/basic/react-native-ios-full-pipeline.yml +++ b/.buildkite/basic/react-native-ios-full-pipeline.yml @@ -9,14 +9,14 @@ steps: # # Test fixtures # - - label: ':mac: Build RN {{matrix}} test fixture ipa (Old Arch)' + - label: ':mac: Build RN {{matrix.reactnative}} test fixture ipa (Old Arch)' key: "build-react-native-ios-fixture-old-arch-full" timeout_in_minutes: 30 agents: queue: "macos-15" env: - NODE_VERSION: "18" - RN_VERSION: "{{matrix}}" + NODE_VERSION: "{{matrix.node}}" + RN_VERSION: "{{matrix.reactnative}}" RCT_NEW_ARCH_ENABLED: "0" BUILD_IOS: "true" XCODE_VERSION: "16.2.0" @@ -26,13 +26,23 @@ steps: - "bundle install" - "node scripts/generate-react-native-fixture.js" matrix: - - "0.68" - - "0.69" - - "0.72" - - "0.74" - - "0.76" - - "0.78" - - "0.79" + setup: + reactnative: + - "0.72" + - "0.74" + - "0.76" + - "0.78" + - "0.80" + - "0.81" + node: + - "22" + adjustments: + - with: + reactnative: "0.68" + node: "18" + - with: + reactnative: "0.69" + node: "18" retry: automatic: - exit_status: "*" @@ -44,7 +54,7 @@ steps: agents: queue: "macos-15" env: - NODE_VERSION: "18" + NODE_VERSION: "22" RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_IOS: "true" @@ -59,7 +69,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" retry: automatic: - exit_status: "*" @@ -161,7 +172,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" - label: ":bitbar: :mac: RN {{matrix}} iOS (New Arch) end-to-end tests" depends_on: "build-react-native-ios-fixture-new-arch-full" @@ -203,7 +215,8 @@ steps: - "0.74" - "0.76" - "0.78" - - "0.79" + - "0.80" + - "0.81" # current latest version (v7.40.1) of react-native-navigation's autolinking tool doesn't currently support RN 0.73+, # causing a build failure - see https://github.com/wix/react-native-navigation/issues/7821 diff --git a/.buildkite/basic/react-native-ios-pipeline.yml b/.buildkite/basic/react-native-ios-pipeline.yml index d44d3f709c..b070b5e4cd 100644 --- a/.buildkite/basic/react-native-ios-pipeline.yml +++ b/.buildkite/basic/react-native-ios-pipeline.yml @@ -9,36 +9,12 @@ steps: # # Test fixtures # - - label: ':mac: Build RN {{matrix}} test fixture ipa (Old Arch)' - key: "build-react-native-ios-fixture-old-arch" - timeout_in_minutes: 20 - agents: - queue: "macos-15" - env: - NODE_VERSION: "18" - RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" - BUILD_IOS: "true" - XCODE_VERSION: "16.2.0" - artifact_paths: - - "test/react-native/features/fixtures/generated/old-arch/**/output/reactnative.ipa" - commands: - - "bundle install" - - "node scripts/generate-react-native-fixture.js" - matrix: - - "0.80" - retry: - automatic: - - exit_status: "*" - limit: 1 - - - label: ':mac: Build RN {{matrix}} test fixture ipa (New Arch)' + - label: ':mac: Build RN {{matrix}} test fixture ipa' key: "build-react-native-ios-fixture-new-arch" timeout_in_minutes: 20 agents: queue: "macos-15" env: - NODE_VERSION: "18" RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_IOS: "true" @@ -49,7 +25,7 @@ steps: - "bundle install" - "node scripts/generate-react-native-fixture.js" matrix: - - "0.80" + - "0.82" retry: automatic: - exit_status: "*" @@ -57,45 +33,7 @@ steps: # # End-to-end tests # - - label: ":bitbar: :mac: RN {{matrix}} iOS (Old Arch) end-to-end tests" - depends_on: "build-react-native-ios-fixture-old-arch" - timeout_in_minutes: 30 - plugins: - artifacts#v1.9.0: - download: "test/react-native/features/fixtures/generated/old-arch/{{matrix}}/output/reactnative.ipa" - upload: ./test/react-native/maze_output/**/* - docker-compose#v4.12.0: - pull: react-native-maze-runner - run: react-native-maze-runner - service-ports: true - command: - - --app=/app/features/fixtures/generated/old-arch/{{matrix}}/output/reactnative.ipa - - --farm=bb - - --device=IOS_15 - - --fail-fast - - --no-tunnel - - --aws-public-ip - test-collector#v1.10.2: - files: "reports/TEST-*.xml" - format: "junit" - branch: "^main|next$$" - api-token-env-name: "REACT_NATIVE_BUILDKITE_ANALYTICS_TOKEN" - retry: - manual: - permit_on_passed: true - automatic: - - exit_status: 103 # Appium session failed - limit: 2 - env: - RN_VERSION: "{{matrix}}" - RCT_NEW_ARCH_ENABLED: "0" - concurrency: 25 - concurrency_group: "bitbar" - concurrency_method: eager - matrix: - - "0.80" - - - label: ":bitbar: :mac: RN {{matrix}} iOS (New Arch) end-to-end tests" + - label: ":bitbar: :mac: RN {{matrix}} iOS end-to-end tests" depends_on: "build-react-native-ios-fixture-new-arch" timeout_in_minutes: 30 plugins: @@ -131,5 +69,5 @@ steps: concurrency_group: "bitbar" concurrency_method: eager matrix: - - "0.80" + - "0.82" diff --git a/scripts/generate-react-native-fixture.js b/scripts/generate-react-native-fixture.js index de9feaa11a..8589c25cae 100644 --- a/scripts/generate-react-native-fixture.js +++ b/scripts/generate-react-native-fixture.js @@ -57,10 +57,10 @@ let reactNativeSafeAreaContextVersion = '4.14.0' // RN 0.77 requires react-native-screens 4.6.0, which in turn requires react navigation v7 if (parseFloat(reactNativeVersion) >= 0.77) { - reactNavigationVersion = '7.1.14' - reactNavigationNativeStackVersion = '7.3.21' - reactNativeScreensVersion = '4.11.1' - reactNativeSafeAreaContextVersion = '5.5.1' + reactNavigationVersion = '7.1.18' + reactNavigationNativeStackVersion = '7.3.28' + reactNativeScreensVersion = '4.17.1' + reactNativeSafeAreaContextVersion = '5.6.1' } else if (parseFloat(reactNativeVersion) <= 0.69) { reactNativeScreensVersion = '3.14.0' reactNativeSafeAreaContextVersion = '4.3.4' diff --git a/scripts/react-native/android-utils.js b/scripts/react-native/android-utils.js index f1ef8a0d6e..3b8ebe857e 100644 --- a/scripts/react-native/android-utils.js +++ b/scripts/react-native/android-utils.js @@ -6,7 +6,16 @@ module.exports = { // set android:usesCleartextTraffic="true" in AndroidManifest.xml const androidManifestPath = `${fixtureDir}/android/app/src/main/AndroidManifest.xml` let androidManifestContents = fs.readFileSync(androidManifestPath, 'utf8') - androidManifestContents = androidManifestContents.replace(' Date: Mon, 20 Oct 2025 03:23:26 +0000 Subject: [PATCH 07/43] build(deps): bump actions/setup-node from 5.0.0 to 6.0.0 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/a0853c24544627f65ddf259abe73b1d18a591444...2028fbc5c25fe9cf00d9f06a71cc4710d4507903) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/pr-diff.yml | 2 +- .github/workflows/test-electron.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index 1e24dcfc37..0770c9f78a 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -29,7 +29,7 @@ jobs: ruby-version: '3.1' - name: Install Node - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 with: node-version: 18 diff --git a/.github/workflows/pr-diff.yml b/.github/workflows/pr-diff.yml index 58504d95ad..fbce5b37be 100644 --- a/.github/workflows/pr-diff.yml +++ b/.github/workflows/pr-diff.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup node - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: 18.x diff --git a/.github/workflows/test-electron.yml b/.github/workflows/test-electron.yml index 7ebee1bc47..744c26a733 100644 --- a/.github/workflows/test-electron.yml +++ b/.github/workflows/test-electron.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: ${{ matrix.node-version }} - name: (Act) install build tools and dependencies From a67908c8da5b3502e0ecaac71dfb22ce2c211c4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 03:23:33 +0000 Subject: [PATCH 08/43] build(deps): bump github/codeql-action from 3.30.5 to 4.30.9 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.5 to 4.30.9. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/3599b3baa15b485a2e49ef411a7a4bb2452e7f93...16140ae1a102900babc80a33c44059580f687047) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.30.9 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8d0ce6b740..04da8e2957 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7d50bbf326..84f3bff159 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 with: sarif_file: results.sarif From bc8eda8d8c0a8c32de2ae40db4f8f5f11b79a8ee Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:08:24 +0200 Subject: [PATCH 09/43] Add error boundary e2e tests in React Native (#2590) * add error boundary e2e test * fix lint errors * fix lint * add react import * add timer for error * update scenario * add jsConfig * add set timeout * revert not needed changes * add empty onError callback to prevent app crashing * add new step in scenario * add metadata to the event * fix the event metadata --------- Co-authored-by: Ben Wilson --- .../ReactNativeErrorBoundaryScenario.js | 45 +++++++++++++++++++ .../scenario-launcher/src/scenarios/index.js | 3 ++ .../react-native-error-boundary.feature | 12 +++++ 3 files changed, 60 insertions(+) create mode 100644 test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js create mode 100644 test/react-native/features/react-native-error-boundary.feature diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js b/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js new file mode 100644 index 0000000000..57181eb195 --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js @@ -0,0 +1,45 @@ +import Bugsnag from '@bugsnag/react-native' +import * as React from 'react' +import { Text, View } from 'react-native' +import Scenario from './Scenario' + +const onError = (event) => { + // callback will only run for errors caught by boundary + event.addMetadata('errorBoundary', 'caughtByErrorBoundary', true) + event.addMetadata('errorBoundary', 'handlerType', 'react-native-error-boundary') +} + +export class ReactNativeErrorBoundaryScenario extends Scenario { + view () { + const ErrorBoundary = Bugsnag.getPlugin('react').createErrorBoundary(React) + return ( + + + + ) + } + + run () { + // Error is thrown during render + } +} + +function ErrorView () { + return ( + + There was an error + + ) +} + +function MainView () { + return ( + + Hello world {text()} + + ) +} + +const text = function () { + throw new Error('borked') +} diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js b/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js index 1c0c937efa..9c08ba1c88 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js +++ b/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js @@ -78,6 +78,9 @@ export { NativeFeatureFlagsScenario } from './NativeFeatureFlagsScenario' export { ReactNavigationBreadcrumbsEnabledScenario } from './ReactNavigationBreadcrumbsEnabledScenario' export { ReactNavigationBreadcrumbsDisabledScenario } from './ReactNavigationBreadcrumbsDisabledScenario' +// react-native-error-boundary.feature +export { ReactNativeErrorBoundaryScenario } from './ReactNativeErrorBoundaryScenario' + // react-native-navigation.feature export { ReactNativeNavigationBreadcrumbsEnabledScenario } from './ReactNativeNavigationBreadcrumbsEnabledScenario' export { ReactNativeNavigationBreadcrumbsDisabledScenario } from './ReactNativeNavigationBreadcrumbsDisabledScenario' diff --git a/test/react-native/features/react-native-error-boundary.feature b/test/react-native/features/react-native-error-boundary.feature new file mode 100644 index 0000000000..d04cbf34b0 --- /dev/null +++ b/test/react-native/features/react-native-error-boundary.feature @@ -0,0 +1,12 @@ +Feature: ReactNative ErrorBoundary support + +Scenario: ErrorBoundary component reports errors + When I run "ReactNativeErrorBoundaryScenario" + And I relaunch the app after a crash + And I configure Bugsnag for "ReactNativeErrorBoundaryScenario" + Then I wait to receive an error + And the exception "errorClass" equals "Error" + And the exception "message" equals "borked" + And the event "metaData.react.componentStack" is not null + And the event "metaData.errorBoundary.caughtByErrorBoundary" is true + And the event "metaData.errorBoundary.handlerType" equals "react-native-error-boundary" \ No newline at end of file From 9f80ad5b9cab348dae7af46630864a9cdfe86bf3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 03:25:01 +0000 Subject: [PATCH 10/43] build(deps): bump ruby/setup-ruby from 1.265.0 to 1.266.0 Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.265.0 to 1.266.0. - [Release notes](https://github.com/ruby/setup-ruby/releases) - [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb) - [Commits](https://github.com/ruby/setup-ruby/compare/ab177d40ee5483edb974554986f56b33477e21d0...4ff6f3611a42bc75eee1e5138240eb1613f48c8f) --- updated-dependencies: - dependency-name: ruby/setup-ruby dependency-version: 1.266.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/update-dependencies.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index a107fac7ce..95632664c7 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 - name: Install Ruby - uses: ruby/setup-ruby@ab177d40ee5483edb974554986f56b33477e21d0 + uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f with: ruby-version: '3.1' diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index 0b26069e77..8f5b53019a 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -40,7 +40,7 @@ jobs: - run: git submodule update --init --recursive - name: Install ruby - uses: ruby/setup-ruby@ab177d40ee5483edb974554986f56b33477e21d0 # v1.265.0 + uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0 with: ruby-version: 2.7 From 368509e6dd36a226ad1a8f9e54d9532fb3f451ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 03:25:12 +0000 Subject: [PATCH 11/43] build(deps): bump github/codeql-action from 4.30.9 to 4.31.0 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.30.9 to 4.31.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/16140ae1a102900babc80a33c44059580f687047...4e94bd11f71e507f7f87df81788dff88d1dacbfb) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 04da8e2957..aff1df527a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 46f5b9dac1..f86c88c731 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 with: sarif_file: results.sarif From 00aea053fa99d6f64de40b6566cfcefe70e61900 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 03:25:18 +0000 Subject: [PATCH 12/43] build(deps): bump actions/upload-artifact from 4.6.2 to 5.0.0 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 5.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...330a01c490aca151604b8cf639adc76d48f6c5d4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecard.yml | 2 +- .github/workflows/test-electron.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 46f5b9dac1..ea57d1df45 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -59,7 +59,7 @@ jobs: # 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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/test-electron.yml b/.github/workflows/test-electron.yml index 744c26a733..199e2d0ec3 100644 --- a/.github/workflows/test-electron.yml +++ b/.github/workflows/test-electron.yml @@ -66,7 +66,7 @@ jobs: START_LOCAL_NPM: 1 VERBOSE: 1 ELECTRON_VERSION: ${{ matrix.electron }} - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 if: failure() with: name: cucumber-failures From 04622d912498cdb3e6161e829d089c440a129b0b Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Mon, 27 Oct 2025 09:19:37 +0000 Subject: [PATCH 13/43] Apply suggestion from @gingerbenw --- .github/workflows/aws-lambda.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index 95632664c7..d7794de4f0 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 - name: Install Ruby - uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f + uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0 with: ruby-version: '3.1' From 167abda480c2eb9aac49fcf36d662343c1d37317 Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Thu, 30 Oct 2025 14:39:07 +0000 Subject: [PATCH 14/43] Amend secondary default endpoints (#2584) * refactor: :truck: Change insighthub to bugsnag for secondary endpoints --- CHANGELOG.md | 1 + packages/core/client.js | 12 ++++++------ packages/core/test/endpoints.test.ts | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 775cf7c96b..239d6df975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Changed - Update bugsnag-cocoa to [v6.34.0](https//github.com/bugsnag/bugsnag-cocoa/releases/tag/v6.34.0) [#2571](https://github.com/bugsnag/bugsnag-js/pull/2571) +- Amend secondary default notify and sessions endpoints to `bugsnag.smartbear.com` [#2584](https://github.com/bugsnag/bugsnag-js/pull/2584) ## [8.6.0] - 2025-09-25 diff --git a/packages/core/client.js b/packages/core/client.js index 04ec54eabc..694a41540e 100644 --- a/packages/core/client.js +++ b/packages/core/client.js @@ -13,9 +13,9 @@ const metadataDelegate = require('./lib/metadata-delegate') const runSyncCallbacks = require('./lib/sync-callback-runner') const BREADCRUMB_TYPES = require('./lib/breadcrumb-types') const { add, clear, merge } = require('./lib/feature-flag-delegate') -const HUB_PREFIX = '00000' -const HUB_NOTIFY = 'https://notify.insighthub.smartbear.com' -const HUB_SESSION = 'https://sessions.insighthub.smartbear.com' +const SECONDARY_ENDPOINT_API_KEY_PREFIX = '00000' +const SECONDARY_NOTIFY_ENDPOINT = 'https://notify.bugsnag.smartbear.com' +const SECONDARY_SESSIONS_ENDPOINT = 'https://sessions.bugsnag.smartbear.com' const noop = () => { } @@ -169,10 +169,10 @@ class Client { // warn about an apikey that is not of the expected format if (!/^[0-9a-f]{32}$/i.test(config.apiKey)) errors.apiKey = 'should be a string of 32 hexadecimal characters' - if (opts.endpoints === undefined && config.apiKey.indexOf(HUB_PREFIX) === 0) { + if (opts.endpoints === undefined && config.apiKey.indexOf(SECONDARY_ENDPOINT_API_KEY_PREFIX) === 0) { config.endpoints = { - notify: HUB_NOTIFY, - sessions: HUB_SESSION + notify: SECONDARY_NOTIFY_ENDPOINT, + sessions: SECONDARY_SESSIONS_ENDPOINT } } } diff --git a/packages/core/test/endpoints.test.ts b/packages/core/test/endpoints.test.ts index ee2ec38c1c..a5b904203e 100644 --- a/packages/core/test/endpoints.test.ts +++ b/packages/core/test/endpoints.test.ts @@ -5,25 +5,25 @@ const Client = require('../client') /* -------------------------------------------------------------------------- * Constants – keep tests self-contained * ------------------------------------------------------------------------ */ -const HUB_PREFIX = '00000' -const HUB_NOTIFY = 'https://notify.insighthub.smartbear.com' -const HUB_SESSION = 'https://sessions.insighthub.smartbear.com' +const SECONDARY_ENDPOINT_API_KEY_PREFIX = '00000' +const SECONDARY_NOTIFY = 'https://notify.bugsnag.smartbear.com' +const SECONDARY_SESSION = 'https://sessions.bugsnag.smartbear.com' const BUGSNAG_NOTIFY = 'https://notify.bugsnag.com' const BUGSNAG_SESSION = 'https://sessions.bugsnag.com' -const HUB_KEY = `${HUB_PREFIX}abcdef0123456789abcdef012345` +const PREFIXED_KEY = `${SECONDARY_ENDPOINT_API_KEY_PREFIX}abcdef0123456789abcdef012345` const NORMAL_KEY = 'abcdef0123456789abcdef0123456789' describe('endpoint selection', () => { - describe('Client → automatic InsightHub switch', () => { - it('swaps to InsightHub urls when apiKey starts with 00000', () => { - const client = new Client({ apiKey: HUB_KEY }) + describe('Client → automatic BugSnag switch', () => { + it('swaps to secondary urls when apiKey starts with 00000', () => { + const client = new Client({ apiKey: PREFIXED_KEY }) expect(client._config.endpoints).toEqual({ - notify: HUB_NOTIFY, - sessions: HUB_SESSION + notify: SECONDARY_NOTIFY, + sessions: SECONDARY_SESSION }) }) - it('keeps Bugsnag urls otherwise', () => { + it('keeps default urls otherwise', () => { const client = new Client({ apiKey: NORMAL_KEY }) expect(client._config.endpoints).toEqual({ notify: BUGSNAG_NOTIFY, @@ -33,7 +33,7 @@ describe('endpoint selection', () => { it('does **not** switch if custom endpoints are supplied', () => { const custom = { notify: 'https://n.example.com', sessions: 'https://s.example.com' } - const client = new Client({ apiKey: HUB_KEY, endpoints: custom }) + const client = new Client({ apiKey: PREFIXED_KEY, endpoints: custom }) expect(client._config.endpoints).toBe(custom) }) }) From 7c8843e51b01443a44d91caddff80e006ccceaff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 03:25:32 +0000 Subject: [PATCH 15/43] build(deps): bump github/codeql-action from 4.31.0 to 4.31.2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.0 to 4.31.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/4e94bd11f71e507f7f87df81788dff88d1dacbfb...0499de31b99561a6d14a36a5f662c2a54f91beee) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index aff1df527a..ca73558440 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/autobuild@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 4f8eaa4e86..f3decf5ef0 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: sarif_file: results.sarif From 124b1886e0650fe2ca2f47a115fc2236ae9a643b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 03:25:46 +0000 Subject: [PATCH 16/43] build(deps): bump danger/danger-js from 13.0.4 to 13.0.5 Bumps [danger/danger-js](https://github.com/danger/danger-js) from 13.0.4 to 13.0.5. - [Release notes](https://github.com/danger/danger-js/releases) - [Changelog](https://github.com/danger/danger-js/blob/main/CHANGELOG.md) - [Commits](https://github.com/danger/danger-js/compare/bdccecb77e0144055fbaea9224f10cf8b1229b68...67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9) --- updated-dependencies: - dependency-name: danger/danger-js dependency-version: 13.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/pr-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-diff.yml b/.github/workflows/pr-diff.yml index fbce5b37be..6f1b0b607d 100644 --- a/.github/workflows/pr-diff.yml +++ b/.github/workflows/pr-diff.yml @@ -43,6 +43,6 @@ jobs: cat packages/browser/dist/bugsnag.min.js | gzip | wc -c > .diff/size-after-gzipped - name: Run danger - uses: danger/danger-js@bdccecb77e0144055fbaea9224f10cf8b1229b68 # 13.0.4 + uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 75db9cd128a6a9e321e35f562fe52de9452b876b Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Mon, 10 Nov 2025 10:12:13 +0000 Subject: [PATCH 17/43] chore: pin yoctocolors-cjs to 2.1.2 --- package-lock.json | 2 ++ packages/plugin-angular/package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/package-lock.json b/package-lock.json index b7ae8e6d9b..cfc29f7cc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46865,6 +46865,7 @@ "ng-packagr": "^19.1.0", "rxjs": "~7.8.0", "typescript": "~5.6.2", + "yoctocolors-cjs": "2.1.2", "zone.js": "~0.15.0" }, "peerDependencies": { @@ -55772,6 +55773,7 @@ "rxjs": "~7.8.0", "tslib": "^2.3.0", "typescript": "~5.6.2", + "yoctocolors-cjs": "2.1.2", "zone.js": "~0.15.0" }, "dependencies": { diff --git a/packages/plugin-angular/package.json b/packages/plugin-angular/package.json index 018d326a5e..c9ca7b2356 100644 --- a/packages/plugin-angular/package.json +++ b/packages/plugin-angular/package.json @@ -34,6 +34,7 @@ "ng-packagr": "^19.1.0", "rxjs": "~7.8.0", "typescript": "~5.6.2", + "yoctocolors-cjs": "2.1.2", "zone.js": "~0.15.0" }, "dependencies": { From 39e49101ffb11b655034919182ba57fd8c613793 Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Mon, 10 Nov 2025 14:30:33 +0000 Subject: [PATCH 18/43] test: remove devices no longer available on browserstack --- .buildkite/basic/browser-pipeline.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.buildkite/basic/browser-pipeline.yml b/.buildkite/basic/browser-pipeline.yml index b9eacee12b..a3440064b1 100644 --- a/.buildkite/basic/browser-pipeline.yml +++ b/.buildkite/basic/browser-pipeline.yml @@ -50,7 +50,6 @@ steps: # - label: ":browserstack: {{matrix}} non-https tests" matrix: - - ios_11 - safari_16 depends_on: "browser-maze-runner-bs" timeout_in_minutes: 30 From 32a800b625db21684a320354a369f1493557f15f Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Mon, 10 Nov 2025 16:44:46 +0000 Subject: [PATCH 19/43] chore: update axios to 1.13.2 --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfc29f7cc6..f4dcf470d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14675,14 +14675,14 @@ "dev": true }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -68871,13 +68871,13 @@ "dev": true }, "axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dev": true, "requires": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, From e96b6fc50faab83827a83dd951e1f9fc2a6e0bda Mon Sep 17 00:00:00 2001 From: Bumpsnag bot <> Date: Mon, 10 Nov 2025 12:14:20 +0000 Subject: [PATCH 20/43] Update bugsnag-cocoa to 6.34.1 [full ci] --- CHANGELOG.md | 6 ++++++ packages/react-native/ios/vendor/bugsnag-cocoa | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 239d6df975..0714352b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Dependencies + +Update bugsnag-cocoa to [6.34.1](https//github.com/bugsnag/bugsnag-cocoa/releases/tag/6.34.1) [#2606](https://github.com/bugsnag/bugsnag-js/pull/2606) + ## [8.7.0] - 2025-10-13 ### Added diff --git a/packages/react-native/ios/vendor/bugsnag-cocoa b/packages/react-native/ios/vendor/bugsnag-cocoa index 1f991e92a6..f4348c29cc 160000 --- a/packages/react-native/ios/vendor/bugsnag-cocoa +++ b/packages/react-native/ios/vendor/bugsnag-cocoa @@ -1 +1 @@ -Subproject commit 1f991e92a6e3993c2763d071781d895ca4075a90 +Subproject commit f4348c29cc881ce80e4e22a46f29d7f5a18e924b From efcbc2956a97dc2125f7fa16596439db57cbc8f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 03:17:37 +0000 Subject: [PATCH 21/43] build(deps): bump github/codeql-action from 4.31.2 to 4.31.3 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.2 to 4.31.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/0499de31b99561a6d14a36a5f662c2a54f91beee...014f16e7ab1402f30e7c3329d33797e7948572db) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ca73558440..665c15ab3d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/autobuild@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f3decf5ef0..ca0ada24d9 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 with: sarif_file: results.sarif From 84e3700f395e59e538daa8552311dc4634a66a71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 03:41:09 +0000 Subject: [PATCH 22/43] build(deps): bump github/codeql-action from 4.31.3 to 4.31.5 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.3 to 4.31.5. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/014f16e7ab1402f30e7c3329d33797e7948572db...fdbfb4d2750291e159f0156def62b853c2798ca2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 665c15ab3d..4adf691ead 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 + uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 + uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 + uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index ca0ada24d9..8d9bbeaaac 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3 + uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: sarif_file: results.sarif From 16bfcff09e5c8e9264ac38a6e94b47fab51a5160 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Mon, 1 Dec 2025 17:39:31 +0000 Subject: [PATCH 23/43] Rename auto_detect_failures fixture files --- test/browser/features/auto_detect_errors.feature | 6 +++--- .../script/{a.html => autodetect_false.html} | 0 .../script/{b.html => unhandled_exceptions_false.html} | 0 .../script/{c.html => unhandled_rejections_false.html} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename test/browser/features/fixtures/auto_detect_errors/script/{a.html => autodetect_false.html} (100%) rename test/browser/features/fixtures/auto_detect_errors/script/{b.html => unhandled_exceptions_false.html} (100%) rename test/browser/features/fixtures/auto_detect_errors/script/{c.html => unhandled_rejections_false.html} (100%) diff --git a/test/browser/features/auto_detect_errors.feature b/test/browser/features/auto_detect_errors.feature index b220a42d7d..8c72d7132b 100644 --- a/test/browser/features/auto_detect_errors.feature +++ b/test/browser/features/auto_detect_errors.feature @@ -2,7 +2,7 @@ Feature: Switching off automatic reporting Scenario: setting autoDetectErrors option to false - When I navigate to the test URL "/auto_detect_errors/script/a.html" + When I navigate to the test URL "/auto_detect_errors/script/autodetect_false.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "unhandled" is false @@ -11,7 +11,7 @@ Scenario: setting autoDetectErrors option to false And the exception "type" equals "browserjs" Scenario: setting enabledErrorTypes.unhandledExceptions option to false - When I navigate to the test URL "/auto_detect_errors/script/b.html" + When I navigate to the test URL "/auto_detect_errors/script/unhandled_exceptions_false.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "unhandled" is false @@ -20,7 +20,7 @@ Scenario: setting enabledErrorTypes.unhandledExceptions option to false And the exception "type" equals "browserjs" Scenario: setting enabledErrorTypes.unhandledRejections option to false - When I navigate to the test URL "/auto_detect_errors/script/c.html" + When I navigate to the test URL "/auto_detect_errors/script/unhandled_rejections_false.html" And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API diff --git a/test/browser/features/fixtures/auto_detect_errors/script/a.html b/test/browser/features/fixtures/auto_detect_errors/script/autodetect_false.html similarity index 100% rename from test/browser/features/fixtures/auto_detect_errors/script/a.html rename to test/browser/features/fixtures/auto_detect_errors/script/autodetect_false.html diff --git a/test/browser/features/fixtures/auto_detect_errors/script/b.html b/test/browser/features/fixtures/auto_detect_errors/script/unhandled_exceptions_false.html similarity index 100% rename from test/browser/features/fixtures/auto_detect_errors/script/b.html rename to test/browser/features/fixtures/auto_detect_errors/script/unhandled_exceptions_false.html diff --git a/test/browser/features/fixtures/auto_detect_errors/script/c.html b/test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html similarity index 100% rename from test/browser/features/fixtures/auto_detect_errors/script/c.html rename to test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html From 5f6938b33a1fdb79790a6a1c0e861cc88ff3ec8b Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Tue, 2 Dec 2025 15:49:26 +0000 Subject: [PATCH 24/43] Rename fixtures files (batch 2) (#2621) * Rename csp fixture * Rename delivery fixture * Rename device fixture files --------- Co-authored-by: Steve Kirkland --- test/browser/features/csp.feature | 2 +- test/browser/features/delivery.feature | 3 +-- test/browser/features/device.feature | 20 ++++++++++--------- .../csp/script/{a.html => no_crash.html} | 0 .../script/{a.html => oversized.html} | 0 .../device/script/{b.html => disabled.html} | 0 .../device/script/{a.html => enabled.html} | 0 .../device/script/{c.html => store_id.html} | 0 8 files changed, 13 insertions(+), 12 deletions(-) rename test/browser/features/fixtures/csp/script/{a.html => no_crash.html} (100%) rename test/browser/features/fixtures/delivery/script/{a.html => oversized.html} (100%) rename test/browser/features/fixtures/device/script/{b.html => disabled.html} (100%) rename test/browser/features/fixtures/device/script/{a.html => enabled.html} (100%) rename test/browser/features/fixtures/device/script/{c.html => store_id.html} (100%) diff --git a/test/browser/features/csp.feature b/test/browser/features/csp.feature index 31dc3c9250..5acd71b610 100644 --- a/test/browser/features/csp.feature +++ b/test/browser/features/csp.feature @@ -2,5 +2,5 @@ Feature: Compatibility with a Content Security Policy Scenario: notifer does not crash for CSP violations - When I navigate to the test URL "/csp/script/a.html" + When I navigate to the test URL "/csp/script/no_crash.html" Then I let the test page run for up to 10 seconds diff --git a/test/browser/features/delivery.feature b/test/browser/features/delivery.feature index a452d2fafa..26e53729d6 100644 --- a/test/browser/features/delivery.feature +++ b/test/browser/features/delivery.feature @@ -3,8 +3,7 @@ Feature: Delivery of errors @skip_ie_10 Scenario: Delivery is attempted oversized payloads When I set the HTTP status code for the next "POST" request to 400 - And I navigate to the test URL "/delivery/script/a.html" - And I wait for 5 seconds + And I navigate to the test URL "/delivery/script/oversized.html" Then I wait to receive an error # Check that Bugsnag is discarding the event diff --git a/test/browser/features/device.feature b/test/browser/features/device.feature index b95e5f38e1..7d1e9e1336 100644 --- a/test/browser/features/device.feature +++ b/test/browser/features/device.feature @@ -2,7 +2,7 @@ Feature: Browser device data Scenario: Device data is included by default - When I navigate to the test URL "/device/script/a.html" + When I navigate to the test URL "/device/script/enabled.html" And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event "device.time" is not null @@ -12,7 +12,7 @@ Scenario: Device data is included by default And the event device ID is valid Scenario: Device ID is not collected when the config option is disabled - When I navigate to the test URL "/device/script/b.html" + When I navigate to the test URL "/device/script/disabled.html" And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event "device.time" is not null @@ -23,17 +23,19 @@ Scenario: Device ID is not collected when the config option is disabled @skip_if_local_storage_is_unavailable Scenario: Device ID is read from local storage - When I navigate to the test URL "/device/script/c.html" + When I navigate to the test URL "/device/script/store_id.html" And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event device ID is "cabcdefghijklmnopqrstuvwx" - When I navigate to the test URL "/device/script/a.html" - # This is 2 requests because the first request still counts (i.e. it's only 1 _new_ request) - And I wait to receive 2 errors + And I discard the oldest error + + When I navigate to the test URL "/device/script/enabled.html" + And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event device ID is "cabcdefghijklmnopqrstuvwx" - When I navigate to the test URL "/device/script/a.html" - # This is 3 requests because the first 2 requests still count - And I wait to receive 3 errors + And I discard the oldest error + + When I navigate to the test URL "/device/script/enabled.html" + And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event device ID is "cabcdefghijklmnopqrstuvwx" diff --git a/test/browser/features/fixtures/csp/script/a.html b/test/browser/features/fixtures/csp/script/no_crash.html similarity index 100% rename from test/browser/features/fixtures/csp/script/a.html rename to test/browser/features/fixtures/csp/script/no_crash.html diff --git a/test/browser/features/fixtures/delivery/script/a.html b/test/browser/features/fixtures/delivery/script/oversized.html similarity index 100% rename from test/browser/features/fixtures/delivery/script/a.html rename to test/browser/features/fixtures/delivery/script/oversized.html diff --git a/test/browser/features/fixtures/device/script/b.html b/test/browser/features/fixtures/device/script/disabled.html similarity index 100% rename from test/browser/features/fixtures/device/script/b.html rename to test/browser/features/fixtures/device/script/disabled.html diff --git a/test/browser/features/fixtures/device/script/a.html b/test/browser/features/fixtures/device/script/enabled.html similarity index 100% rename from test/browser/features/fixtures/device/script/a.html rename to test/browser/features/fixtures/device/script/enabled.html diff --git a/test/browser/features/fixtures/device/script/c.html b/test/browser/features/fixtures/device/script/store_id.html similarity index 100% rename from test/browser/features/fixtures/device/script/c.html rename to test/browser/features/fixtures/device/script/store_id.html From f7ec3a0f991d664186b58ad3963c263f743c7abe Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Tue, 2 Dec 2025 15:54:15 +0000 Subject: [PATCH 25/43] Rename fixtures files (batch 3) (#2622) * Rename csp fixture * Rename delivery fixture * Rename device fixture files * Rename "a" fixture files * Rename "b" fixture files * Rename "c" fixture files * Rename remaining fixture files * Corrections * Corrections --------- Co-authored-by: Steve Kirkland --- .../browserify/{a.html => notify_new_error.html} | 2 +- .../fixtures/handled/browserify/package.json | 2 +- .../c.html => browserify/promise_catch.html} | 2 +- .../browserify/src/{a.js => notify_new_error.js} | 0 .../browserify/src/{c.js => promise_catch.js} | 0 .../browserify/src/{b.js => try_catch_notify.js} | 0 .../browserify/{b.html => try_catch_notify.html} | 2 +- .../rollup/{b.html => notify_new_error.html} | 2 +- .../fixtures/handled/rollup/package.json | 2 +- .../c.html => rollup/promise_catch.html} | 2 +- .../rollup/src/{a.js => notify_new_error.js} | 0 .../rollup/src/{c.js => promise_catch.js} | 0 .../rollup/src/{b.js => try_catch_notify.js} | 0 .../rollup/{a.html => try_catch_notify.html} | 2 +- .../script/{h.html => callback_override.html} | 0 .../script/{f.html => client_notify_object.html} | 0 .../script/{g.html => client_notify_string.html} | 0 .../script/{a.html => notify_new_error.html} | 0 .../script/{d.html => notify_object.html} | 0 .../script/{e.html => notify_string.html} | 0 .../script/{c.html => promise_catch.html} | 0 .../script/{b.html => try_catch_notify.html} | 0 .../typescript/{a.html => notify_new_error.html} | 2 +- .../fixtures/handled/typescript/package.json | 2 +- .../typescript/{c.html => promise_catch.html} | 2 +- .../typescript/src/{a.ts => notify_new_error.ts} | 0 .../typescript/src/{c.ts => promise_catch.ts} | 0 .../typescript/src/{b.ts => try_catch_notify.ts} | 0 .../typescript/{b.html => try_catch_notify.html} | 2 +- .../features/fixtures/handled/webpack3/a.html | 9 --------- .../features/fixtures/handled/webpack3/b.html | 9 --------- .../handled/webpack3/notify_new_error.html | 9 +++++++++ .../c.html => webpack3/promise_catch.html} | 2 +- .../webpack3/src/{a.js => notify_new_error.js} | 0 .../webpack3/src/{c.js => promise_catch.js} | 0 .../webpack3/src/{b.js => try_catch_notify.js} | 0 .../handled/webpack3/try_catch_notify.html | 9 +++++++++ .../fixtures/handled/webpack3/webpack.config.js | 6 +++++- .../features/fixtures/handled/webpack4/a.html | 9 --------- .../features/fixtures/handled/webpack4/b.html | 9 --------- .../handled/webpack4/notify_new_error.html | 9 +++++++++ .../c.html => webpack4/promise_catch.html} | 2 +- .../webpack4/src/{a.js => notify_new_error.js} | 0 .../webpack4/src/{c.js => promise_catch.js} | 0 .../webpack4/src/{b.js => try_catch_notify.js} | 0 .../handled/webpack4/try_catch_notify.html | 9 +++++++++ .../fixtures/handled/webpack4/webpack.config.js | 6 +++++- test/browser/features/handled_errors.feature | 16 ++++++++-------- 48 files changed, 68 insertions(+), 60 deletions(-) rename test/browser/features/fixtures/handled/browserify/{a.html => notify_new_error.html} (64%) rename test/browser/features/fixtures/handled/{rollup/c.html => browserify/promise_catch.html} (87%) rename test/browser/features/fixtures/handled/browserify/src/{a.js => notify_new_error.js} (100%) rename test/browser/features/fixtures/handled/browserify/src/{c.js => promise_catch.js} (100%) rename test/browser/features/fixtures/handled/browserify/src/{b.js => try_catch_notify.js} (100%) rename test/browser/features/fixtures/handled/browserify/{b.html => try_catch_notify.html} (64%) rename test/browser/features/fixtures/handled/rollup/{b.html => notify_new_error.html} (64%) rename test/browser/features/fixtures/handled/{webpack4/c.html => rollup/promise_catch.html} (87%) rename test/browser/features/fixtures/handled/rollup/src/{a.js => notify_new_error.js} (100%) rename test/browser/features/fixtures/handled/rollup/src/{c.js => promise_catch.js} (100%) rename test/browser/features/fixtures/handled/rollup/src/{b.js => try_catch_notify.js} (100%) rename test/browser/features/fixtures/handled/rollup/{a.html => try_catch_notify.html} (64%) rename test/browser/features/fixtures/handled/script/{h.html => callback_override.html} (100%) rename test/browser/features/fixtures/handled/script/{f.html => client_notify_object.html} (100%) rename test/browser/features/fixtures/handled/script/{g.html => client_notify_string.html} (100%) rename test/browser/features/fixtures/handled/script/{a.html => notify_new_error.html} (100%) rename test/browser/features/fixtures/handled/script/{d.html => notify_object.html} (100%) rename test/browser/features/fixtures/handled/script/{e.html => notify_string.html} (100%) rename test/browser/features/fixtures/handled/script/{c.html => promise_catch.html} (100%) rename test/browser/features/fixtures/handled/script/{b.html => try_catch_notify.html} (100%) rename test/browser/features/fixtures/handled/typescript/{a.html => notify_new_error.html} (77%) rename test/browser/features/fixtures/handled/typescript/{c.html => promise_catch.html} (89%) rename test/browser/features/fixtures/handled/typescript/src/{a.ts => notify_new_error.ts} (100%) rename test/browser/features/fixtures/handled/typescript/src/{c.ts => promise_catch.ts} (100%) rename test/browser/features/fixtures/handled/typescript/src/{b.ts => try_catch_notify.ts} (100%) rename test/browser/features/fixtures/handled/typescript/{b.html => try_catch_notify.html} (77%) delete mode 100644 test/browser/features/fixtures/handled/webpack3/a.html delete mode 100644 test/browser/features/fixtures/handled/webpack3/b.html create mode 100644 test/browser/features/fixtures/handled/webpack3/notify_new_error.html rename test/browser/features/fixtures/handled/{browserify/c.html => webpack3/promise_catch.html} (87%) rename test/browser/features/fixtures/handled/webpack3/src/{a.js => notify_new_error.js} (100%) rename test/browser/features/fixtures/handled/webpack3/src/{c.js => promise_catch.js} (100%) rename test/browser/features/fixtures/handled/webpack3/src/{b.js => try_catch_notify.js} (100%) create mode 100644 test/browser/features/fixtures/handled/webpack3/try_catch_notify.html delete mode 100644 test/browser/features/fixtures/handled/webpack4/a.html delete mode 100644 test/browser/features/fixtures/handled/webpack4/b.html create mode 100644 test/browser/features/fixtures/handled/webpack4/notify_new_error.html rename test/browser/features/fixtures/handled/{webpack3/c.html => webpack4/promise_catch.html} (87%) rename test/browser/features/fixtures/handled/webpack4/src/{a.js => notify_new_error.js} (100%) rename test/browser/features/fixtures/handled/webpack4/src/{c.js => promise_catch.js} (100%) rename test/browser/features/fixtures/handled/webpack4/src/{b.js => try_catch_notify.js} (100%) create mode 100644 test/browser/features/fixtures/handled/webpack4/try_catch_notify.html diff --git a/test/browser/features/fixtures/handled/browserify/a.html b/test/browser/features/fixtures/handled/browserify/notify_new_error.html similarity index 64% rename from test/browser/features/fixtures/handled/browserify/a.html rename to test/browser/features/fixtures/handled/browserify/notify_new_error.html index 8f9a1579ce..5acf9f74c9 100644 --- a/test/browser/features/fixtures/handled/browserify/a.html +++ b/test/browser/features/fixtures/handled/browserify/notify_new_error.html @@ -2,7 +2,7 @@ - + diff --git a/test/browser/features/fixtures/handled/browserify/package.json b/test/browser/features/fixtures/handled/browserify/package.json index 68d667f57a..3b32b16f2b 100644 --- a/test/browser/features/fixtures/handled/browserify/package.json +++ b/test/browser/features/fixtures/handled/browserify/package.json @@ -2,7 +2,7 @@ "name": "bugsnag-js-fixtures-handled-browserify", "private": true, "scripts": { - "build": "browserify -o dist/a.js src/a.js && browserify -o dist/b.js src/b.js && browserify -o dist/c.js src/c.js" + "build": "browserify -o dist/notify_new_error.js src/notify_new_error.js && browserify -o dist/try_catch_notify.js src/try_catch_notify.js && browserify -o dist/promise_catch.js src/promise_catch.js" }, "dependencies": { "browserify": "^16.2.2" diff --git a/test/browser/features/fixtures/handled/rollup/c.html b/test/browser/features/fixtures/handled/browserify/promise_catch.html similarity index 87% rename from test/browser/features/fixtures/handled/rollup/c.html rename to test/browser/features/fixtures/handled/browserify/promise_catch.html index 783438d392..46b12dbe51 100644 --- a/test/browser/features/fixtures/handled/rollup/c.html +++ b/test/browser/features/fixtures/handled/browserify/promise_catch.html @@ -2,7 +2,7 @@ - +
PENDING
diff --git a/test/browser/features/fixtures/handled/browserify/src/a.js b/test/browser/features/fixtures/handled/browserify/src/notify_new_error.js similarity index 100% rename from test/browser/features/fixtures/handled/browserify/src/a.js rename to test/browser/features/fixtures/handled/browserify/src/notify_new_error.js diff --git a/test/browser/features/fixtures/handled/browserify/src/c.js b/test/browser/features/fixtures/handled/browserify/src/promise_catch.js similarity index 100% rename from test/browser/features/fixtures/handled/browserify/src/c.js rename to test/browser/features/fixtures/handled/browserify/src/promise_catch.js diff --git a/test/browser/features/fixtures/handled/browserify/src/b.js b/test/browser/features/fixtures/handled/browserify/src/try_catch_notify.js similarity index 100% rename from test/browser/features/fixtures/handled/browserify/src/b.js rename to test/browser/features/fixtures/handled/browserify/src/try_catch_notify.js diff --git a/test/browser/features/fixtures/handled/browserify/b.html b/test/browser/features/fixtures/handled/browserify/try_catch_notify.html similarity index 64% rename from test/browser/features/fixtures/handled/browserify/b.html rename to test/browser/features/fixtures/handled/browserify/try_catch_notify.html index 1368a97048..b77cec4b69 100644 --- a/test/browser/features/fixtures/handled/browserify/b.html +++ b/test/browser/features/fixtures/handled/browserify/try_catch_notify.html @@ -2,7 +2,7 @@ - + diff --git a/test/browser/features/fixtures/handled/rollup/b.html b/test/browser/features/fixtures/handled/rollup/notify_new_error.html similarity index 64% rename from test/browser/features/fixtures/handled/rollup/b.html rename to test/browser/features/fixtures/handled/rollup/notify_new_error.html index 1368a97048..5acf9f74c9 100644 --- a/test/browser/features/fixtures/handled/rollup/b.html +++ b/test/browser/features/fixtures/handled/rollup/notify_new_error.html @@ -2,7 +2,7 @@ - + diff --git a/test/browser/features/fixtures/handled/rollup/package.json b/test/browser/features/fixtures/handled/rollup/package.json index c0cb5ae527..33570806b8 100644 --- a/test/browser/features/fixtures/handled/rollup/package.json +++ b/test/browser/features/fixtures/handled/rollup/package.json @@ -2,7 +2,7 @@ "name": "bugsnag-js-fixtures-handled-rollup", "private": true, "scripts": { - "build": "ENTRY_NAME=a rollup -c && ENTRY_NAME=b rollup -c && ENTRY_NAME=c rollup -c" + "build": "ENTRY_NAME=notify_new_error rollup -c && ENTRY_NAME=try_catch_notify rollup -c && ENTRY_NAME=promise_catch rollup -c" }, "dependencies": { "rollup": "^0.59.0", diff --git a/test/browser/features/fixtures/handled/webpack4/c.html b/test/browser/features/fixtures/handled/rollup/promise_catch.html similarity index 87% rename from test/browser/features/fixtures/handled/webpack4/c.html rename to test/browser/features/fixtures/handled/rollup/promise_catch.html index 783438d392..46b12dbe51 100644 --- a/test/browser/features/fixtures/handled/webpack4/c.html +++ b/test/browser/features/fixtures/handled/rollup/promise_catch.html @@ -2,7 +2,7 @@ - +
PENDING
diff --git a/test/browser/features/fixtures/handled/rollup/src/a.js b/test/browser/features/fixtures/handled/rollup/src/notify_new_error.js similarity index 100% rename from test/browser/features/fixtures/handled/rollup/src/a.js rename to test/browser/features/fixtures/handled/rollup/src/notify_new_error.js diff --git a/test/browser/features/fixtures/handled/rollup/src/c.js b/test/browser/features/fixtures/handled/rollup/src/promise_catch.js similarity index 100% rename from test/browser/features/fixtures/handled/rollup/src/c.js rename to test/browser/features/fixtures/handled/rollup/src/promise_catch.js diff --git a/test/browser/features/fixtures/handled/rollup/src/b.js b/test/browser/features/fixtures/handled/rollup/src/try_catch_notify.js similarity index 100% rename from test/browser/features/fixtures/handled/rollup/src/b.js rename to test/browser/features/fixtures/handled/rollup/src/try_catch_notify.js diff --git a/test/browser/features/fixtures/handled/rollup/a.html b/test/browser/features/fixtures/handled/rollup/try_catch_notify.html similarity index 64% rename from test/browser/features/fixtures/handled/rollup/a.html rename to test/browser/features/fixtures/handled/rollup/try_catch_notify.html index 8f9a1579ce..b77cec4b69 100644 --- a/test/browser/features/fixtures/handled/rollup/a.html +++ b/test/browser/features/fixtures/handled/rollup/try_catch_notify.html @@ -2,7 +2,7 @@ - + diff --git a/test/browser/features/fixtures/handled/script/h.html b/test/browser/features/fixtures/handled/script/callback_override.html similarity index 100% rename from test/browser/features/fixtures/handled/script/h.html rename to test/browser/features/fixtures/handled/script/callback_override.html diff --git a/test/browser/features/fixtures/handled/script/f.html b/test/browser/features/fixtures/handled/script/client_notify_object.html similarity index 100% rename from test/browser/features/fixtures/handled/script/f.html rename to test/browser/features/fixtures/handled/script/client_notify_object.html diff --git a/test/browser/features/fixtures/handled/script/g.html b/test/browser/features/fixtures/handled/script/client_notify_string.html similarity index 100% rename from test/browser/features/fixtures/handled/script/g.html rename to test/browser/features/fixtures/handled/script/client_notify_string.html diff --git a/test/browser/features/fixtures/handled/script/a.html b/test/browser/features/fixtures/handled/script/notify_new_error.html similarity index 100% rename from test/browser/features/fixtures/handled/script/a.html rename to test/browser/features/fixtures/handled/script/notify_new_error.html diff --git a/test/browser/features/fixtures/handled/script/d.html b/test/browser/features/fixtures/handled/script/notify_object.html similarity index 100% rename from test/browser/features/fixtures/handled/script/d.html rename to test/browser/features/fixtures/handled/script/notify_object.html diff --git a/test/browser/features/fixtures/handled/script/e.html b/test/browser/features/fixtures/handled/script/notify_string.html similarity index 100% rename from test/browser/features/fixtures/handled/script/e.html rename to test/browser/features/fixtures/handled/script/notify_string.html diff --git a/test/browser/features/fixtures/handled/script/c.html b/test/browser/features/fixtures/handled/script/promise_catch.html similarity index 100% rename from test/browser/features/fixtures/handled/script/c.html rename to test/browser/features/fixtures/handled/script/promise_catch.html diff --git a/test/browser/features/fixtures/handled/script/b.html b/test/browser/features/fixtures/handled/script/try_catch_notify.html similarity index 100% rename from test/browser/features/fixtures/handled/script/b.html rename to test/browser/features/fixtures/handled/script/try_catch_notify.html diff --git a/test/browser/features/fixtures/handled/typescript/a.html b/test/browser/features/fixtures/handled/typescript/notify_new_error.html similarity index 77% rename from test/browser/features/fixtures/handled/typescript/a.html rename to test/browser/features/fixtures/handled/typescript/notify_new_error.html index 82e09f5a0b..4ee21f62c0 100644 --- a/test/browser/features/fixtures/handled/typescript/a.html +++ b/test/browser/features/fixtures/handled/typescript/notify_new_error.html @@ -5,6 +5,6 @@ - + diff --git a/test/browser/features/fixtures/handled/typescript/package.json b/test/browser/features/fixtures/handled/typescript/package.json index 2ac913849d..a88cc168df 100644 --- a/test/browser/features/fixtures/handled/typescript/package.json +++ b/test/browser/features/fixtures/handled/typescript/package.json @@ -2,7 +2,7 @@ "name": "bugsnag-js-fixtures-handled-typescript", "private": true, "scripts": { - "build": "browserify src/a.ts -p [ tsify ] -o dist/a.js && browserify src/b.ts -p [ tsify ] -o dist/b.js && browserify src/c.ts -p [ tsify ] -o dist/c.js" + "build": "browserify src/notify_new_error.ts -p [ tsify ] -o dist/notify_new_error.js && browserify src/try_catch_notify.ts -p [ tsify ] -o dist/try_catch_notify.js && browserify src/promise_catch.ts -p [ tsify ] -o dist/promise_catch.js" }, "dependencies": { "browserify": "^16.2.2", diff --git a/test/browser/features/fixtures/handled/typescript/c.html b/test/browser/features/fixtures/handled/typescript/promise_catch.html similarity index 89% rename from test/browser/features/fixtures/handled/typescript/c.html rename to test/browser/features/fixtures/handled/typescript/promise_catch.html index 4bd9194816..6c733bf27c 100644 --- a/test/browser/features/fixtures/handled/typescript/c.html +++ b/test/browser/features/fixtures/handled/typescript/promise_catch.html @@ -12,6 +12,6 @@ ? 'YES' : 'NO' - + diff --git a/test/browser/features/fixtures/handled/typescript/src/a.ts b/test/browser/features/fixtures/handled/typescript/src/notify_new_error.ts similarity index 100% rename from test/browser/features/fixtures/handled/typescript/src/a.ts rename to test/browser/features/fixtures/handled/typescript/src/notify_new_error.ts diff --git a/test/browser/features/fixtures/handled/typescript/src/c.ts b/test/browser/features/fixtures/handled/typescript/src/promise_catch.ts similarity index 100% rename from test/browser/features/fixtures/handled/typescript/src/c.ts rename to test/browser/features/fixtures/handled/typescript/src/promise_catch.ts diff --git a/test/browser/features/fixtures/handled/typescript/src/b.ts b/test/browser/features/fixtures/handled/typescript/src/try_catch_notify.ts similarity index 100% rename from test/browser/features/fixtures/handled/typescript/src/b.ts rename to test/browser/features/fixtures/handled/typescript/src/try_catch_notify.ts diff --git a/test/browser/features/fixtures/handled/typescript/b.html b/test/browser/features/fixtures/handled/typescript/try_catch_notify.html similarity index 77% rename from test/browser/features/fixtures/handled/typescript/b.html rename to test/browser/features/fixtures/handled/typescript/try_catch_notify.html index 4dad86ea72..03d4036d35 100644 --- a/test/browser/features/fixtures/handled/typescript/b.html +++ b/test/browser/features/fixtures/handled/typescript/try_catch_notify.html @@ -5,6 +5,6 @@ - + diff --git a/test/browser/features/fixtures/handled/webpack3/a.html b/test/browser/features/fixtures/handled/webpack3/a.html deleted file mode 100644 index 8f9a1579ce..0000000000 --- a/test/browser/features/fixtures/handled/webpack3/a.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/test/browser/features/fixtures/handled/webpack3/b.html b/test/browser/features/fixtures/handled/webpack3/b.html deleted file mode 100644 index 1368a97048..0000000000 --- a/test/browser/features/fixtures/handled/webpack3/b.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/test/browser/features/fixtures/handled/webpack3/notify_new_error.html b/test/browser/features/fixtures/handled/webpack3/notify_new_error.html new file mode 100644 index 0000000000..5acf9f74c9 --- /dev/null +++ b/test/browser/features/fixtures/handled/webpack3/notify_new_error.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/browser/features/fixtures/handled/browserify/c.html b/test/browser/features/fixtures/handled/webpack3/promise_catch.html similarity index 87% rename from test/browser/features/fixtures/handled/browserify/c.html rename to test/browser/features/fixtures/handled/webpack3/promise_catch.html index 783438d392..46b12dbe51 100644 --- a/test/browser/features/fixtures/handled/browserify/c.html +++ b/test/browser/features/fixtures/handled/webpack3/promise_catch.html @@ -2,7 +2,7 @@ - +
PENDING
diff --git a/test/browser/features/fixtures/handled/webpack3/src/a.js b/test/browser/features/fixtures/handled/webpack3/src/notify_new_error.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack3/src/a.js rename to test/browser/features/fixtures/handled/webpack3/src/notify_new_error.js diff --git a/test/browser/features/fixtures/handled/webpack3/src/c.js b/test/browser/features/fixtures/handled/webpack3/src/promise_catch.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack3/src/c.js rename to test/browser/features/fixtures/handled/webpack3/src/promise_catch.js diff --git a/test/browser/features/fixtures/handled/webpack3/src/b.js b/test/browser/features/fixtures/handled/webpack3/src/try_catch_notify.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack3/src/b.js rename to test/browser/features/fixtures/handled/webpack3/src/try_catch_notify.js diff --git a/test/browser/features/fixtures/handled/webpack3/try_catch_notify.html b/test/browser/features/fixtures/handled/webpack3/try_catch_notify.html new file mode 100644 index 0000000000..b77cec4b69 --- /dev/null +++ b/test/browser/features/fixtures/handled/webpack3/try_catch_notify.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/browser/features/fixtures/handled/webpack3/webpack.config.js b/test/browser/features/fixtures/handled/webpack3/webpack.config.js index 2bfe48512b..b5e65c2cea 100644 --- a/test/browser/features/fixtures/handled/webpack3/webpack.config.js +++ b/test/browser/features/fixtures/handled/webpack3/webpack.config.js @@ -3,7 +3,11 @@ const webpack = require('webpack') const es3ifyPlugin = require('es3ify-webpack-plugin') module.exports = { - entry: { a: './src/a.js', b: './src/b.js', c: './src/c.js' }, + entry: { + notify_new_error: './src/notify_new_error.js', + try_catch_notify: './src/try_catch_notify.js', + promise_catch: './src/promise_catch.js' + }, devtool: 'sourcemap', output: { path: path.resolve(__dirname, 'dist'), diff --git a/test/browser/features/fixtures/handled/webpack4/a.html b/test/browser/features/fixtures/handled/webpack4/a.html deleted file mode 100644 index 8f9a1579ce..0000000000 --- a/test/browser/features/fixtures/handled/webpack4/a.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/test/browser/features/fixtures/handled/webpack4/b.html b/test/browser/features/fixtures/handled/webpack4/b.html deleted file mode 100644 index 1368a97048..0000000000 --- a/test/browser/features/fixtures/handled/webpack4/b.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/test/browser/features/fixtures/handled/webpack4/notify_new_error.html b/test/browser/features/fixtures/handled/webpack4/notify_new_error.html new file mode 100644 index 0000000000..5acf9f74c9 --- /dev/null +++ b/test/browser/features/fixtures/handled/webpack4/notify_new_error.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/browser/features/fixtures/handled/webpack3/c.html b/test/browser/features/fixtures/handled/webpack4/promise_catch.html similarity index 87% rename from test/browser/features/fixtures/handled/webpack3/c.html rename to test/browser/features/fixtures/handled/webpack4/promise_catch.html index 783438d392..46b12dbe51 100644 --- a/test/browser/features/fixtures/handled/webpack3/c.html +++ b/test/browser/features/fixtures/handled/webpack4/promise_catch.html @@ -2,7 +2,7 @@ - +
PENDING
diff --git a/test/browser/features/fixtures/handled/webpack4/src/a.js b/test/browser/features/fixtures/handled/webpack4/src/notify_new_error.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack4/src/a.js rename to test/browser/features/fixtures/handled/webpack4/src/notify_new_error.js diff --git a/test/browser/features/fixtures/handled/webpack4/src/c.js b/test/browser/features/fixtures/handled/webpack4/src/promise_catch.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack4/src/c.js rename to test/browser/features/fixtures/handled/webpack4/src/promise_catch.js diff --git a/test/browser/features/fixtures/handled/webpack4/src/b.js b/test/browser/features/fixtures/handled/webpack4/src/try_catch_notify.js similarity index 100% rename from test/browser/features/fixtures/handled/webpack4/src/b.js rename to test/browser/features/fixtures/handled/webpack4/src/try_catch_notify.js diff --git a/test/browser/features/fixtures/handled/webpack4/try_catch_notify.html b/test/browser/features/fixtures/handled/webpack4/try_catch_notify.html new file mode 100644 index 0000000000..b77cec4b69 --- /dev/null +++ b/test/browser/features/fixtures/handled/webpack4/try_catch_notify.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/browser/features/fixtures/handled/webpack4/webpack.config.js b/test/browser/features/fixtures/handled/webpack4/webpack.config.js index dda2766412..9ca9996749 100644 --- a/test/browser/features/fixtures/handled/webpack4/webpack.config.js +++ b/test/browser/features/fixtures/handled/webpack4/webpack.config.js @@ -3,7 +3,11 @@ const es3ifyPlugin = require('es3ify-webpack-plugin') const UglifyJsPlugin = require('uglifyjs-webpack-plugin') module.exports = { - entry: { a: './src/a.js', b: './src/b.js', c: './src/c.js' }, + entry: { + notify_new_error: './src/notify_new_error.js', + try_catch_notify: './src/try_catch_notify.js', + promise_catch: './src/promise_catch.js' + }, mode: 'none', output: { path: path.resolve(__dirname, 'dist'), diff --git a/test/browser/features/handled_errors.feature b/test/browser/features/handled_errors.feature index 82b8f682c0..73df1dcd7a 100644 --- a/test/browser/features/handled_errors.feature +++ b/test/browser/features/handled_errors.feature @@ -2,7 +2,7 @@ Feature: Reporting handled errors Scenario Outline: calling notify() with Error - When I navigate to the test URL "/handled//a.html" + When I navigate to the test URL "/handled//notify_new_error.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -21,7 +21,7 @@ Scenario Outline: calling notify() with Error | typescript | Scenario Outline: calling notify() with Error within try/catch - When I navigate to the test URL "/handled//b.html" + When I navigate to the test URL "/handled//try_catch_notify.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception matches the "handled" values for the current browser @@ -38,7 +38,7 @@ Scenario Outline: calling notify() with Error within try/catch | typescript | Scenario Outline: calling notify() with Error within Promise catch - When I navigate to the test URL "/handled//c.html" + When I navigate to the test URL "/handled//promise_catch.html" And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API @@ -57,7 +57,7 @@ Scenario Outline: calling notify() with Error within Promise catch | typescript | Scenario: calling notify() with an object, getting a generated a stacktrace - When I navigate to the test URL "/handled/script/d.html" + When I navigate to the test URL "/handled/script/notify_object.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Errr" @@ -69,7 +69,7 @@ Scenario: calling notify() with an object, getting a generated a stacktrace And event 0 is handled Scenario: calling notify() with a string, getting a generated stacktrace - When I navigate to the test URL "/handled/script/e.html" + When I navigate to the test URL "/handled/script/notify_string.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -81,7 +81,7 @@ Scenario: calling notify() with a string, getting a generated stacktrace And event 0 is handled Scenario: calling window.client.notify() with an object, getting a generated stacktrace - When I navigate to the test URL "/handled/script/f.html" + When I navigate to the test URL "/handled/script/client_notify_object.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -95,7 +95,7 @@ Scenario: calling window.client.notify() with an object, getting a generated sta And event 0 is handled Scenario: calling window.client.notify() with a string, getting a generated stacktrace - When I navigate to the test URL "/handled/script/g.html" + When I navigate to the test URL "/handled/script/client_notify_string.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -109,7 +109,7 @@ Scenario: calling window.client.notify() with a string, getting a generated stac And event 0 is handled Scenario: overridden handled state in a callback - When I navigate to the test URL "/handled/script/h.html" + When I navigate to the test URL "/handled/script/callback_override.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "message" ends with "hello" From 71d0eb69dfc854799a84ab6d7ea7a6ef24c222fd Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Wed, 3 Dec 2025 09:43:35 +0000 Subject: [PATCH 26/43] Rename fixtures files (batch 4) (#2623) * Rename csp fixture * Rename delivery fixture * Rename device fixture files * Rename "a" fixture files * Rename "b" fixture files * Rename "c" fixture files * Rename remaining fixture files * Rename fixture files * Rename fixture files * Rename fixture files * Corrections * Corrections * Rename fixture files * Correction * Correction file name * Move BitBar browser tests to EU hub --------- Co-authored-by: Steve Kirkland --- .buildkite/basic/browser-pipeline.yml | 4 ++-- docker-compose.yml | 1 + .../script/{b.html => load_after_script.html} | 2 +- .../script/{b.js => load_after_script.js} | 0 .../script/{a.html => load_before_script.html} | 0 .../ip_redaction/script/{a.html => collect_false.html} | 0 .../ip_redaction/script/{b.html => id_provided.html} | 0 .../navigation/script/{a.html => navigation.html} | 0 .../on_error/script/{a.html => onerror_config.html} | 0 .../script/{b.html => onerror_config_false.html} | 0 .../on_error/script/{d.html => onerror_notify.html} | 0 .../script/{e.html => onerror_notify_false.html} | 0 .../redaction/script/{b.html => overrides.html} | 0 .../redaction/script/{a.html => password.html} | 0 .../fixtures/redaction/script/{d.html => regexes.html} | 0 .../redaction/script/{c.html => subtrees.html} | 0 test/browser/features/inline_script.feature | 6 +++--- test/browser/features/ip_redaction.feature | 4 ++-- test/browser/features/on_error.feature | 10 ++++------ test/browser/features/redaction.feature | 8 ++++---- 20 files changed, 17 insertions(+), 18 deletions(-) rename test/browser/features/fixtures/inline_script/script/{b.html => load_after_script.html} (90%) rename test/browser/features/fixtures/inline_script/script/{b.js => load_after_script.js} (100%) rename test/browser/features/fixtures/inline_script/script/{a.html => load_before_script.html} (100%) rename test/browser/features/fixtures/ip_redaction/script/{a.html => collect_false.html} (100%) rename test/browser/features/fixtures/ip_redaction/script/{b.html => id_provided.html} (100%) rename test/browser/features/fixtures/navigation/script/{a.html => navigation.html} (100%) rename test/browser/features/fixtures/on_error/script/{a.html => onerror_config.html} (100%) rename test/browser/features/fixtures/on_error/script/{b.html => onerror_config_false.html} (100%) rename test/browser/features/fixtures/on_error/script/{d.html => onerror_notify.html} (100%) rename test/browser/features/fixtures/on_error/script/{e.html => onerror_notify_false.html} (100%) rename test/browser/features/fixtures/redaction/script/{b.html => overrides.html} (100%) rename test/browser/features/fixtures/redaction/script/{a.html => password.html} (100%) rename test/browser/features/fixtures/redaction/script/{d.html => regexes.html} (100%) rename test/browser/features/fixtures/redaction/script/{c.html => subtrees.html} (100%) diff --git a/.buildkite/basic/browser-pipeline.yml b/.buildkite/basic/browser-pipeline.yml index a3440064b1..cb92f22e2f 100644 --- a/.buildkite/basic/browser-pipeline.yml +++ b/.buildkite/basic/browser-pipeline.yml @@ -111,7 +111,7 @@ steps: # # BitBar tests # - - label: ":bitbar: {{matrix}} Browser tests (US hub)" + - label: ":bitbar: {{matrix}} Browser tests (EU hub)" matrix: - firefox_latest - chrome_latest @@ -142,7 +142,7 @@ steps: concurrency_group: "bitbar" concurrency_method: eager - - label: ":bitbar: ie_11 Browser tests" + - label: ":bitbar: ie_11 Browser tests (EU hub)" depends_on: "browser-maze-runner-bb" timeout_in_minutes: 30 plugins: diff --git a/docker-compose.yml b/docker-compose.yml index 550a97d8b0..4d3768957f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -55,6 +55,7 @@ services: API_HOST: "${API_HOST:-maze-runner}" MAZE_REPEATER_API_KEY: "${MAZE_REPEATER_API_KEY_BROWSER:-}" MAZE_HUB_REPEATER_API_KEY: "${MAZE_HUB_REPEATER_API_KEY_BROWSER:-}" + MAZE_SELENIUM_SERVER: "https://eu-desktop-hub.bitbar.com/wd/hub" env_file: - ${DOCKER_ENV_FILE:-test/browser/features/fixtures/null_env} networks: diff --git a/test/browser/features/fixtures/inline_script/script/b.html b/test/browser/features/fixtures/inline_script/script/load_after_script.html similarity index 90% rename from test/browser/features/fixtures/inline_script/script/b.html rename to test/browser/features/fixtures/inline_script/script/load_after_script.html index 2547fce1a7..703812ee00 100644 --- a/test/browser/features/fixtures/inline_script/script/b.html +++ b/test/browser/features/fixtures/inline_script/script/load_after_script.html @@ -9,7 +9,7 @@ - + diff --git a/test/browser/features/fixtures/inline_script/script/b.js b/test/browser/features/fixtures/inline_script/script/load_after_script.js similarity index 100% rename from test/browser/features/fixtures/inline_script/script/b.js rename to test/browser/features/fixtures/inline_script/script/load_after_script.js diff --git a/test/browser/features/fixtures/inline_script/script/a.html b/test/browser/features/fixtures/inline_script/script/load_before_script.html similarity index 100% rename from test/browser/features/fixtures/inline_script/script/a.html rename to test/browser/features/fixtures/inline_script/script/load_before_script.html diff --git a/test/browser/features/fixtures/ip_redaction/script/a.html b/test/browser/features/fixtures/ip_redaction/script/collect_false.html similarity index 100% rename from test/browser/features/fixtures/ip_redaction/script/a.html rename to test/browser/features/fixtures/ip_redaction/script/collect_false.html diff --git a/test/browser/features/fixtures/ip_redaction/script/b.html b/test/browser/features/fixtures/ip_redaction/script/id_provided.html similarity index 100% rename from test/browser/features/fixtures/ip_redaction/script/b.html rename to test/browser/features/fixtures/ip_redaction/script/id_provided.html diff --git a/test/browser/features/fixtures/navigation/script/a.html b/test/browser/features/fixtures/navigation/script/navigation.html similarity index 100% rename from test/browser/features/fixtures/navigation/script/a.html rename to test/browser/features/fixtures/navigation/script/navigation.html diff --git a/test/browser/features/fixtures/on_error/script/a.html b/test/browser/features/fixtures/on_error/script/onerror_config.html similarity index 100% rename from test/browser/features/fixtures/on_error/script/a.html rename to test/browser/features/fixtures/on_error/script/onerror_config.html diff --git a/test/browser/features/fixtures/on_error/script/b.html b/test/browser/features/fixtures/on_error/script/onerror_config_false.html similarity index 100% rename from test/browser/features/fixtures/on_error/script/b.html rename to test/browser/features/fixtures/on_error/script/onerror_config_false.html diff --git a/test/browser/features/fixtures/on_error/script/d.html b/test/browser/features/fixtures/on_error/script/onerror_notify.html similarity index 100% rename from test/browser/features/fixtures/on_error/script/d.html rename to test/browser/features/fixtures/on_error/script/onerror_notify.html diff --git a/test/browser/features/fixtures/on_error/script/e.html b/test/browser/features/fixtures/on_error/script/onerror_notify_false.html similarity index 100% rename from test/browser/features/fixtures/on_error/script/e.html rename to test/browser/features/fixtures/on_error/script/onerror_notify_false.html diff --git a/test/browser/features/fixtures/redaction/script/b.html b/test/browser/features/fixtures/redaction/script/overrides.html similarity index 100% rename from test/browser/features/fixtures/redaction/script/b.html rename to test/browser/features/fixtures/redaction/script/overrides.html diff --git a/test/browser/features/fixtures/redaction/script/a.html b/test/browser/features/fixtures/redaction/script/password.html similarity index 100% rename from test/browser/features/fixtures/redaction/script/a.html rename to test/browser/features/fixtures/redaction/script/password.html diff --git a/test/browser/features/fixtures/redaction/script/d.html b/test/browser/features/fixtures/redaction/script/regexes.html similarity index 100% rename from test/browser/features/fixtures/redaction/script/d.html rename to test/browser/features/fixtures/redaction/script/regexes.html diff --git a/test/browser/features/fixtures/redaction/script/c.html b/test/browser/features/fixtures/redaction/script/subtrees.html similarity index 100% rename from test/browser/features/fixtures/redaction/script/c.html rename to test/browser/features/fixtures/redaction/script/subtrees.html diff --git a/test/browser/features/inline_script.feature b/test/browser/features/inline_script.feature index 25b48dfdb1..ba9351574f 100644 --- a/test/browser/features/inline_script.feature +++ b/test/browser/features/inline_script.feature @@ -1,7 +1,7 @@ Feature: Inline script detection Scenario: loading Bugsnag before scripts have run - When I navigate to the test URL "/inline_script/script/a.html" + When I navigate to the test URL "/inline_script/script/load_before_script.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -11,7 +11,7 @@ Feature: Inline script detection And the event "metaData.script" is not null Scenario: loading Bugsnag after scripts have run - When I navigate to the test URL "/inline_script/script/b.html" + When I navigate to the test URL "/inline_script/script/load_after_script.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -21,7 +21,7 @@ Feature: Inline script detection And the event "metaData.script" is null Scenario: inline script detected after location change - When I navigate to the test URL "/navigation/script/a.html" + When I navigate to the test URL "/navigation/script/navigation.html" And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API diff --git a/test/browser/features/ip_redaction.feature b/test/browser/features/ip_redaction.feature index a6502449ab..7b7b574466 100644 --- a/test/browser/features/ip_redaction.feature +++ b/test/browser/features/ip_redaction.feature @@ -3,7 +3,7 @@ Feature: Redacting IP addresses @skip_if_local_storage_is_unavailable Scenario: setting collectUserIp option to false - When I navigate to the test URL "/ip_redaction/script/a.html" + When I navigate to the test URL "/ip_redaction/script/collect_false.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "device.id" is not null @@ -13,7 +13,7 @@ Scenario: setting collectUserIp option to false And the error payload field "events.0.user.id" equals the stored value "device_id" Scenario: setting collectUserIp option to false and providing user id - When I navigate to the test URL "/ip_redaction/script/b.html" + When I navigate to the test URL "/ip_redaction/script/id_provided.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "request.clientIp" equals "[REDACTED]" diff --git a/test/browser/features/on_error.feature b/test/browser/features/on_error.feature index 0e2500263f..bc23bdb4fe 100644 --- a/test/browser/features/on_error.feature +++ b/test/browser/features/on_error.feature @@ -2,23 +2,21 @@ Feature: onError callbacks Scenario: modifying report via onError in config - When I navigate to the test URL "/on_error/script/a.html" + When I navigate to the test URL "/on_error/script/onerror_config.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "metaData.on_error.global" equals "works" Scenario: ignoring report via onError in config (return false) - When I navigate to the test URL "/on_error/script/b.html" - And I wait for 1 second + When I navigate to the test URL "/on_error/script/onerror_config_false.html" Then I should receive no errors Scenario: setting onError in notify opts - When I navigate to the test URL "/on_error/script/d.html" + When I navigate to the test URL "/on_error/script/onerror_notify.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "metaData.on_error.notify_opts" equals "works" Scenario: ignoring report via onError in notify opts (return false) - When I navigate to the test URL "/on_error/script/e.html" - And I wait for 1 second + When I navigate to the test URL "/on_error/script/onerror_notify_false.html" Then I should receive no errors diff --git a/test/browser/features/redaction.feature b/test/browser/features/redaction.feature index db3b0ebcb5..d6c7b33dad 100644 --- a/test/browser/features/redaction.feature +++ b/test/browser/features/redaction.feature @@ -2,14 +2,14 @@ Feature: Filtering sensitive content from payload Scenario: "password" is filtered by default - When I navigate to the test URL "/redaction/script/a.html" + When I navigate to the test URL "/redaction/script/password.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "21" And the event "metaData.user.password" equals "[REDACTED]" Scenario: User setting can override defaults - When I navigate to the test URL "/redaction/script/b.html" + When I navigate to the test URL "/redaction/script/overrides.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "21" @@ -18,7 +18,7 @@ Scenario: User setting can override defaults And the event "metaData.details.api_key" equals "[REDACTED]" Scenario: it only removes properties from specific payload subtrees - When I navigate to the test URL "/redaction/script/c.html" + When I navigate to the test URL "/redaction/script/subtrees.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "21" @@ -28,7 +28,7 @@ Scenario: it only removes properties from specific payload subtrees And the "method" of stack frame 0 equals "handle" Scenario: it works with regexes - When I navigate to the test URL "/redaction/script/d.html" + When I navigate to the test URL "/redaction/script/regexes.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "metaData.extra.details0" equals "[REDACTED]" From 24d3d4c2c7a66a3e8609f0cf801dae566ba3b2f1 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Wed, 3 Dec 2025 10:01:52 +0000 Subject: [PATCH 27/43] Rename fixtures files (final batch, 5) (#2624) * Rename csp fixture * Rename delivery fixture * Rename device fixture files * Rename "a" fixture files * Rename "b" fixture files * Rename "c" fixture files * Rename remaining fixture files * Rename fixture files * Rename fixture files * Rename fixture files * Corrections * Corrections * Rename fixture files * Correction * Correction file name * Rename fixture files * Remove obsolete docker compose file versions * Rename test fixture files * Rename fixture files * Corrections * Renae fixture files * Move BitBar browser tests to EU hub * Fail fast and pipeline consistency --------- Co-authored-by: Steve Kirkland --- .buildkite/basic/browser-pipeline.yml | 70 ++++++++++--------- docker-compose.yml | 2 - .../features/fixtures/browser_errors.yml | 34 ++++----- .../{f.html => empty_enabled_stages.html} | 0 .../{e.html => null_enabled_stages.html} | 0 ...{b.html => release_stage_development.html} | 0 .../{d.html => release_stage_enabled.html} | 0 ...{c.html => release_stage_not_enabled.html} | 0 .../{a.html => release_stage_production.html} | 0 .../sessions/script/{a.html => default.html} | 0 .../script/{b.html => sessions_disabled.html} | 0 .../script/@dist/{g.js => at_filename.js} | 0 .../script/{g.html => at_filename.html} | 2 +- .../script/{f.html => bluebird.html} | 0 .../script/{e.html => malformed_uri.html} | 0 .../{h.html => override_unhandled.html} | 0 .../script/{c.html => promise_rejection.html} | 0 .../script/{a.html => syntax_error.html} | 0 .../unhandled/script/{b.html => thrown.html} | 0 .../{d.html => undefined_function.html} | 0 .../user_info/script/{b.html => client.html} | 0 .../user_info/script/{a.html => config.html} | 0 .../script/{f.html => device_id.html} | 0 .../user_info/script/{e.html => no_user.html} | 0 .../script/{d.html => on_error.html} | 0 .../script/{g.html => user_id_holds.html} | 0 test/browser/features/release_stage.feature | 14 ++-- test/browser/features/sessions.feature | 5 +- .../browser/features/unhandled_errors.feature | 18 ++--- test/browser/features/user_info.feature | 12 ++-- .../node/features/fixtures/docker-compose.yml | 1 - 31 files changed, 78 insertions(+), 80 deletions(-) rename test/browser/features/fixtures/release_stage/script/{f.html => empty_enabled_stages.html} (100%) rename test/browser/features/fixtures/release_stage/script/{e.html => null_enabled_stages.html} (100%) rename test/browser/features/fixtures/release_stage/script/{b.html => release_stage_development.html} (100%) rename test/browser/features/fixtures/release_stage/script/{d.html => release_stage_enabled.html} (100%) rename test/browser/features/fixtures/release_stage/script/{c.html => release_stage_not_enabled.html} (100%) rename test/browser/features/fixtures/release_stage/script/{a.html => release_stage_production.html} (100%) rename test/browser/features/fixtures/sessions/script/{a.html => default.html} (100%) rename test/browser/features/fixtures/sessions/script/{b.html => sessions_disabled.html} (100%) rename test/browser/features/fixtures/unhandled/script/@dist/{g.js => at_filename.js} (100%) rename test/browser/features/fixtures/unhandled/script/{g.html => at_filename.html} (92%) rename test/browser/features/fixtures/unhandled/script/{f.html => bluebird.html} (100%) rename test/browser/features/fixtures/unhandled/script/{e.html => malformed_uri.html} (100%) rename test/browser/features/fixtures/unhandled/script/{h.html => override_unhandled.html} (100%) rename test/browser/features/fixtures/unhandled/script/{c.html => promise_rejection.html} (100%) rename test/browser/features/fixtures/unhandled/script/{a.html => syntax_error.html} (100%) rename test/browser/features/fixtures/unhandled/script/{b.html => thrown.html} (100%) rename test/browser/features/fixtures/unhandled/script/{d.html => undefined_function.html} (100%) rename test/browser/features/fixtures/user_info/script/{b.html => client.html} (100%) rename test/browser/features/fixtures/user_info/script/{a.html => config.html} (100%) rename test/browser/features/fixtures/user_info/script/{f.html => device_id.html} (100%) rename test/browser/features/fixtures/user_info/script/{e.html => no_user.html} (100%) rename test/browser/features/fixtures/user_info/script/{d.html => on_error.html} (100%) rename test/browser/features/fixtures/user_info/script/{g.html => user_id_holds.html} (100%) diff --git a/.buildkite/basic/browser-pipeline.yml b/.buildkite/basic/browser-pipeline.yml index cb92f22e2f..07bb29e095 100644 --- a/.buildkite/basic/browser-pipeline.yml +++ b/.buildkite/basic/browser-pipeline.yml @@ -11,15 +11,15 @@ steps: timeout_in_minutes: 20 plugins: - artifacts#v1.5.0: - download: min_packages.tar + download: "min_packages.tar" - docker-compose#v4.12.0: build: - - browser-maze-runner-bb - image-repository: 855461928731.dkr.ecr.us-west-1.amazonaws.com/js + - "browser-maze-runner-bb" + image-repository: "855461928731.dkr.ecr.us-west-1.amazonaws.com/js" cache-from: - - browser-maze-runner-bb:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME} + - "browser-maze-runner-bb:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME}" push: - - browser-maze-runner-bb:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME} + - "browser-maze-runner-bb:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME}" retry: automatic: - exit_status: "*" @@ -31,15 +31,15 @@ steps: timeout_in_minutes: 20 plugins: - artifacts#v1.5.0: - download: min_packages.tar + download: "min_packages.tar" - docker-compose#v4.12.0: build: - - browser-maze-runner-bs - image-repository: 855461928731.dkr.ecr.us-west-1.amazonaws.com/js + - "browser-maze-runner-bs" + image-repository: "855461928731.dkr.ecr.us-west-1.amazonaws.com/js" cache-from: - - browser-maze-runner-bs:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME} + - "browser-maze-runner-bs:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME}" push: - - browser-maze-runner-bs:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME} + - "browser-maze-runner-bs:855461928731.dkr.ecr.us-west-1.amazonaws.com/js:ci-browser-${BRANCH_NAME}" retry: automatic: - exit_status: "*" @@ -50,15 +50,16 @@ steps: # - label: ":browserstack: {{matrix}} non-https tests" matrix: - - safari_16 + - "safari_16" depends_on: "browser-maze-runner-bs" timeout_in_minutes: 30 plugins: docker-compose#v4.12.0: - pull: browser-maze-runner-bs - run: browser-maze-runner-bs + pull: "browser-maze-runner-bs" + run: "browser-maze-runner-bs" use-aliases: true command: + - "--fail-fast" - "--farm=bs" - "--browser={{matrix}}" artifacts#v1.5.0: @@ -71,28 +72,29 @@ steps: api-token-env-name: "BROWSER_BUILDKITE_ANALYTICS_TOKEN" concurrency: 2 concurrency_group: "browserstack" - concurrency_method: eager + concurrency_method: "eager" # # BrowserStack https tests # - label: ":browserstack: {{matrix}} tests" matrix: - - edge_17 - - safari_10 - - ios_15 - - android_9 - - chrome_43 - - chrome_72 - - firefox_78 + - "edge_17" + - "safari_10" + - "ios_15" + - "android_9" + - "chrome_43" + - "chrome_72" + - "firefox_78" depends_on: "browser-maze-runner-bs" timeout_in_minutes: 30 plugins: docker-compose#v4.12.0: - pull: browser-maze-runner-bs - run: browser-maze-runner-bs + pull: "browser-maze-runner-bs" + run: "browser-maze-runner-bs" use-aliases: true command: + - "--fail-fast" - "--https" - "--farm=bs" - "--browser={{matrix}}" @@ -106,25 +108,26 @@ steps: api-token-env-name: "BROWSER_BUILDKITE_ANALYTICS_TOKEN" concurrency: 2 concurrency_group: "browserstack" - concurrency_method: eager + concurrency_method: "eager" # # BitBar tests # - label: ":bitbar: {{matrix}} Browser tests (EU hub)" matrix: - - firefox_latest - - chrome_latest - - edge_latest + - "firefox_latest" + - "chrome_latest" + - "edge_latest" depends_on: "browser-maze-runner-bb" timeout_in_minutes: 30 plugins: docker-compose#v4.12.0: - pull: browser-maze-runner-bb - run: browser-maze-runner-bb + pull: "browser-maze-runner-bb" + run: "browser-maze-runner-bb" service-ports: true use-aliases: true command: + - "--fail-fast" - "--https" - "--farm=bb" - "--browser={{matrix}}" @@ -140,18 +143,19 @@ steps: api-token-env-name: "BROWSER_BUILDKITE_ANALYTICS_TOKEN" concurrency: 25 concurrency_group: "bitbar" - concurrency_method: eager + concurrency_method: "eager" - label: ":bitbar: ie_11 Browser tests (EU hub)" depends_on: "browser-maze-runner-bb" timeout_in_minutes: 30 plugins: docker-compose#v4.12.0: - pull: browser-maze-runner-bb - run: browser-maze-runner-bb + pull: "browser-maze-runner-bb" + run: "browser-maze-runner-bb" service-ports: true use-aliases: true command: + - "--fail-fast" - "--farm=bb" - "--browser=ie_11" - "--no-tunnel" @@ -166,6 +170,6 @@ steps: api-token-env-name: "BROWSER_BUILDKITE_ANALYTICS_TOKEN" concurrency: 25 concurrency_group: "bitbar" - concurrency_method: eager + concurrency_method: "eager" env: HOST: "localhost" # IE11 needs the host set to localhost diff --git a/docker-compose.yml b/docker-compose.yml index 4d3768957f..c18d714281 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.6' - x-common-environment: &common-environment BUILDKITE: BUILDKITE_BRANCH: diff --git a/test/browser/features/fixtures/browser_errors.yml b/test/browser/features/fixtures/browser_errors.yml index 77a30e4cc0..e869f3600a 100644 --- a/test/browser/features/fixtures/browser_errors.yml +++ b/test/browser/features/fixtures/browser_errors.yml @@ -8,7 +8,7 @@ ie_11: errorMessage: "Expected ';'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -34,7 +34,7 @@ edge_17: errorMessage: "Expected ';'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -60,7 +60,7 @@ safari_10: errorMessage: "Unexpected token '!'. Parse error." lineNumber: 18 columnNumber: 0 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -86,7 +86,7 @@ safari_16: errorMessage: "Unexpected token '!'. Parse error." lineNumber: 18 columnNumber: 0 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -112,7 +112,7 @@ ios_11: errorMessage: "Unexpected token '!'. Parse error." lineNumber: 18 columnNumber: 0 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -138,7 +138,7 @@ ios_15: errorMessage: "Unexpected token '!'. Parse error." lineNumber: 18 columnNumber: 0 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -164,7 +164,7 @@ android_4: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -190,7 +190,7 @@ android_6: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -216,7 +216,7 @@ android_7: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -242,7 +242,7 @@ android_8: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -268,7 +268,7 @@ android_9: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -294,7 +294,7 @@ firefox_78: errorMessage: "unexpected token: '!'" lineNumber: 18 columnNumber: 12 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -320,7 +320,7 @@ chrome_43: errorMessage: "Unexpected token !" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -346,7 +346,7 @@ chrome_72: errorMessage: "Unexpected token !" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -374,7 +374,7 @@ chrome_latest: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -400,7 +400,7 @@ edge_latest: errorMessage: "Unexpected token '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" @@ -426,7 +426,7 @@ firefox_latest: errorMessage: "unexpected token: '!'" lineNumber: 18 columnNumber: 13 - file: '/unhandled/script/a.html' + file: '/unhandled/script/syntax_error.html' unhandled_thrown: errorClass: 'Error' errorMessage: "bad things" diff --git a/test/browser/features/fixtures/release_stage/script/f.html b/test/browser/features/fixtures/release_stage/script/empty_enabled_stages.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/f.html rename to test/browser/features/fixtures/release_stage/script/empty_enabled_stages.html diff --git a/test/browser/features/fixtures/release_stage/script/e.html b/test/browser/features/fixtures/release_stage/script/null_enabled_stages.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/e.html rename to test/browser/features/fixtures/release_stage/script/null_enabled_stages.html diff --git a/test/browser/features/fixtures/release_stage/script/b.html b/test/browser/features/fixtures/release_stage/script/release_stage_development.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/b.html rename to test/browser/features/fixtures/release_stage/script/release_stage_development.html diff --git a/test/browser/features/fixtures/release_stage/script/d.html b/test/browser/features/fixtures/release_stage/script/release_stage_enabled.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/d.html rename to test/browser/features/fixtures/release_stage/script/release_stage_enabled.html diff --git a/test/browser/features/fixtures/release_stage/script/c.html b/test/browser/features/fixtures/release_stage/script/release_stage_not_enabled.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/c.html rename to test/browser/features/fixtures/release_stage/script/release_stage_not_enabled.html diff --git a/test/browser/features/fixtures/release_stage/script/a.html b/test/browser/features/fixtures/release_stage/script/release_stage_production.html similarity index 100% rename from test/browser/features/fixtures/release_stage/script/a.html rename to test/browser/features/fixtures/release_stage/script/release_stage_production.html diff --git a/test/browser/features/fixtures/sessions/script/a.html b/test/browser/features/fixtures/sessions/script/default.html similarity index 100% rename from test/browser/features/fixtures/sessions/script/a.html rename to test/browser/features/fixtures/sessions/script/default.html diff --git a/test/browser/features/fixtures/sessions/script/b.html b/test/browser/features/fixtures/sessions/script/sessions_disabled.html similarity index 100% rename from test/browser/features/fixtures/sessions/script/b.html rename to test/browser/features/fixtures/sessions/script/sessions_disabled.html diff --git a/test/browser/features/fixtures/unhandled/script/@dist/g.js b/test/browser/features/fixtures/unhandled/script/@dist/at_filename.js similarity index 100% rename from test/browser/features/fixtures/unhandled/script/@dist/g.js rename to test/browser/features/fixtures/unhandled/script/@dist/at_filename.js diff --git a/test/browser/features/fixtures/unhandled/script/g.html b/test/browser/features/fixtures/unhandled/script/at_filename.html similarity index 92% rename from test/browser/features/fixtures/unhandled/script/g.html rename to test/browser/features/fixtures/unhandled/script/at_filename.html index ec87bbd422..f156166681 100644 --- a/test/browser/features/fixtures/unhandled/script/g.html +++ b/test/browser/features/fixtures/unhandled/script/at_filename.html @@ -14,6 +14,6 @@ - + diff --git a/test/browser/features/fixtures/unhandled/script/f.html b/test/browser/features/fixtures/unhandled/script/bluebird.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/f.html rename to test/browser/features/fixtures/unhandled/script/bluebird.html diff --git a/test/browser/features/fixtures/unhandled/script/e.html b/test/browser/features/fixtures/unhandled/script/malformed_uri.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/e.html rename to test/browser/features/fixtures/unhandled/script/malformed_uri.html diff --git a/test/browser/features/fixtures/unhandled/script/h.html b/test/browser/features/fixtures/unhandled/script/override_unhandled.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/h.html rename to test/browser/features/fixtures/unhandled/script/override_unhandled.html diff --git a/test/browser/features/fixtures/unhandled/script/c.html b/test/browser/features/fixtures/unhandled/script/promise_rejection.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/c.html rename to test/browser/features/fixtures/unhandled/script/promise_rejection.html diff --git a/test/browser/features/fixtures/unhandled/script/a.html b/test/browser/features/fixtures/unhandled/script/syntax_error.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/a.html rename to test/browser/features/fixtures/unhandled/script/syntax_error.html diff --git a/test/browser/features/fixtures/unhandled/script/b.html b/test/browser/features/fixtures/unhandled/script/thrown.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/b.html rename to test/browser/features/fixtures/unhandled/script/thrown.html diff --git a/test/browser/features/fixtures/unhandled/script/d.html b/test/browser/features/fixtures/unhandled/script/undefined_function.html similarity index 100% rename from test/browser/features/fixtures/unhandled/script/d.html rename to test/browser/features/fixtures/unhandled/script/undefined_function.html diff --git a/test/browser/features/fixtures/user_info/script/b.html b/test/browser/features/fixtures/user_info/script/client.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/b.html rename to test/browser/features/fixtures/user_info/script/client.html diff --git a/test/browser/features/fixtures/user_info/script/a.html b/test/browser/features/fixtures/user_info/script/config.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/a.html rename to test/browser/features/fixtures/user_info/script/config.html diff --git a/test/browser/features/fixtures/user_info/script/f.html b/test/browser/features/fixtures/user_info/script/device_id.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/f.html rename to test/browser/features/fixtures/user_info/script/device_id.html diff --git a/test/browser/features/fixtures/user_info/script/e.html b/test/browser/features/fixtures/user_info/script/no_user.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/e.html rename to test/browser/features/fixtures/user_info/script/no_user.html diff --git a/test/browser/features/fixtures/user_info/script/d.html b/test/browser/features/fixtures/user_info/script/on_error.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/d.html rename to test/browser/features/fixtures/user_info/script/on_error.html diff --git a/test/browser/features/fixtures/user_info/script/g.html b/test/browser/features/fixtures/user_info/script/user_id_holds.html similarity index 100% rename from test/browser/features/fixtures/user_info/script/g.html rename to test/browser/features/fixtures/user_info/script/user_id_holds.html diff --git a/test/browser/features/release_stage.feature b/test/browser/features/release_stage.feature index af899eb66b..fba50fd1c2 100644 --- a/test/browser/features/release_stage.feature +++ b/test/browser/features/release_stage.feature @@ -2,35 +2,33 @@ Feature: Configuring releaseStage and enabledReleaseStages Scenario: setting releaseStage=production - When I navigate to the test URL "/release_stage/script/a.html" + When I navigate to the test URL "/release_stage/script/release_stage_production.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "app.releaseStage" equals "production" Scenario: setting releaseStage=development - When I navigate to the test URL "/release_stage/script/b.html" + When I navigate to the test URL "/release_stage/script/release_stage_development.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "app.releaseStage" equals "development" Scenario: setting releaseStage=qa enabledReleaseStages=[production,staging] - When I navigate to the test URL "/release_stage/script/c.html" - And I wait for 2 seconds + When I navigate to the test URL "/release_stage/script/release_stage_not_enabled.html" Then I should receive no errors Scenario: setting releaseStage=staging enabledReleaseStages=[production,staging] - When I navigate to the test URL "/release_stage/script/d.html" + When I navigate to the test URL "/release_stage/script/release_stage_enabled.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "app.releaseStage" equals "staging" Scenario: setting releaseStage=development enabledReleaseStages=null - When I navigate to the test URL "/release_stage/script/e.html" + When I navigate to the test URL "/release_stage/script/null_enabled_stages.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "app.releaseStage" equals "development" Scenario: setting enabledReleaseStages=[] - When I navigate to the test URL "/release_stage/script/f.html" - And I wait for 2 seconds + When I navigate to the test URL "/release_stage/script/empty_enabled_stages.html" Then I should receive no errors diff --git a/test/browser/features/sessions.feature b/test/browser/features/sessions.feature index 550c165608..402f8d2b77 100644 --- a/test/browser/features/sessions.feature +++ b/test/browser/features/sessions.feature @@ -2,11 +2,10 @@ Feature: Session tracking Scenario: tracking sessions by default - When I navigate to the test URL "/sessions/script/a.html" + When I navigate to the test URL "/sessions/script/default.html" Then I wait to receive a session And the session is a valid browser payload for the session tracking API Scenario: autoTrackSessions=false - When I navigate to the test URL "/sessions/script/b.html" - And I wait for 2 seconds + When I navigate to the test URL "/sessions/script/sessions_disabled.html" Then I should receive no sessions diff --git a/test/browser/features/unhandled_errors.feature b/test/browser/features/unhandled_errors.feature index f3ec2b000e..e0db9970aa 100644 --- a/test/browser/features/unhandled_errors.feature +++ b/test/browser/features/unhandled_errors.feature @@ -2,7 +2,7 @@ Feature: Reporting unhandled errors Scenario: syntax errors - When I navigate to the test URL "/unhandled/script/a.html" + When I navigate to the test URL "/unhandled/script/syntax_error.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception matches the "unhandled_syntax" values for the current browser @@ -10,14 +10,14 @@ Scenario: syntax errors And event 0 is unhandled Scenario: thrown errors - When I navigate to the test URL "/unhandled/script/b.html" + When I navigate to the test URL "/unhandled/script/thrown.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception matches the "unhandled_thrown" values for the current browser And event 0 is unhandled Scenario: unhandled promise rejections - When I navigate to the test URL "/unhandled/script/c.html" + When I navigate to the test URL "/unhandled/script/promise_rejection.html" And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API @@ -26,21 +26,21 @@ Scenario: unhandled promise rejections And event 0 is unhandled Scenario: undefined function invocation - When I navigate to the test URL "/unhandled/script/d.html" + When I navigate to the test URL "/unhandled/script/undefined_function.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception matches the "unhandled_undefined_function" values for the current browser And event 0 is unhandled Scenario: decoding malformed URI component - When I navigate to the test URL "/unhandled/script/e.html" + When I navigate to the test URL "/unhandled/script/malformed_uri.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception matches the "unhandled_malformed_uri" values for the current browser And event 0 is unhandled Scenario: detecting unhandled promise rejections with bluebird - When I navigate to the test URL "/unhandled/script/f.html" + When I navigate to the test URL "/unhandled/script/bluebird.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -48,15 +48,15 @@ Scenario: detecting unhandled promise rejections with bluebird And event 0 is unhandled Scenario: parsing stacks correctly with "@" in filename - When I navigate to the test URL "/unhandled/script/g.html" + When I navigate to the test URL "/unhandled/script/at_filename.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "message" ends with "at in filename" - And the "file" of stack frame 0 ends with "unhandled/script/@dist/g.js" + And the "file" of stack frame 0 ends with "unhandled/script/@dist/at_filename.js" And event 0 is unhandled Scenario: overridden handled state in a callback - When I navigate to the test URL "/unhandled/script/h.html" + When I navigate to the test URL "/unhandled/script/override_unhandled.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "message" equals "hello" diff --git a/test/browser/features/user_info.feature b/test/browser/features/user_info.feature index 731f539679..081e8107f8 100644 --- a/test/browser/features/user_info.feature +++ b/test/browser/features/user_info.feature @@ -2,37 +2,37 @@ Feature: Configuring user info Scenario: setting user in config - When I navigate to the test URL "/user_info/script/a.html" + When I navigate to the test URL "/user_info/script/config.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "cjhc01kh00000mcojaw8jqag8" Scenario: setting user on client - When I navigate to the test URL "/user_info/script/b.html" + When I navigate to the test URL "/user_info/script/client.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "cjhc05e8u0000peojhf4vfd68" Scenario: setting user in onError callback - When I navigate to the test URL "/user_info/script/d.html" + When I navigate to the test URL "/user_info/script/on_error.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "cjhc06q3d0000q9ojtam2y3w5" Scenario: not setting user - When I navigate to the test URL "/user_info/script/e.html" + When I navigate to the test URL "/user_info/script/no_user.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" is null Scenario: defaulting to device.id - When I navigate to the test URL "/user_info/script/f.html" + When I navigate to the test URL "/user_info/script/device_id.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" is not null Scenario: default device.id does not override user.id - When I navigate to the test URL "/user_info/script/g.html" + When I navigate to the test URL "/user_info/script/user_id_holds.html" Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "user.id" equals "123" diff --git a/test/node/features/fixtures/docker-compose.yml b/test/node/features/fixtures/docker-compose.yml index f300f08e3f..d921d0a68d 100644 --- a/test/node/features/fixtures/docker-compose.yml +++ b/test/node/features/fixtures/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.6' services: handled: From 4640a6eb0edadec7e794da11bab6c263ba798288 Mon Sep 17 00:00:00 2001 From: Bumpsnag bot <> Date: Wed, 3 Dec 2025 18:25:44 +0000 Subject: [PATCH 28/43] Update bugsnag-android to v6.20.0 [full ci] --- CHANGELOG.md | 1 + packages/react-native/android/build.gradle | 4 ++-- packages/react-native/prepare-android-vendor.config | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0714352b7d..05a2b5736a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Dependencies Update bugsnag-cocoa to [6.34.1](https//github.com/bugsnag/bugsnag-cocoa/releases/tag/6.34.1) [#2606](https://github.com/bugsnag/bugsnag-js/pull/2606) +Update bugsnag-android to [v6.20.0](https//github.com/bugsnag/bugsnag-android/releases/tag/v6.20.0) [#2625](https://github.com/bugsnag/bugsnag-js/pull/2625) ## [8.7.0] - 2025-10-13 diff --git a/packages/react-native/android/build.gradle b/packages/react-native/android/build.gradle index 64ff3fb4f5..beb3d75f1a 100644 --- a/packages/react-native/android/build.gradle +++ b/packages/react-native/android/build.gradle @@ -45,8 +45,8 @@ android { } dependencies { - api "com.bugsnag:bugsnag-android:6.18.0" - api "com.bugsnag:bugsnag-plugin-react-native:6.18.0" + api "com.bugsnag:bugsnag-android:6.20.0" + api "com.bugsnag:bugsnag-plugin-react-native:6.20.0" implementation 'com.facebook.react:react-native:+' testImplementation "junit:junit:4.12" diff --git a/packages/react-native/prepare-android-vendor.config b/packages/react-native/prepare-android-vendor.config index 0c197ce90d..d8e74d5e8f 100644 --- a/packages/react-native/prepare-android-vendor.config +++ b/packages/react-native/prepare-android-vendor.config @@ -1,2 +1,2 @@ version -6.18.0 +6.20.0 From 6e60c405dd7b736836e090988610263939eae5c0 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 4 Dec 2025 17:17:38 +0000 Subject: [PATCH 29/43] Replace "the test should run in this browser" steps with Cucumber tags (#2626) * Helper class for determining browser support for various features * Replace cucumber step with tag to only run when the browser supports the feature * More scenarios converted * Correct logic for version override --------- Co-authored-by: Steve Kirkland --- .../features/auto_detect_errors.feature | 50 ++-- test/browser/features/cause.feature | 56 ++--- .../script/unhandled_rejections_false.html | 7 - .../fixtures/cause/script/constructor.html | 13 +- .../fixtures/cause/script/property.html | 14 +- .../handled/browserify/promise_catch.html | 7 - .../handled/rollup/promise_catch.html | 7 - .../handled/script/promise_catch.html | 7 - .../handled/typescript/promise_catch.html | 7 - .../handled/webpack3/promise_catch.html | 7 - .../handled/webpack4/promise_catch.html | 7 - .../navigation/script/navigation.html | 7 - .../script/fetch_failure.html | 9 +- .../script/fetch_success.html | 9 +- .../script/xhr_failure.html | 9 +- .../script/xhr_success.html | 9 +- .../plugin_angular/angular_12/src/index.html | 9 - .../plugin_angular/angular_17/src/index.html | 9 - .../fixtures/plugin_react/webpack4/index.html | 7 - .../plugin_vue/typescript_vue2/index.html | 16 -- .../plugin_vue/typescript_vue3/index.html | 15 -- .../unhandled/script/promise_rejection.html | 7 - test/browser/features/handled_errors.feature | 200 +++++++-------- test/browser/features/inline_script.feature | 2 +- .../features/network_breadcrumbs.feature | 10 +- test/browser/features/plugin_angular.feature | 22 +- test/browser/features/plugin_react.feature | 16 +- test/browser/features/plugin_vue.feature | 8 +- test/browser/features/steps/browser_steps.rb | 12 - test/browser/features/support/browser.rb | 235 ++++++++++++++++++ test/browser/features/support/env.rb | 2 + test/browser/features/support/requires.rb | 43 ++++ .../browser/features/unhandled_errors.feature | 109 ++++---- 33 files changed, 527 insertions(+), 420 deletions(-) create mode 100644 test/browser/features/support/browser.rb create mode 100644 test/browser/features/support/requires.rb diff --git a/test/browser/features/auto_detect_errors.feature b/test/browser/features/auto_detect_errors.feature index 8c72d7132b..569884dec3 100644 --- a/test/browser/features/auto_detect_errors.feature +++ b/test/browser/features/auto_detect_errors.feature @@ -1,30 +1,30 @@ @auto_detect_errors Feature: Switching off automatic reporting -Scenario: setting autoDetectErrors option to false - When I navigate to the test URL "/auto_detect_errors/script/autodetect_false.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the event "unhandled" is false - And the exception "errorClass" equals "Error" - And the exception "message" equals "manual notify does work" - And the exception "type" equals "browserjs" + Scenario: setting autoDetectErrors option to false + When I navigate to the test URL "/auto_detect_errors/script/autodetect_false.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the event "unhandled" is false + And the exception "errorClass" equals "Error" + And the exception "message" equals "manual notify does work" + And the exception "type" equals "browserjs" -Scenario: setting enabledErrorTypes.unhandledExceptions option to false - When I navigate to the test URL "/auto_detect_errors/script/unhandled_exceptions_false.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the event "unhandled" is false - And the exception "errorClass" equals "Error" - And the exception "message" equals "manual notify does work" - And the exception "type" equals "browserjs" + Scenario: setting enabledErrorTypes.unhandledExceptions option to false + When I navigate to the test URL "/auto_detect_errors/script/unhandled_exceptions_false.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the event "unhandled" is false + And the exception "errorClass" equals "Error" + And the exception "message" equals "manual notify does work" + And the exception "type" equals "browserjs" -Scenario: setting enabledErrorTypes.unhandledRejections option to false - When I navigate to the test URL "/auto_detect_errors/script/unhandled_rejections_false.html" - And the test should run in this browser - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the event "unhandled" is false - And the exception "errorClass" equals "Error" - And the exception "message" equals "manual notify does work" - And the exception "type" equals "browserjs" + @requires_promise + Scenario: setting enabledErrorTypes.unhandledRejections option to false + When I navigate to the test URL "/auto_detect_errors/script/unhandled_rejections_false.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the event "unhandled" is false + And the exception "errorClass" equals "Error" + And the exception "message" equals "manual notify does work" + And the exception "type" equals "browserjs" diff --git a/test/browser/features/cause.feature b/test/browser/features/cause.feature index 206bdbcf12..ebac1881ba 100644 --- a/test/browser/features/cause.feature +++ b/test/browser/features/cause.feature @@ -1,32 +1,32 @@ @skip_ie_8 @skip_ie_9 @skip_ie_10 @skip_ie_11 @skip_firefox_30 @skip_safari_6 Feature: Error.cause -Scenario: Error thrown with an assigned Error cause property - When I navigate to the test URL "/cause/script/property.html" - And the test should run in this browser - And I wait to receive an error - Then the error is a valid browser payload for the error reporting API - And the error payload field "events.0.exceptions" is an array with 2 elements - And the error payload field "events.0.exceptions.0.errorClass" equals "Error" - And the error payload field "events.0.exceptions.0.message" equals "I am the error" - And the error payload field "events.0.exceptions.0.type" equals "browserjs" - And the error payload field "events.0.exceptions.0.stacktrace" is a non-empty array - And the error payload field "events.0.exceptions.1.errorClass" equals "Error" - And the error payload field "events.0.exceptions.1.message" equals "I am the cause" - And the error payload field "events.0.exceptions.1.type" equals "browserjs" - And the error payload field "events.0.exceptions.1.stacktrace" is a non-empty array + @requires_error_cause + Scenario: Error thrown with an assigned Error cause property + When I navigate to the test URL "/cause/script/property.html" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + And the error payload field "events.0.exceptions" is an array with 2 elements + And the error payload field "events.0.exceptions.0.errorClass" equals "Error" + And the error payload field "events.0.exceptions.0.message" equals "I am the error" + And the error payload field "events.0.exceptions.0.type" equals "browserjs" + And the error payload field "events.0.exceptions.0.stacktrace" is a non-empty array + And the error payload field "events.0.exceptions.1.errorClass" equals "Error" + And the error payload field "events.0.exceptions.1.message" equals "I am the cause" + And the error payload field "events.0.exceptions.1.type" equals "browserjs" + And the error payload field "events.0.exceptions.1.stacktrace" is a non-empty array -Scenario: Error thrown with an Error cause in the constructor - When I navigate to the test URL "/cause/script/constructor.html" - And the test should run in this browser - And I wait to receive an error - Then the error is a valid browser payload for the error reporting API - And the error payload field "events.0.exceptions" is an array with 2 elements - And the error payload field "events.0.exceptions.0.errorClass" equals "Error" - And the error payload field "events.0.exceptions.0.message" equals "I am the error" - And the error payload field "events.0.exceptions.0.type" equals "browserjs" - And the error payload field "events.0.exceptions.0.stacktrace" is a non-empty array - And the error payload field "events.0.exceptions.1.errorClass" equals "Error" - And the error payload field "events.0.exceptions.1.message" equals "I am the cause" - And the error payload field "events.0.exceptions.1.type" equals "browserjs" - And the error payload field "events.0.exceptions.1.stacktrace" is a non-empty array + @requires_error_cause + Scenario: Error thrown with an Error cause in the constructor + When I navigate to the test URL "/cause/script/constructor.html" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + And the error payload field "events.0.exceptions" is an array with 2 elements + And the error payload field "events.0.exceptions.0.errorClass" equals "Error" + And the error payload field "events.0.exceptions.0.message" equals "I am the error" + And the error payload field "events.0.exceptions.0.type" equals "browserjs" + And the error payload field "events.0.exceptions.0.stacktrace" is a non-empty array + And the error payload field "events.0.exceptions.1.errorClass" equals "Error" + And the error payload field "events.0.exceptions.1.message" equals "I am the cause" + And the error payload field "events.0.exceptions.1.type" equals "browserjs" + And the error payload field "events.0.exceptions.1.stacktrace" is a non-empty array diff --git a/test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html b/test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html index fbddbf74eb..831da2d031 100644 --- a/test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html +++ b/test/browser/features/fixtures/auto_detect_errors/script/unhandled_rejections_false.html @@ -15,13 +15,6 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/cause/script/constructor.html b/test/browser/features/fixtures/cause/script/constructor.html index bc150f5c68..3f85885acf 100644 --- a/test/browser/features/fixtures/cause/script/constructor.html +++ b/test/browser/features/fixtures/cause/script/constructor.html @@ -17,21 +17,10 @@ -
PENDING
- - \ No newline at end of file + diff --git a/test/browser/features/fixtures/cause/script/property.html b/test/browser/features/fixtures/cause/script/property.html index ef3cee81f2..b646f5c4a2 100644 --- a/test/browser/features/fixtures/cause/script/property.html +++ b/test/browser/features/fixtures/cause/script/property.html @@ -17,18 +17,6 @@ -
PENDING
- - \ No newline at end of file + diff --git a/test/browser/features/fixtures/handled/browserify/promise_catch.html b/test/browser/features/fixtures/handled/browserify/promise_catch.html index 46b12dbe51..bcf9133e75 100644 --- a/test/browser/features/fixtures/handled/browserify/promise_catch.html +++ b/test/browser/features/fixtures/handled/browserify/promise_catch.html @@ -5,12 +5,5 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/handled/rollup/promise_catch.html b/test/browser/features/fixtures/handled/rollup/promise_catch.html index 46b12dbe51..bcf9133e75 100644 --- a/test/browser/features/fixtures/handled/rollup/promise_catch.html +++ b/test/browser/features/fixtures/handled/rollup/promise_catch.html @@ -5,12 +5,5 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/handled/script/promise_catch.html b/test/browser/features/fixtures/handled/script/promise_catch.html index 695b695f47..4525b7e99c 100644 --- a/test/browser/features/fixtures/handled/script/promise_catch.html +++ b/test/browser/features/fixtures/handled/script/promise_catch.html @@ -14,13 +14,6 @@ -
PENDING
- -
PENDING
- diff --git a/test/browser/features/fixtures/handled/webpack3/promise_catch.html b/test/browser/features/fixtures/handled/webpack3/promise_catch.html index 46b12dbe51..bcf9133e75 100644 --- a/test/browser/features/fixtures/handled/webpack3/promise_catch.html +++ b/test/browser/features/fixtures/handled/webpack3/promise_catch.html @@ -5,12 +5,5 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/handled/webpack4/promise_catch.html b/test/browser/features/fixtures/handled/webpack4/promise_catch.html index 46b12dbe51..bcf9133e75 100644 --- a/test/browser/features/fixtures/handled/webpack4/promise_catch.html +++ b/test/browser/features/fixtures/handled/webpack4/promise_catch.html @@ -5,12 +5,5 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/navigation/script/navigation.html b/test/browser/features/fixtures/navigation/script/navigation.html index 292dccc139..6b657e80dd 100644 --- a/test/browser/features/fixtures/navigation/script/navigation.html +++ b/test/browser/features/fixtures/navigation/script/navigation.html @@ -14,13 +14,6 @@ -
PENDING
- -
PENDING
- diff --git a/test/browser/features/fixtures/network_breadcrumbs/script/fetch_success.html b/test/browser/features/fixtures/network_breadcrumbs/script/fetch_success.html index 035e5d17ae..b692fc1067 100644 --- a/test/browser/features/fixtures/network_breadcrumbs/script/fetch_success.html +++ b/test/browser/features/fixtures/network_breadcrumbs/script/fetch_success.html @@ -17,16 +17,9 @@ fetch("fetch_success.html").then(function () { Bugsnag.notify(new Error("This error should have network breadcrumbs attached")) }) - + -
PENDING
- diff --git a/test/browser/features/fixtures/network_breadcrumbs/script/xhr_failure.html b/test/browser/features/fixtures/network_breadcrumbs/script/xhr_failure.html index 85e35d24a8..4f6c8c5687 100644 --- a/test/browser/features/fixtures/network_breadcrumbs/script/xhr_failure.html +++ b/test/browser/features/fixtures/network_breadcrumbs/script/xhr_failure.html @@ -29,13 +29,6 @@ -
PENDING
- - \ No newline at end of file + diff --git a/test/browser/features/fixtures/network_breadcrumbs/script/xhr_success.html b/test/browser/features/fixtures/network_breadcrumbs/script/xhr_success.html index bb7bf4110d..9ae0b666b3 100644 --- a/test/browser/features/fixtures/network_breadcrumbs/script/xhr_success.html +++ b/test/browser/features/fixtures/network_breadcrumbs/script/xhr_success.html @@ -28,13 +28,6 @@ -
PENDING
- - \ No newline at end of file + diff --git a/test/browser/features/fixtures/plugin_angular/angular_12/src/index.html b/test/browser/features/fixtures/plugin_angular/angular_12/src/index.html index a95ef3ea85..d45da215f5 100644 --- a/test/browser/features/fixtures/plugin_angular/angular_12/src/index.html +++ b/test/browser/features/fixtures/plugin_angular/angular_12/src/index.html @@ -8,15 +8,6 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/plugin_angular/angular_17/src/index.html b/test/browser/features/fixtures/plugin_angular/angular_17/src/index.html index 4e93c8e766..769d425f75 100644 --- a/test/browser/features/fixtures/plugin_angular/angular_17/src/index.html +++ b/test/browser/features/fixtures/plugin_angular/angular_17/src/index.html @@ -8,15 +8,6 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/plugin_react/webpack4/index.html b/test/browser/features/fixtures/plugin_react/webpack4/index.html index f1fa4e27fd..6e074cedef 100644 --- a/test/browser/features/fixtures/plugin_react/webpack4/index.html +++ b/test/browser/features/fixtures/plugin_react/webpack4/index.html @@ -4,14 +4,7 @@ -
PENDING
- diff --git a/test/browser/features/fixtures/plugin_vue/typescript_vue2/index.html b/test/browser/features/fixtures/plugin_vue/typescript_vue2/index.html index 620d3d29ab..b2c66e7ab6 100644 --- a/test/browser/features/fixtures/plugin_vue/typescript_vue2/index.html +++ b/test/browser/features/fixtures/plugin_vue/typescript_vue2/index.html @@ -4,26 +4,10 @@ -
PENDING

{{ message }}

{{ errr() }}
- diff --git a/test/browser/features/fixtures/plugin_vue/typescript_vue3/index.html b/test/browser/features/fixtures/plugin_vue/typescript_vue3/index.html index d349e08042..b2c66e7ab6 100644 --- a/test/browser/features/fixtures/plugin_vue/typescript_vue3/index.html +++ b/test/browser/features/fixtures/plugin_vue/typescript_vue3/index.html @@ -4,25 +4,10 @@ -
PENDING

{{ message }}

{{ errr() }}
- diff --git a/test/browser/features/fixtures/unhandled/script/promise_rejection.html b/test/browser/features/fixtures/unhandled/script/promise_rejection.html index c971f51ed4..75188dcd13 100644 --- a/test/browser/features/fixtures/unhandled/script/promise_rejection.html +++ b/test/browser/features/fixtures/unhandled/script/promise_rejection.html @@ -14,13 +14,6 @@ -
PENDING
- diff --git a/test/browser/features/handled_errors.feature b/test/browser/features/handled_errors.feature index 73df1dcd7a..603603b48d 100644 --- a/test/browser/features/handled_errors.feature +++ b/test/browser/features/handled_errors.feature @@ -1,117 +1,117 @@ @handled Feature: Reporting handled errors -Scenario Outline: calling notify() with Error - When I navigate to the test URL "/handled//notify_new_error.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "bad things" - And the exception "type" equals "browserjs" - And the error payload field "events.0.app.type" equals "browser" - And event 0 is handled + Scenario Outline: calling notify() with Error + When I navigate to the test URL "/handled//notify_new_error.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "bad things" + And the exception "type" equals "browserjs" + And the error payload field "events.0.app.type" equals "browser" + And event 0 is handled - Examples: - | type | - | script | - | webpack3 | - | webpack4 | - | browserify | - | rollup | - | typescript | + Examples: + | type | + | script | + | webpack3 | + | webpack4 | + | browserify | + | rollup | + | typescript | -Scenario Outline: calling notify() with Error within try/catch - When I navigate to the test URL "/handled//try_catch_notify.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception matches the "handled" values for the current browser - And the exception "type" equals "browserjs" - And event 0 is handled + Scenario Outline: calling notify() with Error within try/catch + When I navigate to the test URL "/handled//try_catch_notify.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception matches the "handled" values for the current browser + And the exception "type" equals "browserjs" + And event 0 is handled - Examples: - | type | - | script | - | webpack3 | - | webpack4 | - | browserify | - | rollup | - | typescript | + Examples: + | type | + | script | + | webpack3 | + | webpack4 | + | browserify | + | rollup | + | typescript | -Scenario Outline: calling notify() with Error within Promise catch - When I navigate to the test URL "/handled//promise_catch.html" - And the test should run in this browser - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "bad things" - And the exception "type" equals "browserjs" - And event 0 is handled + @requires_promise + Scenario Outline: calling notify() with Error within Promise catch + When I navigate to the test URL "/handled//promise_catch.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "bad things" + And the exception "type" equals "browserjs" + And event 0 is handled - Examples: - | type | - | script | - | webpack3 | - | webpack4 | - | browserify | - | rollup | - | typescript | + Examples: + | type | + | script | + | webpack3 | + | webpack4 | + | browserify | + | rollup | + | typescript | -Scenario: calling notify() with an object, getting a generated a stacktrace - When I navigate to the test URL "/handled/script/notify_object.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Errr" - And the exception "message" equals "make a stacktrace for me" - And the exception "type" equals "browserjs" + Scenario: calling notify() with an object, getting a generated a stacktrace + When I navigate to the test URL "/handled/script/notify_object.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Errr" + And the exception "message" equals "make a stacktrace for me" + And the exception "type" equals "browserjs" - # this ensures the first generated stackframe doesn't come from bugsnag's source - And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" - And event 0 is handled + # this ensures the first generated stackframe doesn't come from bugsnag's source + And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" + And event 0 is handled -Scenario: calling notify() with a string, getting a generated stacktrace - When I navigate to the test URL "/handled/script/notify_string.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "make a stacktrace for me" - And the exception "type" equals "browserjs" + Scenario: calling notify() with a string, getting a generated stacktrace + When I navigate to the test URL "/handled/script/notify_string.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "make a stacktrace for me" + And the exception "type" equals "browserjs" - # this ensures the first generated stackframe doesn't come from bugsnag's source - And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" - And event 0 is handled + # this ensures the first generated stackframe doesn't come from bugsnag's source + And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" + And event 0 is handled -Scenario: calling window.client.notify() with an object, getting a generated stacktrace - When I navigate to the test URL "/handled/script/client_notify_object.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "make a stacktrace for me" - And the exception "type" equals "browserjs" + Scenario: calling window.client.notify() with an object, getting a generated stacktrace + When I navigate to the test URL "/handled/script/client_notify_object.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "make a stacktrace for me" + And the exception "type" equals "browserjs" - # this ensure the stacktrace features all of the nested stackframes - And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" - And the error payload field "events.0.exceptions.0.stacktrace.1.method" equals "b" - And the error payload field "events.0.exceptions.0.stacktrace.2.method" equals "c" - And event 0 is handled + # this ensure the stacktrace features all of the nested stackframes + And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" + And the error payload field "events.0.exceptions.0.stacktrace.1.method" equals "b" + And the error payload field "events.0.exceptions.0.stacktrace.2.method" equals "c" + And event 0 is handled -Scenario: calling window.client.notify() with a string, getting a generated stacktrace - When I navigate to the test URL "/handled/script/client_notify_string.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "make a stacktrace for me" - And the exception "type" equals "browserjs" + Scenario: calling window.client.notify() with a string, getting a generated stacktrace + When I navigate to the test URL "/handled/script/client_notify_string.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "make a stacktrace for me" + And the exception "type" equals "browserjs" - # this ensure the stacktrace features all of the nested stackframes - And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" - And the error payload field "events.0.exceptions.0.stacktrace.1.method" equals "b" - And the error payload field "events.0.exceptions.0.stacktrace.2.method" equals "c" - And event 0 is handled + # this ensure the stacktrace features all of the nested stackframes + And the error payload field "events.0.exceptions.0.stacktrace.0.method" equals "a" + And the error payload field "events.0.exceptions.0.stacktrace.1.method" equals "b" + And the error payload field "events.0.exceptions.0.stacktrace.2.method" equals "c" + And event 0 is handled -Scenario: overridden handled state in a callback - When I navigate to the test URL "/handled/script/callback_override.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "message" ends with "hello" - # The severity is "error" because only the handled-ness has been changed - And event 0 is handled with the severity "error" + Scenario: overridden handled state in a callback + When I navigate to the test URL "/handled/script/callback_override.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "message" ends with "hello" + # The severity is "error" because only the handled-ness has been changed + And event 0 is handled with the severity "error" diff --git a/test/browser/features/inline_script.feature b/test/browser/features/inline_script.feature index ba9351574f..b1562718c6 100644 --- a/test/browser/features/inline_script.feature +++ b/test/browser/features/inline_script.feature @@ -20,9 +20,9 @@ Feature: Inline script detection And event 0 is handled And the event "metaData.script" is null + @requires_history_management Scenario: inline script detected after location change When I navigate to the test URL "/navigation/script/navigation.html" - And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the event "metaData.script.content" matches "throw new Error\('history'\)" diff --git a/test/browser/features/network_breadcrumbs.feature b/test/browser/features/network_breadcrumbs.feature index cbe93df489..3d4f3e5f0a 100644 --- a/test/browser/features/network_breadcrumbs.feature +++ b/test/browser/features/network_breadcrumbs.feature @@ -3,30 +3,32 @@ Feature: Network breadcrumbs Bugsnag error reports should include breadcrumbs for network requests, including those made using fetch, and xml http requests. + @requires_fetch Scenario: A fetch request succeeds When I navigate to the test URL "/network_breadcrumbs/script/fetch_success.html" - And the test should run in this browser And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/network_breadcrumbs/json/fetch_success.json" + @requires_fetch Scenario: A fetch request fails When I navigate to the test URL "/network_breadcrumbs/script/fetch_failure.html" - And the test should run in this browser And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/network_breadcrumbs/json/fetch_failure.json" + @requires_weak_map + @requires_xml_http_request Scenario: An xmlHttpRequest succeeds When I navigate to the test URL "/network_breadcrumbs/script/xhr_success.html" - And the test should run in this browser And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/network_breadcrumbs/json/xhr_success.json" + @requires_weak_map + @requires_xml_http_request Scenario: An xmlHttpRequest fails When I navigate to the test URL "/network_breadcrumbs/script/xhr_failure.html" - And the test should run in this browser And I wait to receive an error Then the error is a valid browser payload for the error reporting API And the event contains a breadcrumb matching the JSON fixture in "features/fixtures/network_breadcrumbs/json/xhr_failure.json" diff --git a/test/browser/features/plugin_angular.feature b/test/browser/features/plugin_angular.feature index 225907bcc5..9c1fcc266b 100644 --- a/test/browser/features/plugin_angular.feature +++ b/test/browser/features/plugin_angular.feature @@ -4,13 +4,15 @@ @skip_safari_10 @skip_before_ios_12 Feature: Angular support -Scenario Outline: basic error handler usage - When I navigate to the test URL "/plugin_angular/angular_/dist/index.html" - And the test should run in this browser - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the error payload field "events.0.device.runtimeVersions.angular" is not null - Examples: - | version | - | 12 | - | 17 | + @requires_promise + @requires_set + @requires_array_from + Scenario Outline: basic error handler usage + When I navigate to the test URL "/plugin_angular/angular_/dist/index.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the error payload field "events.0.device.runtimeVersions.angular" is not null + Examples: + | version | + | 12 | + | 17 | diff --git a/test/browser/features/plugin_react.feature b/test/browser/features/plugin_react.feature index 129f08c629..a6ccb19698 100644 --- a/test/browser/features/plugin_react.feature +++ b/test/browser/features/plugin_react.feature @@ -1,11 +1,11 @@ @plugin_react Feature: React support -Scenario: basic error boundary usage - When I navigate to the test URL "/plugin_react/webpack4/index.html" - And the test should run in this browser - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "borked" - And the event "metaData.react.componentStack" is not null + @requires_set + Scenario: basic error boundary usage + When I navigate to the test URL "/plugin_react/webpack4/index.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "borked" + And the event "metaData.react.componentStack" is not null diff --git a/test/browser/features/plugin_vue.feature b/test/browser/features/plugin_vue.feature index 3a3e3d79ac..7b8034b640 100644 --- a/test/browser/features/plugin_vue.feature +++ b/test/browser/features/plugin_vue.feature @@ -11,9 +11,11 @@ Feature: Vue support And the exception "message" equals "borked" And the event "metaData.vue.errorInfo" is not null + @requires_let + @requires_proxy + @skip_safari_10 Scenario: vue3 + typescript usage When I navigate to the test URL "/plugin_vue/typescript_vue3/index.html" - And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" @@ -21,9 +23,11 @@ Feature: Vue support And the event "metaData.vue.errorInfo" equals "render function" And the event "metaData.vue.component" equals "App" + @requires_let + @requires_proxy + @skip_safari_10 Scenario: vue2 + typescript usage When I navigate to the test URL "/plugin_vue/typescript_vue2/index.html" - And the test should run in this browser Then I wait to receive an error And the error is a valid browser payload for the error reporting API And the exception "errorClass" equals "Error" diff --git a/test/browser/features/steps/browser_steps.rb b/test/browser/features/steps/browser_steps.rb index ed0ae21324..81d017ed69 100644 --- a/test/browser/features/steps/browser_steps.rb +++ b/test/browser/features/steps/browser_steps.rb @@ -20,18 +20,6 @@ end end -When('the test should run in this browser') do - wait = Selenium::WebDriver::Wait.new(timeout: 10) - wait.until { - Maze.driver.find_element(id: 'bugsnag-test-should-run') && - Maze.driver.find_element(id: 'bugsnag-test-should-run').text != 'PENDING' - } - if Maze.driver.find_element(id: 'bugsnag-test-should-run').text == 'NO' - Maze::Server.reset! - skip_this_scenario - end -end - When('I let the test page run for up to {int} seconds') do |n| wait = Selenium::WebDriver::Wait.new(timeout: n) wait.until { diff --git a/test/browser/features/support/browser.rb b/test/browser/features/support/browser.rb new file mode 100644 index 0000000000..6a344e7c03 --- /dev/null +++ b/test/browser/features/support/browser.rb @@ -0,0 +1,235 @@ +require 'yaml' + +# Provides information on browser support for features needed in the e2e tests. +# Source: caniuse.com +class Browser + attr_reader :name + + def initialize(browser_spec) + # e.g. "chrome_61", "edge_latest", "chrome" + @name, version = browser_spec.split("_") + + # Assume Android runs the latest Chrome and iOS/Safari versions match. + if @name == "android" + @name = "chrome" + @version = Float::INFINITY + else + @name = "safari" if @name == "ios" + + # Assume we're running the latest version if there is no version present. + @version = if version.nil? || version == "latest" + Float::INFINITY + else + Integer(version) + end + end + end + + # https://caniuse.com/wf-array-from + def supports_array_from? + case @name + when "chrome" + @version >= 45 + when "edge" + @version >= 12 + when "firefox" + @version >= 38 + when "safari" + @version >= 10 + when "ie" + false # Determined manually using a test page + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/mdn-javascript_builtins_error_cause + def supports_error_cause? + case @name + when "chrome" + @version >= 93 + when "edge" + @version >= 93 + when "firefox" + @version >= 91 + when "safari" + @version >= 15 + when "ie" + false + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/fetch + def supports_fetch? + case @name + when "chrome" + @version >= 42 + when "edge" + @version >= 14 + when "firefox" + @version >= 39 + when "safari" + @version >= 10 # 10.1 + when "ie" + false + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/mdn-api_history + def supports_history_management? + case @name + when "chrome" + @version >= 4 + when "edge" + @version >= 12 + when "firefox" + @version >= 2 + when "safari" + @version >= 3 # 3.1 + when "ie" + @version >= 10 + else + # Assume support for unknown browsers + true + end + end + + def supports_let? + case @name + when "chrome" + @version >= 49 + when "edge" + @version >= 12 + when "firefox" + @version >= 44 + when "safari" + @version >= 11 + when "ie" + @version >= 11 # Partial - let variables are not bound separately to each iteration of for loops + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/promises + def supports_promise? + case @name + when "chrome" + @version >= 33 + when "edge" + @version >= 12 + when "firefox" + @version >= 29 + when "safari" + @version >= 7 # 7.1 + when "ie" + false + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/proxy + def supports_proxy? + case @name + when "chrome" + @version >= 49 + when "edge" + @version >= 12 + when "firefox" + @version >= 18 + when "safari" + @version >= 10 + when "ie" + false + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/mdn-javascript_builtins_set + def supports_set? + case @name + when "chrome" + @version >= 38 + when "edge" + @version >= 12 + when "firefox" + @version >= 13 + when "safari" + @version >= 8 + when "ie" + @version >= 11 + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/mdn-api_window_unhandledrejection_event + def supports_unhandled_rejection? + case @name + when "chrome" + @version >= 49 + when "edge" + @version >= 79 + when "firefox" + @version >= 69 + when "safari" + @version >= 11 + when "ie" + false + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/weakmap + def supports_weak_map? + case @name + when "chrome" + @version >= 51 + when "edge" + @version >= 15 + when "firefox" + @version >= 54 + when "safari" + @version >= 10 + when "ie" + @version >= 11 # Partial - Notable partial support in IE11 includes (at least some) support for const, let, block-level function declaration, typed arrays, Map, Set and WeakMap. + else + # Assume support for unknown browsers + true + end + end + + # https://caniuse.com/wf-xhr + def supports_xml_http_request? + case @name + when "chrome" + @version >= 4 + when "edge" + @version >= 12 + when "firefox" + @version >= 2 + when "safari" + @version >= 3 # 3.1 + when "ie" + @version >= 11 # Determined manually using a test page + else + # Assume support for unknown browsers + true + end + end +end diff --git a/test/browser/features/support/env.rb b/test/browser/features/support/env.rb index 1ec92bc8d2..b206f7d222 100644 --- a/test/browser/features/support/env.rb +++ b/test/browser/features/support/env.rb @@ -47,9 +47,11 @@ def get_error_message id skip_this_scenario if Maze.config.browser == browser end end + BeforeAll do Maze.config.receive_no_requests_wait = 15 Maze.config.enforce_bugsnag_integrity = false + $browser = Browser.new(Maze.config.browser) end at_exit do diff --git a/test/browser/features/support/requires.rb b/test/browser/features/support/requires.rb new file mode 100644 index 0000000000..23209f2c33 --- /dev/null +++ b/test/browser/features/support/requires.rb @@ -0,0 +1,43 @@ +Before('@requires_array_from') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support Array.from") unless $browser.supports_array_from? +end + +Before('@requires_error_cause') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support error.cause") unless $browser.supports_error_cause? +end + +Before('@requires_fetch') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support fetch()") unless $browser.supports_fetch? +end + +Before('@requires_history_management') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support history management") unless $browser.supports_history_management? +end + +Before('@requires_let') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support let") unless $browser.supports_let? +end + +Before('@requires_promise') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support Promises") unless $browser.supports_promise? +end + +Before('@requires_proxy') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support Proxy") unless $browser.supports_proxy? +end + +Before('@requires_set') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support Set") unless $browser.supports_set? +end + +Before('@requires_unhandled_rejection') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support onunhandledrejection") unless $browser.supports_unhandled_rejection? +end + +Before('@requires_weak_map') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support WeakMap") unless $browser.supports_weak_map? +end + +Before('@requires_xml_http_request') do |_scenario| + skip_this_scenario("Skipping scenario on #{$browser.name} as it does not support XMLHttpRequest") unless $browser.supports_xml_http_request? +end diff --git a/test/browser/features/unhandled_errors.feature b/test/browser/features/unhandled_errors.feature index e0db9970aa..aabc1a6dab 100644 --- a/test/browser/features/unhandled_errors.feature +++ b/test/browser/features/unhandled_errors.feature @@ -1,64 +1,65 @@ @unhandled Feature: Reporting unhandled errors -Scenario: syntax errors - When I navigate to the test URL "/unhandled/script/syntax_error.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception matches the "unhandled_syntax" values for the current browser - And the error payload field "events.0.app.type" equals "browser" - And event 0 is unhandled + Scenario: syntax errors + When I navigate to the test URL "/unhandled/script/syntax_error.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception matches the "unhandled_syntax" values for the current browser + And the error payload field "events.0.app.type" equals "browser" + And event 0 is unhandled -Scenario: thrown errors - When I navigate to the test URL "/unhandled/script/thrown.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception matches the "unhandled_thrown" values for the current browser - And event 0 is unhandled + Scenario: thrown errors + When I navigate to the test URL "/unhandled/script/thrown.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception matches the "unhandled_thrown" values for the current browser + And event 0 is unhandled -Scenario: unhandled promise rejections - When I navigate to the test URL "/unhandled/script/promise_rejection.html" - And the test should run in this browser - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "broken promises" - And event 0 is unhandled + @requires_promise + @requires_unhandled_rejection + Scenario: unhandled promise rejections + When I navigate to the test URL "/unhandled/script/promise_rejection.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "broken promises" + And event 0 is unhandled -Scenario: undefined function invocation - When I navigate to the test URL "/unhandled/script/undefined_function.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception matches the "unhandled_undefined_function" values for the current browser - And event 0 is unhandled + Scenario: undefined function invocation + When I navigate to the test URL "/unhandled/script/undefined_function.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception matches the "unhandled_undefined_function" values for the current browser + And event 0 is unhandled -Scenario: decoding malformed URI component - When I navigate to the test URL "/unhandled/script/malformed_uri.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception matches the "unhandled_malformed_uri" values for the current browser - And event 0 is unhandled + Scenario: decoding malformed URI component + When I navigate to the test URL "/unhandled/script/malformed_uri.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception matches the "unhandled_malformed_uri" values for the current browser + And event 0 is unhandled -Scenario: detecting unhandled promise rejections with bluebird - When I navigate to the test URL "/unhandled/script/bluebird.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "errorClass" equals "Error" - And the exception "message" equals "broken bluebird promises" - And event 0 is unhandled + Scenario: detecting unhandled promise rejections with bluebird + When I navigate to the test URL "/unhandled/script/bluebird.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "errorClass" equals "Error" + And the exception "message" equals "broken bluebird promises" + And event 0 is unhandled -Scenario: parsing stacks correctly with "@" in filename - When I navigate to the test URL "/unhandled/script/at_filename.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "message" ends with "at in filename" - And the "file" of stack frame 0 ends with "unhandled/script/@dist/at_filename.js" - And event 0 is unhandled + Scenario: parsing stacks correctly with "@" in filename + When I navigate to the test URL "/unhandled/script/at_filename.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "message" ends with "at in filename" + And the "file" of stack frame 0 ends with "unhandled/script/@dist/at_filename.js" + And event 0 is unhandled -Scenario: overridden handled state in a callback - When I navigate to the test URL "/unhandled/script/override_unhandled.html" - Then I wait to receive an error - And the error is a valid browser payload for the error reporting API - And the exception "message" equals "hello" - # The severity is "warning" because only the handled-ness has been changed - And event 0 is unhandled with the severity "warning" + Scenario: overridden handled state in a callback + When I navigate to the test URL "/unhandled/script/override_unhandled.html" + Then I wait to receive an error + And the error is a valid browser payload for the error reporting API + And the exception "message" equals "hello" + # The severity is "warning" because only the handled-ness has been changed + And event 0 is unhandled with the severity "warning" From b7d4647e340f1843b257012be121bdac3f75435e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 03:14:33 +0000 Subject: [PATCH 30/43] build(deps): bump github/codeql-action from 4.31.5 to 4.31.7 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.5 to 4.31.7. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/fdbfb4d2750291e159f0156def62b853c2798ca2...cf1bb45a277cb3c205638b2cd5c984db1c46a412) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4adf691ead..34d0b9f99f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 + uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 + uses: github/codeql-action/autobuild@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -74,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 + uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8d9bbeaaac..5cd4c6a400 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 + uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7 with: sarif_file: results.sarif From db228570dd26ad660f9c10e3b3e604b154d02cb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:55:28 +0000 Subject: [PATCH 31/43] Merge pull request #2614 from bugsnag/dependabot/github_actions/actions/checkout-6.0.0 build(deps): bump actions/checkout from 5.0.0 to 6.0.0 --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/pr-diff.yml | 4 ++-- .github/workflows/scorecard.yml | 4 ++-- .github/workflows/test-electron.yml | 2 +- .github/workflows/update-dependencies.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index d7794de4f0..0c044f773b 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -21,7 +21,7 @@ jobs: - run: sam --version - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install Ruby uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4adf691ead..4cca8f30cd 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/pr-diff.yml b/.github/workflows/pr-diff.yml index 6f1b0b607d..dd21b723ae 100644 --- a/.github/workflows/pr-diff.yml +++ b/.github/workflows/pr-diff.yml @@ -14,7 +14,7 @@ jobs: node-version: 18.x - name: Checkout base branch - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ github.base_ref }} @@ -29,7 +29,7 @@ jobs: cat packages/browser/dist/bugsnag.min.js | gzip | wc -c > .diff/size-before-gzipped - name: Checkout PR branch - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: clean: false diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8d9bbeaaac..4094e9bf52 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -76,5 +76,5 @@ jobs: name: "Checksum validation of Gradle Wrappers" runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: gradle/actions/wrapper-validation@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 diff --git a/.github/workflows/test-electron.yml b/.github/workflows/test-electron.yml index 199e2d0ec3..e95fe5af8d 100644 --- a/.github/workflows/test-electron.yml +++ b/.github/workflows/test-electron.yml @@ -14,7 +14,7 @@ jobs: os: [ ubuntu-latest ] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index 8f5b53019a..82b8d9e2b2 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -28,7 +28,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REVIEWER: gingerbenw steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: next From 6ec4d6dd73aedee57e831e2021a5c5e97b31dce8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:56:33 +0000 Subject: [PATCH 32/43] build(deps): bump ruby/setup-ruby from 1.266.0 to 1.269.0 Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.266.0 to 1.269.0. - [Release notes](https://github.com/ruby/setup-ruby/releases) - [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb) - [Commits](https://github.com/ruby/setup-ruby/compare/4ff6f3611a42bc75eee1e5138240eb1613f48c8f...d697be2f83c6234b20877c3b5eac7a7f342f0d0c) --- updated-dependencies: - dependency-name: ruby/setup-ruby dependency-version: 1.269.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/update-dependencies.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index 0c044f773b..bf2b45a32f 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install Ruby - uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0 + uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1.269.0 with: ruby-version: '3.1' diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index 82b8d9e2b2..bc833af7f8 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -40,7 +40,7 @@ jobs: - run: git submodule update --init --recursive - name: Install ruby - uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0 + uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1.269.0 with: ruby-version: 2.7 From 9a71939f7f770481644eb206ae30885c86033dc1 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Mon, 8 Dec 2025 09:58:07 +0000 Subject: [PATCH 33/43] Reset server request lists on navigation failure (#2629) Co-authored-by: Steve Kirkland --- test/browser/features/support/env.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/browser/features/support/env.rb b/test/browser/features/support/env.rb index b206f7d222..23682e643c 100644 --- a/test/browser/features/support/env.rb +++ b/test/browser/features/support/env.rb @@ -51,6 +51,7 @@ def get_error_message id BeforeAll do Maze.config.receive_no_requests_wait = 15 Maze.config.enforce_bugsnag_integrity = false + Maze.config.reset_on_navigation_failure = true $browser = Browser.new(Maze.config.browser) end From ea91f81dbcd8460d1337a9ed14f9eb11855b9925 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Tue, 9 Dec 2025 10:26:47 +0000 Subject: [PATCH 34/43] Remove skips for browser versions no longer tested against (#2628) Co-authored-by: Steve Kirkland --- test/browser/features/cause.feature | 2 +- test/browser/features/delivery.feature | 1 - test/browser/features/network_breadcrumbs.feature | 2 +- test/browser/features/plugin_angular.feature | 2 +- test/browser/features/plugin_vue.feature | 2 -- test/browser/features/web_worker.feature | 11 ++++------- test/node/features/koa-1x.feature | 1 - test/node/features/koa-1x_disabled.feature | 1 - test/node/features/koa.feature | 1 - test/node/features/koa_disabled.feature | 1 - test/node/features/webpack.feature | 1 - 11 files changed, 7 insertions(+), 18 deletions(-) diff --git a/test/browser/features/cause.feature b/test/browser/features/cause.feature index ebac1881ba..74bdae3de2 100644 --- a/test/browser/features/cause.feature +++ b/test/browser/features/cause.feature @@ -1,4 +1,4 @@ -@skip_ie_8 @skip_ie_9 @skip_ie_10 @skip_ie_11 @skip_firefox_30 @skip_safari_6 +@skip_ie_11 Feature: Error.cause @requires_error_cause diff --git a/test/browser/features/delivery.feature b/test/browser/features/delivery.feature index 26e53729d6..55c9a6b4be 100644 --- a/test/browser/features/delivery.feature +++ b/test/browser/features/delivery.feature @@ -1,6 +1,5 @@ Feature: Delivery of errors - @skip_ie_10 Scenario: Delivery is attempted oversized payloads When I set the HTTP status code for the next "POST" request to 400 And I navigate to the test URL "/delivery/script/oversized.html" diff --git a/test/browser/features/network_breadcrumbs.feature b/test/browser/features/network_breadcrumbs.feature index 3d4f3e5f0a..3113862cf2 100644 --- a/test/browser/features/network_breadcrumbs.feature +++ b/test/browser/features/network_breadcrumbs.feature @@ -1,4 +1,4 @@ -@network_breadcrumbs @skip_ie_8 @skip_ie_9 +@network_breadcrumbs Feature: Network breadcrumbs Bugsnag error reports should include breadcrumbs for network requests, including those made using fetch, and xml http requests. diff --git a/test/browser/features/plugin_angular.feature b/test/browser/features/plugin_angular.feature index 9c1fcc266b..d978da871d 100644 --- a/test/browser/features/plugin_angular.feature +++ b/test/browser/features/plugin_angular.feature @@ -1,7 +1,7 @@ @plugin_angular # Skipped on older Safari versions not supported by Angular 10 - Angular renders the fixture component twice, causing duplicate events to be reported -@skip_safari_10 @skip_before_ios_12 +@skip_safari_10 Feature: Angular support @requires_promise diff --git a/test/browser/features/plugin_vue.feature b/test/browser/features/plugin_vue.feature index 7b8034b640..484af19c9c 100644 --- a/test/browser/features/plugin_vue.feature +++ b/test/browser/features/plugin_vue.feature @@ -1,8 +1,6 @@ @plugin_vue Feature: Vue support - # Skipped on IE <=10, see https://github.com/vuejs/vue/issues/12837 - @skip_ie_8 @skip_ie_9 @skip_ie_10 Scenario: basic error handler usage When I navigate to the test URL "/plugin_vue/webpack4/index.html" Then I wait to receive an error diff --git a/test/browser/features/web_worker.feature b/test/browser/features/web_worker.feature index 8d59e23aec..e8248e0a17 100644 --- a/test/browser/features/web_worker.feature +++ b/test/browser/features/web_worker.feature @@ -1,8 +1,5 @@ -# browsers that do not support web workers -@skip_ie_8 @skip_ie_9 - -# browsers that currently throw errors in our test fixtures -@skip_ie_10 @skip_ie_11 @skip_chrome_43 @skip_edge_17 @skip_safari_10 @skip_before_ios_12 +# browsers that currently throw errors in our test fixtures +@skip_ie_11 @skip_chrome_43 @skip_edge_17 @skip_safari_10 Feature: worker notifier @@ -17,7 +14,7 @@ Feature: worker notifier Scenario: config.autoDetectErrors defaults to false Given I navigate to the test URL "/web_worker/worker_auto_detect_errors/default" Then I should receive no errors - + Scenario: setting config.autoDetectErrors option to true Given I navigate to the test URL "/web_worker/worker_auto_detect_errors/enabled" And I wait to receive an error @@ -48,7 +45,7 @@ Feature: worker notifier Then the session is a valid browser payload for the session tracking API # Not supported on Safari https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Integrity-Policy#browser_compatibility - @skip_safari_16 @skip_ios_12 + @skip_safari_16 Scenario: Integrity headers are set when setPayloadChecksums is true When I navigate to the test URL "/web_worker/integrity" And I wait to receive an error diff --git a/test/node/features/koa-1x.feature b/test/node/features/koa-1x.feature index 3eabb36224..376734eb1d 100644 --- a/test/node/features/koa-1x.feature +++ b/test/node/features/koa-1x.feature @@ -1,4 +1,3 @@ -@skip_before_node_8 Feature: @bugsnag/plugin-koa (koa v1.x support) Background: diff --git a/test/node/features/koa-1x_disabled.feature b/test/node/features/koa-1x_disabled.feature index 7c12f8a866..3dc6304c48 100644 --- a/test/node/features/koa-1x_disabled.feature +++ b/test/node/features/koa-1x_disabled.feature @@ -1,4 +1,3 @@ -@skip_before_node_8 Feature: @bugsnag/plugin-koa (koa v1.x support) autoDetectErrors=false Background: diff --git a/test/node/features/koa.feature b/test/node/features/koa.feature index edada08d03..cb974eabfa 100644 --- a/test/node/features/koa.feature +++ b/test/node/features/koa.feature @@ -1,4 +1,3 @@ -@skip_before_node_8 Feature: @bugsnag/plugin-koa Background: diff --git a/test/node/features/koa_disabled.feature b/test/node/features/koa_disabled.feature index 98d8e2ee8c..3d1aa969c5 100644 --- a/test/node/features/koa_disabled.feature +++ b/test/node/features/koa_disabled.feature @@ -1,4 +1,3 @@ -@skip_before_node_8 Feature: @bugsnag/plugin-koa autoDetectErrors=false Background: diff --git a/test/node/features/webpack.feature b/test/node/features/webpack.feature index 1180998c50..d57a9ba3cb 100644 --- a/test/node/features/webpack.feature +++ b/test/node/features/webpack.feature @@ -1,4 +1,3 @@ -@skip_before_node_6 @skip_node_18 Feature: Webpack bundling support for node apps From 448d11f92487804717b72e7a55fa9dea49aba0ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 17:31:33 +0000 Subject: [PATCH 35/43] Merge pull request #2631 from bugsnag/dependabot/github_actions/actions/setup-node-6.1.0 build(deps): bump actions/setup-node from 6.0.0 to 6.1.0 --- .github/workflows/aws-lambda.yml | 2 +- .github/workflows/pr-diff.yml | 2 +- .github/workflows/test-electron.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aws-lambda.yml b/.github/workflows/aws-lambda.yml index bf2b45a32f..e6bc3bcde7 100644 --- a/.github/workflows/aws-lambda.yml +++ b/.github/workflows/aws-lambda.yml @@ -29,7 +29,7 @@ jobs: ruby-version: '3.1' - name: Install Node - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: 18 diff --git a/.github/workflows/pr-diff.yml b/.github/workflows/pr-diff.yml index dd21b723ae..f400672148 100644 --- a/.github/workflows/pr-diff.yml +++ b/.github/workflows/pr-diff.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup node - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: 18.x diff --git a/.github/workflows/test-electron.yml b/.github/workflows/test-electron.yml index e95fe5af8d..2f80d22020 100644 --- a/.github/workflows/test-electron.yml +++ b/.github/workflows/test-electron.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: ${{ matrix.node-version }} - name: (Act) install build tools and dependencies From 731ccb746a93aa9ffec6796d5ea77131e3609fc2 Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:41:44 +0000 Subject: [PATCH 36/43] fix(plugin-server-session): delay initialization until first use (#2642) * fix(plugin-server-session): delay session tracker initialization until first use * docs(plugin-server-session): add changelog entry --- CHANGELOG.md | 4 ++++ packages/plugin-server-session/session.js | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05a2b5736a..be0a2fee18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +(plugin-server-session) Delay session tracker initialization until first use [#2642](https://github.com/bugsnag/bugsnag-js/pull/2642) + ### Dependencies Update bugsnag-cocoa to [6.34.1](https//github.com/bugsnag/bugsnag-cocoa/releases/tag/6.34.1) [#2606](https://github.com/bugsnag/bugsnag-js/pull/2606) diff --git a/packages/plugin-server-session/session.js b/packages/plugin-server-session/session.js index 7932aee8db..01de8cd2e3 100644 --- a/packages/plugin-server-session/session.js +++ b/packages/plugin-server-session/session.js @@ -5,11 +5,17 @@ const runSyncCallbacks = require('@bugsnag/core/lib/sync-callback-runner') module.exports = { load: (client) => { - const sessionTracker = new SessionTracker(client._config.sessionSummaryInterval) - sessionTracker.on('summary', sendSessionSummary(client)) - sessionTracker.start() + let sessionTracker = null + client._sessionDelegate = { startSession: (client, session) => { + // Lazy initialization: only create and start the tracker on first use + if (!sessionTracker) { + sessionTracker = new SessionTracker(client._config.sessionSummaryInterval) + sessionTracker.on('summary', sendSessionSummary(client)) + sessionTracker.start() + } + client._session = session client._pausedSession = null sessionTracker.track(client._session) From d58e520f5a472aaa7087f52132ac5c16075cd1bb Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:41:40 +0000 Subject: [PATCH 37/43] feat(plugin-cloudflare-workers): add basic cloudflare workers plugin (#2643) * feat(plugin-cloudflare-workers): add basic cloudflare workers plugin * refactor(plugin-cloudflare-workers): rework request metadata handling * refactor(plugin-cloudflare-workers): rework type declarations * test(plugin-cloudflare-workers): rework unit tests * docs(plugin-cloudflare-workers): add changelog entry # Conflicts: # CHANGELOG.md --- CHANGELOG.md | 4 + jest.config.js | 6 +- package-lock.json | 44 ++- .../plugin-cloudflare-workers/LICENSE.txt | 19 ++ packages/plugin-cloudflare-workers/README.md | 7 + .../plugin-cloudflare-workers/package.json | 32 ++ .../plugin-cloudflare-workers/src/index.js | 116 +++++++ .../test/index.test.ts | 316 ++++++++++++++++++ .../plugin-cloudflare-workers/test/setup.ts | 1 + .../bugsnag-plugin-cloudflare-workers.d.ts | 16 + 10 files changed, 558 insertions(+), 3 deletions(-) create mode 100644 packages/plugin-cloudflare-workers/LICENSE.txt create mode 100644 packages/plugin-cloudflare-workers/README.md create mode 100644 packages/plugin-cloudflare-workers/package.json create mode 100644 packages/plugin-cloudflare-workers/src/index.js create mode 100644 packages/plugin-cloudflare-workers/test/index.test.ts create mode 100644 packages/plugin-cloudflare-workers/test/setup.ts create mode 100644 packages/plugin-cloudflare-workers/types/bugsnag-plugin-cloudflare-workers.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index be0a2fee18..57487c61ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +(plugin-cloudflare-workers): Add initial support for Cloudflare Workers [#2643](https://github.com/bugsnag/bugsnag-js/pull/2643) + ### Fixed (plugin-server-session) Delay session tracker initialization until first use [#2642](https://github.com/bugsnag/bugsnag-js/pull/2642) diff --git a/jest.config.js b/jest.config.js index 19f82304ad..dcb9bbd721 100644 --- a/jest.config.js +++ b/jest.config.js @@ -131,6 +131,10 @@ module.exports = { clearMocks: true, modulePathIgnorePatterns: ['.verdaccio', 'fixtures'] }), - project('react native cli', ['react-native-cli'], { testEnvironment: 'node' }) + project('react native cli', ['react-native-cli'], { testEnvironment: 'node' }), + project('cloudflare-workers', ['plugin-cloudflare-workers'], { + testEnvironment: 'node', + setupFilesAfterEnv: ['/packages/plugin-cloudflare-workers/test/setup.ts'] + }) ] } diff --git a/package-lock.json b/package-lock.json index f4dcf470d9..6328a177cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2716,6 +2716,10 @@ "resolved": "packages/plugin-client-ip", "link": true }, + "node_modules/@bugsnag/plugin-cloudflare-workers": { + "resolved": "packages/plugin-cloudflare-workers", + "link": true + }, "node_modules/@bugsnag/plugin-console-breadcrumbs": { "resolved": "packages/plugin-console-breadcrumbs", "link": true @@ -2941,6 +2945,13 @@ "resolved": "packages/web-worker", "link": true }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20251213.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251213.0.tgz", + "integrity": "sha512-PJAGdKfU7hs39C2YOFNLTdrfdqG6rbaVj5UuI306zS+TPokiskRLEgUXKqS6avN9Uu9Nyuf2a0hqoumLQCnJlQ==", + "dev": true, + "license": "MIT OR Apache-2.0" + }, "node_modules/@cnakazawa/watch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", @@ -52977,6 +52988,22 @@ "@bugsnag/core": "^8.0.0" } }, + "packages/plugin-cloudflare-workers": { + "name": "@bugsnag/plugin-cloudflare-workers", + "version": "8.6.0", + "license": "MIT", + "dependencies": { + "@bugsnag/in-flight": "^8.6.0", + "@bugsnag/plugin-browser-session": "^8.6.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.6.0", + "@cloudflare/workers-types": "^4.20251213.0" + }, + "peerDependencies": { + "@bugsnag/core": "^8.0.0" + } + }, "packages/plugin-console-breadcrumbs": { "name": "@bugsnag/plugin-console-breadcrumbs", "version": "8.6.0", @@ -53002,7 +53029,6 @@ "packages/plugin-electron-app": { "name": "@bugsnag/plugin-electron-app", "version": "8.7.0", - "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0" @@ -53044,7 +53070,6 @@ "packages/plugin-electron-client-state-persistence": { "name": "@bugsnag/plugin-electron-client-state-persistence", "version": "8.6.0", - "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0" @@ -59724,6 +59749,15 @@ "@bugsnag/core": "^8.6.0" } }, + "@bugsnag/plugin-cloudflare-workers": { + "version": "file:packages/plugin-cloudflare-workers", + "requires": { + "@bugsnag/core": "^8.6.0", + "@bugsnag/in-flight": "^8.6.0", + "@bugsnag/plugin-browser-session": "^8.6.0", + "@cloudflare/workers-types": "^4.20251213.0" + } + }, "@bugsnag/plugin-console-breadcrumbs": { "version": "file:packages/plugin-console-breadcrumbs", "requires": { @@ -60260,6 +60294,12 @@ } } }, + "@cloudflare/workers-types": { + "version": "4.20251213.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251213.0.tgz", + "integrity": "sha512-PJAGdKfU7hs39C2YOFNLTdrfdqG6rbaVj5UuI306zS+TPokiskRLEgUXKqS6avN9Uu9Nyuf2a0hqoumLQCnJlQ==", + "dev": true + }, "@cnakazawa/watch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", diff --git a/packages/plugin-cloudflare-workers/LICENSE.txt b/packages/plugin-cloudflare-workers/LICENSE.txt new file mode 100644 index 0000000000..ddc0631e24 --- /dev/null +++ b/packages/plugin-cloudflare-workers/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) Bugsnag, https://www.bugsnag.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/plugin-cloudflare-workers/README.md b/packages/plugin-cloudflare-workers/README.md new file mode 100644 index 0000000000..730a681641 --- /dev/null +++ b/packages/plugin-cloudflare-workers/README.md @@ -0,0 +1,7 @@ +# @bugsnag/plugin-cloudflare-workers + +A [@bugsnag/js](https://github.com/bugsnag/bugsnag-js) plugin for capturing errors in Cloudflare Workers. + +## License + +This package is free software released under the MIT License. See [LICENSE.txt](./LICENSE.txt) for details. diff --git a/packages/plugin-cloudflare-workers/package.json b/packages/plugin-cloudflare-workers/package.json new file mode 100644 index 0000000000..aab6da2065 --- /dev/null +++ b/packages/plugin-cloudflare-workers/package.json @@ -0,0 +1,32 @@ +{ + "name": "@bugsnag/plugin-cloudflare-workers", + "version": "8.6.0", + "main": "src/index.js", + "types": "types/bugsnag-plugin-cloudflare-workers.d.ts", + "description": "Cloudflare Workers support for @bugsnag/js", + "homepage": "https://www.bugsnag.com/", + "repository": { + "type": "git", + "url": "git@github.com:bugsnag/bugsnag-js.git" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "src", + "types" + ], + "author": "Bugsnag", + "license": "MIT", + "dependencies": { + "@bugsnag/in-flight": "^8.6.0", + "@bugsnag/plugin-browser-session": "^8.6.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.6.0", + "@cloudflare/workers-types": "^4.20251213.0" + }, + "peerDependencies": { + "@bugsnag/core": "^8.0.0" + } +} diff --git a/packages/plugin-cloudflare-workers/src/index.js b/packages/plugin-cloudflare-workers/src/index.js new file mode 100644 index 0000000000..5cb02702e3 --- /dev/null +++ b/packages/plugin-cloudflare-workers/src/index.js @@ -0,0 +1,116 @@ +const bugsnagInFlight = require('@bugsnag/in-flight') +const BugsnagPluginBrowserSession = require('@bugsnag/plugin-browser-session') + +const SERVER_PLUGIN_NAMES = ['express', 'koa', 'restify', 'hono'] +const isServerPluginLoaded = client => SERVER_PLUGIN_NAMES.some(name => client.getPlugin(name)) + +const extractRequestInfo = (request) => { + if (!request) return {} + + const url = new URL(request.url) + + const info = { + url: request.url, + path: url.pathname, + httpMethod: request.method, + headers: Object.fromEntries(request.headers), + query: url.searchParams.size > 0 ? Object.fromEntries(url.searchParams) : undefined, + clientIp: request.headers.get('Cf-Connecting-IP') || request.headers.get('X-Forwarded-For') || undefined + } + + return info +} + +const getRequestAndMetadataFromReq = (request) => { + const requestInfo = extractRequestInfo(request) + + return { + metadata: requestInfo, + request: { + clientIp: requestInfo.clientIp, + headers: requestInfo.headers, + httpMethod: requestInfo.httpMethod, + url: requestInfo.url + } + } +} + +const BugsnagPluginCloudflareWorkers = { + name: 'cloudflareWorkers', + + load (client) { + bugsnagInFlight.trackInFlight(client) + client._loadPlugin(BugsnagPluginBrowserSession) + + // Reset the app duration between invocations, if the plugin is loaded + const appDurationPlugin = client.getPlugin('appDuration') + + if (appDurationPlugin) { + appDurationPlugin.reset() + } + + return { + createHandler ({ flushTimeoutMs = 2000 } = {}) { + return wrapHandler.bind(null, client, flushTimeoutMs) + } + } + } +} + +function wrapHandler (client, flushTimeoutMs, handler) { + return async function (request, env, ctx) { + // Add request metadata via onError callback so server plugins can override + // Only add metadata if no server plugin is loaded + if (!isServerPluginLoaded(client)) { + client.addOnError((event) => { + const { metadata, request: requestData } = getRequestAndMetadataFromReq(request) + event.request = { ...event.request, ...requestData } + event.addMetadata('request', metadata) + }, true) + } + + // Track sessions if autoTrackSessions is enabled and no server plugin is loaded + if (client._config.autoTrackSessions && !isServerPluginLoaded(client)) { + client.startSession() + } + + try { + return await handler(request, env, ctx) + } catch (err) { + if (client._config.autoDetectErrors && client._config.enabledErrorTypes.unhandledExceptions) { + const handledState = { + severity: 'error', + unhandled: true, + severityReason: { type: 'unhandledException' } + } + + const event = client.Event.create(err, true, handledState, 'cloudflare workers plugin', 1) + + client._notify(event) + } + + throw err + } finally { + // Use ctx.waitUntil to ensure flush completes even after response is returned + // This is critical for Cloudflare Workers as they can terminate immediately + if (ctx && typeof ctx.waitUntil === 'function') { + ctx.waitUntil( + bugsnagInFlight.flush(flushTimeoutMs).catch(err => { + client._logger.error(`Delivery may be unsuccessful: ${err.message}`) + }) + ) + } else { + try { + await bugsnagInFlight.flush(flushTimeoutMs) + } catch (err) { + client._logger.error(`Delivery may be unsuccessful: ${err.message}`) + } + } + } + } +} + +module.exports = BugsnagPluginCloudflareWorkers + +// add a default export for ESM modules without interop +module.exports.default = module.exports diff --git a/packages/plugin-cloudflare-workers/test/index.test.ts b/packages/plugin-cloudflare-workers/test/index.test.ts new file mode 100644 index 0000000000..3430943f6d --- /dev/null +++ b/packages/plugin-cloudflare-workers/test/index.test.ts @@ -0,0 +1,316 @@ +import BugsnagPluginCloudflareWorkers from '../src/' +import Client, { EventDeliveryPayload, SessionDeliveryPayload } from '@bugsnag/core/client' +import type { Request as CloudflareRequest, Response as CloudflareResponse, ExecutionContext, ExportedHandler, IncomingRequestCfProperties } from '@cloudflare/workers-types' + +// Extended ExecutionContext type for testing with helper method +interface MockExecutionContext extends ExecutionContext { + _waitForAllPromises: () => Promise +} + +// Example Env interface for testing type inference +interface Env { + SOME_VALUE?: string +} + +// Mock ExecutionContext for Cloudflare Workers +const createMockExecutionContext = (): MockExecutionContext => { + const promises: Array> = [] + return { + waitUntil: (promise: Promise) => { promises.push(promise) }, + + // Helper for tests to wait for all promises registered with waitUntil + _waitForAllPromises: () => Promise.all(promises) + } as unknown as MockExecutionContext +} + +const createClient = (events: EventDeliveryPayload[], sessions: SessionDeliveryPayload[], config = {}) => { + const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers], ...config }) + + // @ts-ignore the following property is not defined on the public Event interface + client.Event.__type = 'nodejs' + + client._delivery = { + sendEvent (payload, cb = () => {}) { + events.push(payload) + cb() + }, + sendSession (payload, cb = () => {}) { + sessions.push(payload) + cb() + } + } + + return client +} + +describe('plugin: cloudflare workers', () => { + it('has a name', () => { + expect(BugsnagPluginCloudflareWorkers.name).toBe('cloudflareWorkers') + + const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers] }) + const plugin = client.getPlugin('cloudflareWorkers') + + expect(plugin).toBeTruthy() + }) + + it('exports a "createHandler" function', () => { + const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers] }) + const plugin = client.getPlugin('cloudflareWorkers') + + expect(plugin).toMatchObject({ createHandler: expect.any(Function) }) + }) + + it('adds the request as metadata when an error occurs', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions) + + const err = new Error('test error') + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + throw err + }) + } + + const request = new Request('https://example.com/test?foo=bar&baz=qux', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Cf-Connecting-IP': '203.0.113.1' + } + }) as unknown as CloudflareRequest> + const env = {} + const ctx = createMockExecutionContext() + + await expect(exportedHandler.fetch?.(request, env, ctx)).rejects.toThrow(err) + + // Wait for promises registered with ctx.waitUntil to complete + await ctx._waitForAllPromises() + + expect(events).toHaveLength(1) + + const event = events[0].events[0] + expect(event.request).toMatchObject({ + url: 'https://example.com/test?foo=bar&baz=qux', + httpMethod: 'POST', + clientIp: '203.0.113.1', + headers: { + 'content-type': 'application/json', + 'cf-connecting-ip': '203.0.113.1' + } + }) + // @ts-ignore + expect(event._metadata?.request).toMatchObject({ + url: 'https://example.com/test?foo=bar&baz=qux', + path: '/test', + httpMethod: 'POST', + clientIp: '203.0.113.1', + query: { + foo: 'bar', + baz: 'qux' + }, + headers: { + 'content-type': 'application/json', + 'cf-connecting-ip': '203.0.113.1' + } + }) + }) + + it('logs an error if flush times out', async () => { + const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers] }) + client._logger.error = jest.fn() + + client._delivery = { + sendEvent (payload, cb = () => {}) { + setTimeout(cb, 250) + }, + sendSession (payload, cb = () => {}) { + setTimeout(cb, 250) + } + } + + const timeoutError = new Error('flush timed out after 20ms') + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler({ flushTimeoutMs: 20 }) + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler((request, env, ctx) => { + client.notify('hello') + return new Response('Hello World!') as unknown as CloudflareResponse + }) + } + + const request = new Request('https://example.com/test') as unknown as CloudflareRequest> + const env = {} + const ctx = createMockExecutionContext() + + const response = await exportedHandler.fetch?.(request, env, ctx) + + // Wait for promises registered with ctx.waitUntil to complete + await ctx._waitForAllPromises().catch(() => {}) + + expect(await response?.text()).toBe('Hello World!') + expect(client._logger.error).toHaveBeenCalledWith(`Delivery may be unsuccessful: ${timeoutError.message}`) + }) + + it('returns a wrapped handler that resolves to the original return value', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions) + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + // Access env property to verify type inference works correctly + const value = env.SOME_VALUE + return new Response(`Hello World! ${value}`) as unknown as CloudflareResponse + }) + } + + const request = new Request('https://example.com/test') as unknown as CloudflareRequest> + const env = { + SOME_VALUE: 'test value' + } + const ctx = createMockExecutionContext() + + const response = await exportedHandler.fetch?.(request, env, ctx) + expect(await response?.text()).toBe('Hello World! test value') + + expect(events).toHaveLength(0) + expect(sessions).toHaveLength(1) + }) + + it('notifies when an error is thrown', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions) + + const err = new Error('badness') + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + throw err + }) + } + + const request = new Request('https://example.com/test') as unknown as CloudflareRequest> + const env = {} + const ctx = createMockExecutionContext() + + await expect(exportedHandler.fetch?.(request, env, ctx)).rejects.toThrow(err) + + // Wait for promises registered with ctx.waitUntil to complete + await ctx._waitForAllPromises() + + expect(events).toHaveLength(1) + + const event = events[0].events[0] + // @ts-ignore + expect(event.errors[0].errorMessage).toBe('badness') + expect(event.unhandled).toBe(true) + + expect(sessions).toHaveLength(1) + }) + + it('does not notify when autoDetectErrors=false', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions, { autoDetectErrors: false }) + + const err = new Error('badness') + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + throw err + }) + } + + const request = new Request('https://example.com/test') as unknown as CloudflareRequest> + const env = {} + const ctx = createMockExecutionContext() + + await expect(exportedHandler.fetch?.(request, env, ctx)).rejects.toThrow(err) + + expect(events).toHaveLength(0) + expect(sessions).toHaveLength(1) + }) + + it('does not notify when enabledErrorTypes.unhandledExceptions=false', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions, { + enabledErrorTypes: { + unhandledExceptions: false, + unhandledRejections: true + } + }) + + const err = new Error('badness') + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + throw err + }) + } + + const request = new Request('https://example.com/test') as unknown as CloudflareRequest> + const env = {} + const ctx = createMockExecutionContext() + + await expect(exportedHandler.fetch?.(request, env, ctx)).rejects.toThrow(err) + + expect(events).toHaveLength(0) + expect(sessions).toHaveLength(1) + }) +}) diff --git a/packages/plugin-cloudflare-workers/test/setup.ts b/packages/plugin-cloudflare-workers/test/setup.ts new file mode 100644 index 0000000000..a9a4348b20 --- /dev/null +++ b/packages/plugin-cloudflare-workers/test/setup.ts @@ -0,0 +1 @@ +import 'whatwg-fetch' diff --git a/packages/plugin-cloudflare-workers/types/bugsnag-plugin-cloudflare-workers.d.ts b/packages/plugin-cloudflare-workers/types/bugsnag-plugin-cloudflare-workers.d.ts new file mode 100644 index 0000000000..dbeefe11d9 --- /dev/null +++ b/packages/plugin-cloudflare-workers/types/bugsnag-plugin-cloudflare-workers.d.ts @@ -0,0 +1,16 @@ +import { Plugin } from '@bugsnag/core' +declare const BugsnagPluginCloudflareWorkers: Plugin +export default BugsnagPluginCloudflareWorkers +export interface BugsnagPluginCloudflareWorkersConfiguration { + flushTimeoutMs?: number +} +export interface BugsnagPluginCloudflareWorkersResult { + createHandler(configuration?: BugsnagPluginCloudflareWorkersConfiguration): (handler: T) => T +} + +// add a new call signature for the getPlugin() method that types the plugin result +declare module '@bugsnag/core' { + interface Client { + getPlugin(id: 'cloudflareWorkers'): BugsnagPluginCloudflareWorkersResult | undefined + } +} From db3484de264ec43cbfe6a2b6d395ca3162fbd126 Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:13:52 +0000 Subject: [PATCH 38/43] fix(plugin-cloudflare-workers): use request scoped client and run within async context (#2644) --- CHANGELOG.md | 2 +- .../plugin-cloudflare-workers/src/index.js | 91 +++++---- .../test/index.test.ts | 191 +++++++++++++++++- 3 files changed, 238 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57487c61ea..af787fa616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -(plugin-cloudflare-workers): Add initial support for Cloudflare Workers [#2643](https://github.com/bugsnag/bugsnag-js/pull/2643) +(plugin-cloudflare-workers): Add initial support for Cloudflare Workers [#2643](https://github.com/bugsnag/bugsnag-js/pull/2643) [#2644](https://github.com/bugsnag/bugsnag-js/pull/2644) ### Fixed diff --git a/packages/plugin-cloudflare-workers/src/index.js b/packages/plugin-cloudflare-workers/src/index.js index 5cb02702e3..b45b6a91d9 100644 --- a/packages/plugin-cloudflare-workers/src/index.js +++ b/packages/plugin-cloudflare-workers/src/index.js @@ -1,5 +1,6 @@ const bugsnagInFlight = require('@bugsnag/in-flight') const BugsnagPluginBrowserSession = require('@bugsnag/plugin-browser-session') +const clone = require('@bugsnag/core/lib/clone-client') const SERVER_PLUGIN_NAMES = ['express', 'koa', 'restify', 'hono'] const isServerPluginLoaded = client => SERVER_PLUGIN_NAMES.some(name => client.getPlugin(name)) @@ -42,13 +43,6 @@ const BugsnagPluginCloudflareWorkers = { bugsnagInFlight.trackInFlight(client) client._loadPlugin(BugsnagPluginBrowserSession) - // Reset the app duration between invocations, if the plugin is loaded - const appDurationPlugin = client.getPlugin('appDuration') - - if (appDurationPlugin) { - appDurationPlugin.reset() - } - return { createHandler ({ flushTimeoutMs = 2000 } = {}) { return wrapHandler.bind(null, client, flushTimeoutMs) @@ -59,54 +53,65 @@ const BugsnagPluginCloudflareWorkers = { function wrapHandler (client, flushTimeoutMs, handler) { return async function (request, env, ctx) { - // Add request metadata via onError callback so server plugins can override - // Only add metadata if no server plugin is loaded + // Reset the app duration between invocations, if the plugin is loaded + const appDurationPlugin = client.getPlugin('appDuration') + + if (appDurationPlugin) { + appDurationPlugin.reset() + } + + // clone the client to be scoped to this request. + const requestClient = clone(client) + + // only start a session and add request metadata if no server plugin is loaded, + // as those plugins will handle this themselves if (!isServerPluginLoaded(client)) { - client.addOnError((event) => { + if (requestClient._config.autoTrackSessions) { + requestClient.startSession() + } + + requestClient.addOnError((event) => { const { metadata, request: requestData } = getRequestAndMetadataFromReq(request) event.request = { ...event.request, ...requestData } event.addMetadata('request', metadata) }, true) } - // Track sessions if autoTrackSessions is enabled and no server plugin is loaded - if (client._config.autoTrackSessions && !isServerPluginLoaded(client)) { - client.startSession() - } + return client._clientContext.run(requestClient, async () => { + try { + return await handler(request, env, ctx) + } catch (err) { + if (requestClient._config.autoDetectErrors && requestClient._config.enabledErrorTypes.unhandledExceptions) { + const handledState = { + severity: 'error', + unhandled: true, + severityReason: { type: 'unhandledException' } + } - try { - return await handler(request, env, ctx) - } catch (err) { - if (client._config.autoDetectErrors && client._config.enabledErrorTypes.unhandledExceptions) { - const handledState = { - severity: 'error', - unhandled: true, - severityReason: { type: 'unhandledException' } - } - - const event = client.Event.create(err, true, handledState, 'cloudflare workers plugin', 1) + const event = requestClient.Event.create(err, true, handledState, 'cloudflare workers plugin', 1) - client._notify(event) - } + requestClient._notify(event) + } - throw err - } finally { - // Use ctx.waitUntil to ensure flush completes even after response is returned - // This is critical for Cloudflare Workers as they can terminate immediately - if (ctx && typeof ctx.waitUntil === 'function') { - ctx.waitUntil( - bugsnagInFlight.flush(flushTimeoutMs).catch(err => { - client._logger.error(`Delivery may be unsuccessful: ${err.message}`) - }) - ) - } else { - try { - await bugsnagInFlight.flush(flushTimeoutMs) - } catch (err) { - client._logger.error(`Delivery may be unsuccessful: ${err.message}`) + throw err + } finally { + // use ctx.waitUntil to ensure flush completes even after response is returned + // this is critical for Cloudflare Workers as they can terminate immediately + if (ctx && typeof ctx.waitUntil === 'function') { + ctx.waitUntil( + bugsnagInFlight.flush(flushTimeoutMs).catch(err => { + requestClient._logger.error(`Delivery may be unsuccessful: ${err.message}`) + }) + ) + } else { + try { + await bugsnagInFlight.flush(flushTimeoutMs) + } catch (err) { + requestClient._logger.error(`Delivery may be unsuccessful: ${err.message}`) + } } } - } + }) } } diff --git a/packages/plugin-cloudflare-workers/test/index.test.ts b/packages/plugin-cloudflare-workers/test/index.test.ts index 3430943f6d..f4f274e6bb 100644 --- a/packages/plugin-cloudflare-workers/test/index.test.ts +++ b/packages/plugin-cloudflare-workers/test/index.test.ts @@ -23,8 +23,8 @@ const createMockExecutionContext = (): MockExecutionContext => { } as unknown as MockExecutionContext } -const createClient = (events: EventDeliveryPayload[], sessions: SessionDeliveryPayload[], config = {}) => { - const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers], ...config }) +const createClient = (events: EventDeliveryPayload[], sessions: SessionDeliveryPayload[], config = {}, additionalPlugins: any[] = []) => { + const client = new Client({ apiKey: 'AN_API_KEY', plugins: [BugsnagPluginCloudflareWorkers, ...additionalPlugins], ...config }) // @ts-ignore the following property is not defined on the public Event interface client.Event.__type = 'nodejs' @@ -40,6 +40,12 @@ const createClient = (events: EventDeliveryPayload[], sessions: SessionDeliveryP } } + // Mock _clientContext.run to execute the callback immediately + // This simulates AsyncLocalStorage behavior for testing + client._clientContext = { + run: jest.fn((requestClient, callback) => callback()) + } + return client } @@ -97,6 +103,13 @@ describe('plugin: cloudflare workers', () => { // Wait for promises registered with ctx.waitUntil to complete await ctx._waitForAllPromises() + // Verify _clientContext.run was called with a cloned client + expect(client._clientContext.run).toHaveBeenCalledTimes(1) + expect(client._clientContext.run).toHaveBeenCalledWith( + expect.any(Client), + expect.any(Function) + ) + expect(events).toHaveLength(1) const event = events[0].events[0] @@ -139,6 +152,11 @@ describe('plugin: cloudflare workers', () => { } } + // Mock _clientContext.run to execute the callback immediately + client._clientContext = { + run: jest.fn((requestClient, callback) => callback()) + } + const timeoutError = new Error('flush timed out after 20ms') const plugin = client.getPlugin('cloudflareWorkers') @@ -200,6 +218,13 @@ describe('plugin: cloudflare workers', () => { const response = await exportedHandler.fetch?.(request, env, ctx) expect(await response?.text()).toBe('Hello World! test value') + // Verify _clientContext.run was called + expect(client._clientContext.run).toHaveBeenCalledTimes(1) + expect(client._clientContext.run).toHaveBeenCalledWith( + expect.any(Client), + expect.any(Function) + ) + expect(events).toHaveLength(0) expect(sessions).toHaveLength(1) }) @@ -235,6 +260,9 @@ describe('plugin: cloudflare workers', () => { // Wait for promises registered with ctx.waitUntil to complete await ctx._waitForAllPromises() + // Verify _clientContext.run was called + expect(client._clientContext.run).toHaveBeenCalledTimes(1) + expect(events).toHaveLength(1) const event = events[0].events[0] @@ -313,4 +341,163 @@ describe('plugin: cloudflare workers', () => { expect(events).toHaveLength(0) expect(sessions).toHaveLength(1) }) + + it('clones the client for each request to avoid callback accumulation', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + const client = createClient(events, sessions) + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + throw new Error('Test error') + }) + } + + const request1 = new Request('https://example.com/request1?param1=value1', { + method: 'GET', + headers: { + 'X-Custom-Header': 'request1' + } + }) as unknown as CloudflareRequest> + const request2 = new Request('https://example.com/request2?param2=value2', { + method: 'POST', + headers: { + 'X-Custom-Header': 'request2' + } + }) as unknown as CloudflareRequest> + const env = {} + const ctx1 = createMockExecutionContext() + const ctx2 = createMockExecutionContext() + + // Make two requests (both will throw errors) + await expect(exportedHandler.fetch?.(request1, env, ctx1)).rejects.toThrow('Test error') + await expect(exportedHandler.fetch?.(request2, env, ctx2)).rejects.toThrow('Test error') + + // Wait for promises registered with ctx.waitUntil to complete + await ctx1._waitForAllPromises() + await ctx2._waitForAllPromises() + + // Verify _clientContext.run was called twice with different cloned clients + expect(client._clientContext.run).toHaveBeenCalledTimes(2) + + const firstCallClient = (client._clientContext.run as jest.Mock).mock.calls[0][0] + const secondCallClient = (client._clientContext.run as jest.Mock).mock.calls[1][0] + + // Both should be Client instances but different instances + expect(firstCallClient).toBeInstanceOf(Client) + expect(secondCallClient).toBeInstanceOf(Client) + expect(firstCallClient).not.toBe(secondCallClient) + expect(firstCallClient).not.toBe(client) + expect(secondCallClient).not.toBe(client) + + // Both requests should have started sessions + expect(sessions).toHaveLength(2) + + // Verify two events were sent + expect(events).toHaveLength(2) + + // Verify first event has correct request metadata + const event1 = events[0].events[0] + expect(event1.request).toMatchObject({ + url: 'https://example.com/request1?param1=value1', + httpMethod: 'GET', + headers: expect.objectContaining({ + 'x-custom-header': 'request1' + }) + }) + // @ts-ignore + expect(event1._metadata?.request).toMatchObject({ + url: 'https://example.com/request1?param1=value1', + path: '/request1', + httpMethod: 'GET', + query: { + param1: 'value1' + }, + headers: expect.objectContaining({ + 'x-custom-header': 'request1' + }) + }) + + // Verify second event has correct request metadata + const event2 = events[1].events[0] + expect(event2.request).toMatchObject({ + url: 'https://example.com/request2?param2=value2', + httpMethod: 'POST', + headers: expect.objectContaining({ + 'x-custom-header': 'request2' + }) + }) + // @ts-ignore + expect(event2._metadata?.request).toMatchObject({ + url: 'https://example.com/request2?param2=value2', + path: '/request2', + httpMethod: 'POST', + query: { + param2: 'value2' + }, + headers: expect.objectContaining({ + 'x-custom-header': 'request2' + }) + }) + }) + + it('resets app duration plugin between requests', async () => { + const events: EventDeliveryPayload[] = [] + const sessions: SessionDeliveryPayload[] = [] + + // Mock the app duration plugin + const mockReset = jest.fn() + const mockAppDurationPlugin = { + name: 'appDuration', + load: () => ({ + reset: mockReset + }) + } + + const client = createClient(events, sessions, {}, [mockAppDurationPlugin]) + + const plugin = client.getPlugin('cloudflareWorkers') + + if (!plugin) { + throw new Error('Plugin was not loaded!') + } + + const bugsnagHandler = plugin.createHandler() + + const exportedHandler: ExportedHandler = { + fetch: bugsnagHandler(async (request, env, ctx) => { + return new Response('OK') as unknown as CloudflareResponse + }) + } + + const request1 = new Request('https://example.com/request1') as unknown as CloudflareRequest> + const request2 = new Request('https://example.com/request2') as unknown as CloudflareRequest> + const request3 = new Request('https://example.com/request3') as unknown as CloudflareRequest> + const env = {} + const ctx1 = createMockExecutionContext() + const ctx2 = createMockExecutionContext() + const ctx3 = createMockExecutionContext() + + // Make three requests + await exportedHandler.fetch?.(request1, env, ctx1) + await exportedHandler.fetch?.(request2, env, ctx2) + await exportedHandler.fetch?.(request3, env, ctx3) + + // Wait for all promises to complete + await ctx1._waitForAllPromises() + await ctx2._waitForAllPromises() + await ctx3._waitForAllPromises() + + // Verify reset was called for each request + expect(mockReset).toHaveBeenCalledTimes(3) + }) }) From 1ed92a9a4f55ee5a042fbaa392c2c2135aee3ed5 Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:55:01 +0000 Subject: [PATCH 39/43] test(plugin-cloudflare-workers): add cloudflare e2e tests (#2646) * test(plugin-cloudflare-workers): add e2e test fixture and feature * ci(plugin-cloudflare-workers): add CI pipeline * ci(plugin-cloudflare-workers): apply code review suggestions --- .buildkite/basic/cloudflare-pipeline.yml | 16 + .../block/cloudflare-pipeline.block.yml | 10 + .buildkite/package_manifest.json | 25 + .eslintignore | 1 + test/cloudflare-workers/.gitignore | 5 + test/cloudflare-workers/Gemfile | 9 + .../features/cloudflare-worker.feature | 130 + .../fixtures/cloudflare-worker/package.json | 16 + .../fixtures/cloudflare-worker/src/index.ts | 39 + .../fixtures/cloudflare-worker/tsconfig.json | 46 + .../worker-configuration.d.ts | 10857 ++++++++++++++++ .../fixtures/cloudflare-worker/wrangler.jsonc | 18 + .../features/scripts/build-fixtures.rb | 117 + .../features/scripts/start-fixture.rb | 11 + .../features/steps/cloudflare-steps.rb | 57 + .../features/support/env.rb | 16 + 16 files changed, 11373 insertions(+) create mode 100644 .buildkite/basic/cloudflare-pipeline.yml create mode 100644 .buildkite/block/cloudflare-pipeline.block.yml create mode 100644 test/cloudflare-workers/.gitignore create mode 100644 test/cloudflare-workers/Gemfile create mode 100644 test/cloudflare-workers/features/cloudflare-worker.feature create mode 100644 test/cloudflare-workers/features/fixtures/cloudflare-worker/package.json create mode 100644 test/cloudflare-workers/features/fixtures/cloudflare-worker/src/index.ts create mode 100644 test/cloudflare-workers/features/fixtures/cloudflare-worker/tsconfig.json create mode 100644 test/cloudflare-workers/features/fixtures/cloudflare-worker/worker-configuration.d.ts create mode 100644 test/cloudflare-workers/features/fixtures/cloudflare-worker/wrangler.jsonc create mode 100755 test/cloudflare-workers/features/scripts/build-fixtures.rb create mode 100644 test/cloudflare-workers/features/scripts/start-fixture.rb create mode 100644 test/cloudflare-workers/features/steps/cloudflare-steps.rb create mode 100644 test/cloudflare-workers/features/support/env.rb diff --git a/.buildkite/basic/cloudflare-pipeline.yml b/.buildkite/basic/cloudflare-pipeline.yml new file mode 100644 index 0000000000..1ed176c44e --- /dev/null +++ b/.buildkite/basic/cloudflare-pipeline.yml @@ -0,0 +1,16 @@ +steps: + + - group: ":cloudflare: Cloudflare Worker Tests" + steps: + - label: ":cloudflare: Cloudflare Worker tests" + timeout_in_minutes: 15 + agents: + queue: macos-15-isolated + env: + NODE_VERSION: "22" + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + VERBOSE: "1" + commands: + - "cd test/cloudflare-workers" + - "bundle install" + - "bundle exec maze-runner" diff --git a/.buildkite/block/cloudflare-pipeline.block.yml b/.buildkite/block/cloudflare-pipeline.block.yml new file mode 100644 index 0000000000..801966ed52 --- /dev/null +++ b/.buildkite/block/cloudflare-pipeline.block.yml @@ -0,0 +1,10 @@ +steps: + - block: "Trigger Cloudflare Workers pipeline" + key: "trigger-cloudflare-pipeline" + + - label: ":pipeline: Upload Cloudflare Workers pipeline" + depends_on: "trigger-cloudflare-pipeline" + agents: + queue: macos + timeout_in_minutes: 5 + command: buildkite-agent pipeline upload .buildkite/basic/cloudflare-pipeline.yml \ No newline at end of file diff --git a/.buildkite/package_manifest.json b/.buildkite/package_manifest.json index cbdb9d2287..63344e0083 100644 --- a/.buildkite/package_manifest.json +++ b/.buildkite/package_manifest.json @@ -147,5 +147,30 @@ "pipeline": ".buildkite/basic/expo-pipeline.yml", "block": ".buildkite/block/expo-pipeline.block.yml", "paths": [] + }, + { + "pipeline": ".buildkite/basic/cloudflare-pipeline.yml", + "block": ".buildkite/block/cloudflare-pipeline.block.yml", + "paths": [ + "test/cloudflare-workers", + "packages/core", + "packages/node", + "packages/delivery-node", + "packages/plugin-app-duration", + "packages/plugin-console-breadcrumbs", + "packages/plugin-contextualize", + "packages/plugin-intercept", + "packages/plugin-node-device", + "packages/plugin-node-in-project", + "packages/plugin-node-surrounding-code", + "packages/plugin-node-uncaught-exception", + "packages/plugin-node-unhandled-rejection", + "packages/plugin-server-session", + "packages/plugin-stackframe-path-normaliser", + "packages/plugin-strip-project-root", + "packages/plugin-cloudflare-workers", + "packages/plugin-browser-session", + "packages/in-flight" + ] } ] \ No newline at end of file diff --git a/.eslintignore b/.eslintignore index ccaeb1a00f..99b541fc04 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,3 +10,4 @@ packages/**/fixtures test/browser test/node test/react-native-cli/features/fixtures +test/cloudflare-workers diff --git a/test/cloudflare-workers/.gitignore b/test/cloudflare-workers/.gitignore new file mode 100644 index 0000000000..064a3e6a41 --- /dev/null +++ b/test/cloudflare-workers/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +.wrangler/ +.tgz +package-lock.json +/Gemfile.lock diff --git a/test/cloudflare-workers/Gemfile b/test/cloudflare-workers/Gemfile new file mode 100644 index 0000000000..3be2e6f61c --- /dev/null +++ b/test/cloudflare-workers/Gemfile @@ -0,0 +1,9 @@ +source 'https://rubygems.org' + +gem 'bugsnag-maze-runner', '~>10.0' + +# Use a branch of Maze Runner +# gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' + +# Locally, you can run against Maze Runner branches and uncommitted changes: +#gem 'bugsnag-maze-runner', path: '../../../maze-runner' diff --git a/test/cloudflare-workers/features/cloudflare-worker.feature b/test/cloudflare-workers/features/cloudflare-worker.feature new file mode 100644 index 0000000000..86d9011066 --- /dev/null +++ b/test/cloudflare-workers/features/cloudflare-worker.feature @@ -0,0 +1,130 @@ +Feature: @bugsnag/plugin-cloudflare-workers + +Scenario: A handled error + When I start the worker "cloudflare-worker" + And I wait for the host "localhost" to open port "8787" + Then I open the URL "http://localhost:8787/handled?a=1&b=2" and get a 200 response with body "Hello World!" + + Then I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + Then I wait to receive an error + Then the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the event "unhandled" is false + And the event "severity" equals "warning" + And the exception "errorClass" equals "Error" + And the exception "message" equals "handled" + And the exception "type" equals "nodejs" + And the "file" of stack frame 0 matches "index.js" + And the event "request.url" equals "http://localhost:8787/handled?a=1&b=2" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event "request.headers" is not null + And the event "metaData.request.path" equals "/handled" + And the event "metaData.request.query.a" equals "1" + And the event "metaData.request.query.b" equals "2" + +Scenario: An unhandled error + When I start the worker "cloudflare-worker" + And I wait for the host "localhost" to open port "8787" + Then I open the URL "http://localhost:8787/unhandled?a=1&b=2" and get a 500 response + + Then I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + Then I wait to receive an error + Then the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the event "unhandled" is true + And the event "severity" equals "error" + And the exception "errorClass" equals "Error" + And the exception "message" equals "unhandled" + And the exception "type" equals "nodejs" + And the "file" of stack frame 0 matches "index.js" + And the event "request.url" equals "http://localhost:8787/unhandled?a=1&b=2" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event "request.headers" is not null + And the event "metaData.request.path" equals "/unhandled" + And the event "metaData.request.query.a" equals "1" + And the event "metaData.request.query.b" equals "2" + +Scenario: Metadata from one request do not appear in another + When I start the worker "cloudflare-worker" + And I wait for the host "localhost" to open port "8787" + Then I open the URL "http://localhost:8787/metadata_a" and get a 200 response with body "Hello World!" + + Then I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + Then I wait to receive an error + Then the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the event "unhandled" is false + And the event "severity" equals "warning" + And the exception "errorClass" equals "Error" + And the exception "message" equals "Metadata A Error" + And the exception "type" equals "nodejs" + And the "file" of stack frame 0 matches "index.js" + And the event "request.url" equals "http://localhost:8787/metadata_a" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event "request.headers" is not null + And the event "metaData.request.path" equals "/metadata_a" + And the event "metaData.Metadata A" is not null + And the event "metaData.Metadata B" is null + + And I discard the oldest session + And I discard the oldest error + + And I open the URL "http://localhost:8787/metadata_b" and get a 200 response with body "Hello World!" + + And I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the event "unhandled" is false + And the event "severity" equals "warning" + And the exception "errorClass" equals "Error" + And the exception "message" equals "Metadata B Error" + And the exception "type" equals "nodejs" + And the "file" of stack frame 0 matches "index.js" + And the event "request.url" equals "http://localhost:8787/metadata_b" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event "request.headers" is not null + And the event "metaData.request.path" equals "/metadata_b" + And the event "metaData.Metadata A" is null + And the event "metaData.Metadata B" is not null + +Scenario: Breadcrumbs from one request do not appear in another + When I start the worker "cloudflare-worker" + And I wait for the host "localhost" to open port "8787" + Then I open the URL "http://localhost:8787/breadcrumbs_a" and get a 200 response with body "Hello World!" + + Then I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + Then I wait to receive an error + Then the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the exception "message" equals "Breadcrumb A Error" + And the event "request.url" equals "http://localhost:8787/breadcrumbs_a" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event has a "manual" breadcrumb named "Breadcrumb A" + + And I discard the oldest session + And I discard the oldest error + + And I open the URL "http://localhost:8787/breadcrumbs_b" and get a 200 response with body "Hello World!" + + And I wait to receive a session + And the session is valid for the session reporting API version "1" for the "Bugsnag Node" notifier + + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Node" notifier + And the exception "message" equals "Breadcrumb B Error" + And the event "request.url" equals "http://localhost:8787/breadcrumbs_b" + And the event "request.httpMethod" equals "GET" + And the event "request.clientIp" is not null + And the event has a "manual" breadcrumb named "Breadcrumb B" + And the event does not have a "manual" breadcrumb with message "Breadcrumb A" \ No newline at end of file diff --git a/test/cloudflare-workers/features/fixtures/cloudflare-worker/package.json b/test/cloudflare-workers/features/fixtures/cloudflare-worker/package.json new file mode 100644 index 0000000000..76d7864734 --- /dev/null +++ b/test/cloudflare-workers/features/fixtures/cloudflare-worker/package.json @@ -0,0 +1,16 @@ +{ + "name": "cloudflare-worker", + "version": "0.0.0", + "private": true, + "scripts": { + "deploy": "wrangler deploy", + "dev": "wrangler dev", + "start": "wrangler dev --inspector-port 0 --show-interactive-dev-session false --live-reload false --var BUGSNAG_API_KEY:$BUGSNAG_API_KEY --var BUGSNAG_NOTIFY_ENDPOINT:$BUGSNAG_NOTIFY_ENDPOINT --var BUGSNAG_SESSIONS_ENDPOINT:$BUGSNAG_SESSIONS_ENDPOINT", + "cf-typegen": "wrangler types" + }, + "devDependencies": { + "@types/node": "^25.0.2", + "typescript": "^5.5.2", + "wrangler": "^4.54.0" + } +} diff --git a/test/cloudflare-workers/features/fixtures/cloudflare-worker/src/index.ts b/test/cloudflare-workers/features/fixtures/cloudflare-worker/src/index.ts new file mode 100644 index 0000000000..c965a71d37 --- /dev/null +++ b/test/cloudflare-workers/features/fixtures/cloudflare-worker/src/index.ts @@ -0,0 +1,39 @@ +import Bugsnag from '@bugsnag/node' +import BugsnagPluginCloudflareWorkers from '@bugsnag/plugin-cloudflare-workers' + +Bugsnag.start({ + apiKey: process.env.BUGSNAG_API_KEY, + endpoints: { + notify: process.env.BUGSNAG_NOTIFY_ENDPOINT, + sessions: process.env.BUGSNAG_SESSIONS_ENDPOINT + }, + plugins: [BugsnagPluginCloudflareWorkers], +}) + +const plugin = Bugsnag.getPlugin('cloudflareWorkers') + +const bugsnagHandler = plugin!.createHandler() + +export default { + fetch: bugsnagHandler(async (request, env, ctx): Promise => { + if (request.url.includes('/handled')) { + Bugsnag.notify(new Error('handled')); + } else if (request.url.includes('/unhandled')) { + throw new Error('unhandled'); + } else if (request.url.includes('/metadata_a')) { + Bugsnag.addMetadata('Metadata A', 'a', 'value a'); + Bugsnag.notify(new Error('Metadata A Error')); + } else if (request.url.includes('/metadata_b')) { + Bugsnag.addMetadata('Metadata B', 'b', 'value b'); + Bugsnag.notify(new Error('Metadata B Error')); + } else if (request.url.includes('/breadcrumbs_a')) { + Bugsnag.leaveBreadcrumb('Breadcrumb A', { message: 'Breadcrumb A' }) + Bugsnag.notify(new Error('Breadcrumb A Error')); + } else if (request.url.includes('/breadcrumbs_b')) { + Bugsnag.leaveBreadcrumb('Breadcrumb B', { message: 'Breadcrumb B' }) + Bugsnag.notify(new Error('Breadcrumb B Error')); + } + + return new Response('Hello World!'); + }), +} satisfies ExportedHandler; diff --git a/test/cloudflare-workers/features/fixtures/cloudflare-worker/tsconfig.json b/test/cloudflare-workers/features/fixtures/cloudflare-worker/tsconfig.json new file mode 100644 index 0000000000..8c98cdbece --- /dev/null +++ b/test/cloudflare-workers/features/fixtures/cloudflare-worker/tsconfig.json @@ -0,0 +1,46 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2024", + /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "lib": ["es2024"], + /* Specify what JSX code is generated. */ + "jsx": "react-jsx", + + /* Specify what module code is generated. */ + "module": "es2022", + /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "Bundler", + /* Enable importing .json files */ + "resolveJsonModule": true, + + /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + "allowJs": true, + /* Enable error reporting in type-checked JavaScript files. */ + "checkJs": false, + + /* Disable emitting files from a compilation. */ + "noEmit": true, + + /* Ensure that each file can be safely transpiled without relying on other imports. */ + "isolatedModules": true, + /* Allow 'import x from y' when a module doesn't have a default export. */ + "allowSyntheticDefaultImports": true, + /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true, + + /* Enable all strict type-checking options. */ + "strict": true, + + /* Skip type checking all .d.ts files. */ + "skipLibCheck": true, + "types": [ + "./worker-configuration.d.ts", + "node" + ] + }, + "exclude": ["test"], + "include": ["worker-configuration.d.ts", "src/**/*.ts"] +} diff --git a/test/cloudflare-workers/features/fixtures/cloudflare-worker/worker-configuration.d.ts b/test/cloudflare-workers/features/fixtures/cloudflare-worker/worker-configuration.d.ts new file mode 100644 index 0000000000..b1d5af5a54 --- /dev/null +++ b/test/cloudflare-workers/features/fixtures/cloudflare-worker/worker-configuration.d.ts @@ -0,0 +1,10857 @@ +/* eslint-disable */ +// Generated by Wrangler by running `wrangler types` (hash: 03da6d17538081322b523503fe883156) +// Runtime types generated with workerd@1.20251210.0 2025-12-16 nodejs_compat +declare namespace Cloudflare { + interface GlobalProps { + mainModule: typeof import("./scenarios/index"); + } + interface Env { + BUGSNAG_API_KEY: "placeholder-api-key"; + BUGSNAG_NOTIFY_ENDPOINT: "placeholder-notify-endpoint"; + BUGSNAG_SESSIONS_ENDPOINT: "placeholder-sessions-endpoint"; + } +} +interface Env extends Cloudflare.Env {} +type StringifyValues> = { + [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; +}; +declare namespace NodeJS { + interface ProcessEnv extends StringifyValues> {} +} + +// Begin runtime types +/*! ***************************************************************************** +Copyright (c) Cloudflare. All rights reserved. +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* eslint-disable */ +// noinspection JSUnusedGlobalSymbols +declare var onmessage: never; +/** + * The **`DOMException`** interface represents an abnormal event (called an **exception**) that occurs as a result of calling a method or accessing a property of a web API. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException) + */ +declare class DOMException extends Error { + constructor(message?: string, name?: string); + /** + * The **`message`** read-only property of the a message or description associated with the given error name. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) + */ + readonly message: string; + /** + * The **`name`** read-only property of the one of the strings associated with an error name. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) + */ + readonly name: string; + /** + * The **`code`** read-only property of the DOMException interface returns one of the legacy error code constants, or `0` if none match. + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code) + */ + readonly code: number; + static readonly INDEX_SIZE_ERR: number; + static readonly DOMSTRING_SIZE_ERR: number; + static readonly HIERARCHY_REQUEST_ERR: number; + static readonly WRONG_DOCUMENT_ERR: number; + static readonly INVALID_CHARACTER_ERR: number; + static readonly NO_DATA_ALLOWED_ERR: number; + static readonly NO_MODIFICATION_ALLOWED_ERR: number; + static readonly NOT_FOUND_ERR: number; + static readonly NOT_SUPPORTED_ERR: number; + static readonly INUSE_ATTRIBUTE_ERR: number; + static readonly INVALID_STATE_ERR: number; + static readonly SYNTAX_ERR: number; + static readonly INVALID_MODIFICATION_ERR: number; + static readonly NAMESPACE_ERR: number; + static readonly INVALID_ACCESS_ERR: number; + static readonly VALIDATION_ERR: number; + static readonly TYPE_MISMATCH_ERR: number; + static readonly SECURITY_ERR: number; + static readonly NETWORK_ERR: number; + static readonly ABORT_ERR: number; + static readonly URL_MISMATCH_ERR: number; + static readonly QUOTA_EXCEEDED_ERR: number; + static readonly TIMEOUT_ERR: number; + static readonly INVALID_NODE_TYPE_ERR: number; + static readonly DATA_CLONE_ERR: number; + get stack(): any; + set stack(value: any); +} +type WorkerGlobalScopeEventMap = { + fetch: FetchEvent; + scheduled: ScheduledEvent; + queue: QueueEvent; + unhandledrejection: PromiseRejectionEvent; + rejectionhandled: PromiseRejectionEvent; +}; +declare abstract class WorkerGlobalScope extends EventTarget { + EventTarget: typeof EventTarget; +} +/* The **`console`** object provides access to the debugging console (e.g., the Web console in Firefox). * + * The **`console`** object provides access to the debugging console (e.g., the Web console in Firefox). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console) + */ +interface Console { + "assert"(condition?: boolean, ...data: any[]): void; + /** + * The **`console.clear()`** static method clears the console if possible. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/clear_static) + */ + clear(): void; + /** + * The **`console.count()`** static method logs the number of times that this particular call to `count()` has been called. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) + */ + count(label?: string): void; + /** + * The **`console.countReset()`** static method resets counter used with console/count_static. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static) + */ + countReset(label?: string): void; + /** + * The **`console.debug()`** static method outputs a message to the console at the 'debug' log level. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) + */ + debug(...data: any[]): void; + /** + * The **`console.dir()`** static method displays a list of the properties of the specified JavaScript object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) + */ + dir(item?: any, options?: any): void; + /** + * The **`console.dirxml()`** static method displays an interactive tree of the descendant elements of the specified XML/HTML element. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) + */ + dirxml(...data: any[]): void; + /** + * The **`console.error()`** static method outputs a message to the console at the 'error' log level. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) + */ + error(...data: any[]): void; + /** + * The **`console.group()`** static method creates a new inline group in the Web console log, causing any subsequent console messages to be indented by an additional level, until console/groupEnd_static is called. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) + */ + group(...data: any[]): void; + /** + * The **`console.groupCollapsed()`** static method creates a new inline group in the console. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static) + */ + groupCollapsed(...data: any[]): void; + /** + * The **`console.groupEnd()`** static method exits the current inline group in the console. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static) + */ + groupEnd(): void; + /** + * The **`console.info()`** static method outputs a message to the console at the 'info' log level. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) + */ + info(...data: any[]): void; + /** + * The **`console.log()`** static method outputs a message to the console. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static) + */ + log(...data: any[]): void; + /** + * The **`console.table()`** static method displays tabular data as a table. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/table_static) + */ + table(tabularData?: any, properties?: string[]): void; + /** + * The **`console.time()`** static method starts a timer you can use to track how long an operation takes. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) + */ + time(label?: string): void; + /** + * The **`console.timeEnd()`** static method stops a timer that was previously started by calling console/time_static. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static) + */ + timeEnd(label?: string): void; + /** + * The **`console.timeLog()`** static method logs the current value of a timer that was previously started by calling console/time_static. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static) + */ + timeLog(label?: string, ...data: any[]): void; + timeStamp(label?: string): void; + /** + * The **`console.trace()`** static method outputs a stack trace to the console. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/trace_static) + */ + trace(...data: any[]): void; + /** + * The **`console.warn()`** static method outputs a warning message to the console at the 'warning' log level. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) + */ + warn(...data: any[]): void; +} +declare const console: Console; +type BufferSource = ArrayBufferView | ArrayBuffer; +type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; +declare namespace WebAssembly { + class CompileError extends Error { + constructor(message?: string); + } + class RuntimeError extends Error { + constructor(message?: string); + } + type ValueType = "anyfunc" | "externref" | "f32" | "f64" | "i32" | "i64" | "v128"; + interface GlobalDescriptor { + value: ValueType; + mutable?: boolean; + } + class Global { + constructor(descriptor: GlobalDescriptor, value?: any); + value: any; + valueOf(): any; + } + type ImportValue = ExportValue | number; + type ModuleImports = Record; + type Imports = Record; + type ExportValue = Function | Global | Memory | Table; + type Exports = Record; + class Instance { + constructor(module: Module, imports?: Imports); + readonly exports: Exports; + } + interface MemoryDescriptor { + initial: number; + maximum?: number; + shared?: boolean; + } + class Memory { + constructor(descriptor: MemoryDescriptor); + readonly buffer: ArrayBuffer; + grow(delta: number): number; + } + type ImportExportKind = "function" | "global" | "memory" | "table"; + interface ModuleExportDescriptor { + kind: ImportExportKind; + name: string; + } + interface ModuleImportDescriptor { + kind: ImportExportKind; + module: string; + name: string; + } + abstract class Module { + static customSections(module: Module, sectionName: string): ArrayBuffer[]; + static exports(module: Module): ModuleExportDescriptor[]; + static imports(module: Module): ModuleImportDescriptor[]; + } + type TableKind = "anyfunc" | "externref"; + interface TableDescriptor { + element: TableKind; + initial: number; + maximum?: number; + } + class Table { + constructor(descriptor: TableDescriptor, value?: any); + readonly length: number; + get(index: number): any; + grow(delta: number, value?: any): number; + set(index: number, value?: any): void; + } + function instantiate(module: Module, imports?: Imports): Promise; + function validate(bytes: BufferSource): boolean; +} +/** + * The **`ServiceWorkerGlobalScope`** interface of the Service Worker API represents the global execution context of a service worker. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope) + */ +interface ServiceWorkerGlobalScope extends WorkerGlobalScope { + DOMException: typeof DOMException; + WorkerGlobalScope: typeof WorkerGlobalScope; + btoa(data: string): string; + atob(data: string): string; + setTimeout(callback: (...args: any[]) => void, msDelay?: number): number; + setTimeout(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number; + clearTimeout(timeoutId: number | null): void; + setInterval(callback: (...args: any[]) => void, msDelay?: number): number; + setInterval(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number; + clearInterval(timeoutId: number | null): void; + queueMicrotask(task: Function): void; + structuredClone(value: T, options?: StructuredSerializeOptions): T; + reportError(error: any): void; + fetch(input: RequestInfo | URL, init?: RequestInit): Promise; + self: ServiceWorkerGlobalScope; + crypto: Crypto; + caches: CacheStorage; + scheduler: Scheduler; + performance: Performance; + Cloudflare: Cloudflare; + readonly origin: string; + Event: typeof Event; + ExtendableEvent: typeof ExtendableEvent; + CustomEvent: typeof CustomEvent; + PromiseRejectionEvent: typeof PromiseRejectionEvent; + FetchEvent: typeof FetchEvent; + TailEvent: typeof TailEvent; + TraceEvent: typeof TailEvent; + ScheduledEvent: typeof ScheduledEvent; + MessageEvent: typeof MessageEvent; + CloseEvent: typeof CloseEvent; + ReadableStreamDefaultReader: typeof ReadableStreamDefaultReader; + ReadableStreamBYOBReader: typeof ReadableStreamBYOBReader; + ReadableStream: typeof ReadableStream; + WritableStream: typeof WritableStream; + WritableStreamDefaultWriter: typeof WritableStreamDefaultWriter; + TransformStream: typeof TransformStream; + ByteLengthQueuingStrategy: typeof ByteLengthQueuingStrategy; + CountQueuingStrategy: typeof CountQueuingStrategy; + ErrorEvent: typeof ErrorEvent; + MessageChannel: typeof MessageChannel; + MessagePort: typeof MessagePort; + EventSource: typeof EventSource; + ReadableStreamBYOBRequest: typeof ReadableStreamBYOBRequest; + ReadableStreamDefaultController: typeof ReadableStreamDefaultController; + ReadableByteStreamController: typeof ReadableByteStreamController; + WritableStreamDefaultController: typeof WritableStreamDefaultController; + TransformStreamDefaultController: typeof TransformStreamDefaultController; + CompressionStream: typeof CompressionStream; + DecompressionStream: typeof DecompressionStream; + TextEncoderStream: typeof TextEncoderStream; + TextDecoderStream: typeof TextDecoderStream; + Headers: typeof Headers; + Body: typeof Body; + Request: typeof Request; + Response: typeof Response; + WebSocket: typeof WebSocket; + WebSocketPair: typeof WebSocketPair; + WebSocketRequestResponsePair: typeof WebSocketRequestResponsePair; + AbortController: typeof AbortController; + AbortSignal: typeof AbortSignal; + TextDecoder: typeof TextDecoder; + TextEncoder: typeof TextEncoder; + navigator: Navigator; + Navigator: typeof Navigator; + URL: typeof URL; + URLSearchParams: typeof URLSearchParams; + URLPattern: typeof URLPattern; + Blob: typeof Blob; + File: typeof File; + FormData: typeof FormData; + Crypto: typeof Crypto; + SubtleCrypto: typeof SubtleCrypto; + CryptoKey: typeof CryptoKey; + CacheStorage: typeof CacheStorage; + Cache: typeof Cache; + FixedLengthStream: typeof FixedLengthStream; + IdentityTransformStream: typeof IdentityTransformStream; + HTMLRewriter: typeof HTMLRewriter; +} +declare function addEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetAddEventListenerOptions | boolean): void; +declare function removeEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetEventListenerOptions | boolean): void; +/** + * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) + */ +declare function dispatchEvent(event: WorkerGlobalScopeEventMap[keyof WorkerGlobalScopeEventMap]): boolean; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/btoa) */ +declare function btoa(data: string): string; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/atob) */ +declare function atob(data: string): string; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */ +declare function setTimeout(callback: (...args: any[]) => void, msDelay?: number): number; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */ +declare function setTimeout(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearTimeout) */ +declare function clearTimeout(timeoutId: number | null): void; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */ +declare function setInterval(callback: (...args: any[]) => void, msDelay?: number): number; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */ +declare function setInterval(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearInterval) */ +declare function clearInterval(timeoutId: number | null): void; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/queueMicrotask) */ +declare function queueMicrotask(task: Function): void; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/structuredClone) */ +declare function structuredClone(value: T, options?: StructuredSerializeOptions): T; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/reportError) */ +declare function reportError(error: any): void; +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch) */ +declare function fetch(input: RequestInfo | URL, init?: RequestInit): Promise; +declare const self: ServiceWorkerGlobalScope; +/** +* The Web Crypto API provides a set of low-level functions for common cryptographic tasks. +* The Workers runtime implements the full surface of this API, but with some differences in +* the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms) +* compared to those implemented in most browsers. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/) +*/ +declare const crypto: Crypto; +/** +* The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) +*/ +declare const caches: CacheStorage; +declare const scheduler: Scheduler; +/** +* The Workers runtime supports a subset of the Performance API, used to measure timing and performance, +* as well as timing of subrequests and other operations. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/) +*/ +declare const performance: Performance; +declare const Cloudflare: Cloudflare; +declare const origin: string; +declare const navigator: Navigator; +interface TestController { +} +interface ExecutionContext { + waitUntil(promise: Promise): void; + passThroughOnException(): void; + readonly exports: Cloudflare.Exports; + readonly props: Props; +} +type ExportedHandlerFetchHandler = (request: Request>, env: Env, ctx: ExecutionContext) => Response | Promise; +type ExportedHandlerTailHandler = (events: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise; +type ExportedHandlerTraceHandler = (traces: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise; +type ExportedHandlerTailStreamHandler = (event: TailStream.TailEvent, env: Env, ctx: ExecutionContext) => TailStream.TailEventHandlerType | Promise; +type ExportedHandlerScheduledHandler = (controller: ScheduledController, env: Env, ctx: ExecutionContext) => void | Promise; +type ExportedHandlerQueueHandler = (batch: MessageBatch, env: Env, ctx: ExecutionContext) => void | Promise; +type ExportedHandlerTestHandler = (controller: TestController, env: Env, ctx: ExecutionContext) => void | Promise; +interface ExportedHandler { + fetch?: ExportedHandlerFetchHandler; + tail?: ExportedHandlerTailHandler; + trace?: ExportedHandlerTraceHandler; + tailStream?: ExportedHandlerTailStreamHandler; + scheduled?: ExportedHandlerScheduledHandler; + test?: ExportedHandlerTestHandler; + email?: EmailExportedHandler; + queue?: ExportedHandlerQueueHandler; +} +interface StructuredSerializeOptions { + transfer?: any[]; +} +declare abstract class Navigator { + sendBeacon(url: string, body?: BodyInit): boolean; + readonly userAgent: string; + readonly hardwareConcurrency: number; + readonly language: string; + readonly languages: string[]; +} +interface AlarmInvocationInfo { + readonly isRetry: boolean; + readonly retryCount: number; +} +interface Cloudflare { + readonly compatibilityFlags: Record; +} +interface DurableObject { + fetch(request: Request): Response | Promise; + alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise; + webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise; + webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise; + webSocketError?(ws: WebSocket, error: unknown): void | Promise; +} +type DurableObjectStub = Fetcher & { + readonly id: DurableObjectId; + readonly name?: string; +}; +interface DurableObjectId { + toString(): string; + equals(other: DurableObjectId): boolean; + readonly name?: string; +} +declare abstract class DurableObjectNamespace { + newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId; + idFromName(name: string): DurableObjectId; + idFromString(id: string): DurableObjectId; + get(id: DurableObjectId, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub; + getByName(name: string, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub; + jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace; +} +type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high"; +interface DurableObjectNamespaceNewUniqueIdOptions { + jurisdiction?: DurableObjectJurisdiction; +} +type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "oc" | "afr" | "me"; +interface DurableObjectNamespaceGetDurableObjectOptions { + locationHint?: DurableObjectLocationHint; +} +interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = undefined> { +} +interface DurableObjectState { + waitUntil(promise: Promise): void; + readonly exports: Cloudflare.Exports; + readonly props: Props; + readonly id: DurableObjectId; + readonly storage: DurableObjectStorage; + container?: Container; + blockConcurrencyWhile(callback: () => Promise): Promise; + acceptWebSocket(ws: WebSocket, tags?: string[]): void; + getWebSockets(tag?: string): WebSocket[]; + setWebSocketAutoResponse(maybeReqResp?: WebSocketRequestResponsePair): void; + getWebSocketAutoResponse(): WebSocketRequestResponsePair | null; + getWebSocketAutoResponseTimestamp(ws: WebSocket): Date | null; + setHibernatableWebSocketEventTimeout(timeoutMs?: number): void; + getHibernatableWebSocketEventTimeout(): number | null; + getTags(ws: WebSocket): string[]; + abort(reason?: string): void; +} +interface DurableObjectTransaction { + get(key: string, options?: DurableObjectGetOptions): Promise; + get(keys: string[], options?: DurableObjectGetOptions): Promise>; + list(options?: DurableObjectListOptions): Promise>; + put(key: string, value: T, options?: DurableObjectPutOptions): Promise; + put(entries: Record, options?: DurableObjectPutOptions): Promise; + delete(key: string, options?: DurableObjectPutOptions): Promise; + delete(keys: string[], options?: DurableObjectPutOptions): Promise; + rollback(): void; + getAlarm(options?: DurableObjectGetAlarmOptions): Promise; + setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise; + deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise; +} +interface DurableObjectStorage { + get(key: string, options?: DurableObjectGetOptions): Promise; + get(keys: string[], options?: DurableObjectGetOptions): Promise>; + list(options?: DurableObjectListOptions): Promise>; + put(key: string, value: T, options?: DurableObjectPutOptions): Promise; + put(entries: Record, options?: DurableObjectPutOptions): Promise; + delete(key: string, options?: DurableObjectPutOptions): Promise; + delete(keys: string[], options?: DurableObjectPutOptions): Promise; + deleteAll(options?: DurableObjectPutOptions): Promise; + transaction(closure: (txn: DurableObjectTransaction) => Promise): Promise; + getAlarm(options?: DurableObjectGetAlarmOptions): Promise; + setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise; + deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise; + sync(): Promise; + sql: SqlStorage; + kv: SyncKvStorage; + transactionSync(closure: () => T): T; + getCurrentBookmark(): Promise; + getBookmarkForTime(timestamp: number | Date): Promise; + onNextSessionRestoreBookmark(bookmark: string): Promise; +} +interface DurableObjectListOptions { + start?: string; + startAfter?: string; + end?: string; + prefix?: string; + reverse?: boolean; + limit?: number; + allowConcurrency?: boolean; + noCache?: boolean; +} +interface DurableObjectGetOptions { + allowConcurrency?: boolean; + noCache?: boolean; +} +interface DurableObjectGetAlarmOptions { + allowConcurrency?: boolean; +} +interface DurableObjectPutOptions { + allowConcurrency?: boolean; + allowUnconfirmed?: boolean; + noCache?: boolean; +} +interface DurableObjectSetAlarmOptions { + allowConcurrency?: boolean; + allowUnconfirmed?: boolean; +} +declare class WebSocketRequestResponsePair { + constructor(request: string, response: string); + get request(): string; + get response(): string; +} +interface AnalyticsEngineDataset { + writeDataPoint(event?: AnalyticsEngineDataPoint): void; +} +interface AnalyticsEngineDataPoint { + indexes?: ((ArrayBuffer | string) | null)[]; + doubles?: number[]; + blobs?: ((ArrayBuffer | string) | null)[]; +} +/** + * The **`Event`** interface represents an event which takes place on an `EventTarget`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event) + */ +declare class Event { + constructor(type: string, init?: EventInit); + /** + * The **`type`** read-only property of the Event interface returns a string containing the event's type. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type) + */ + get type(): string; + /** + * The **`eventPhase`** read-only property of the being evaluated. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase) + */ + get eventPhase(): number; + /** + * The read-only **`composed`** property of the or not the event will propagate across the shadow DOM boundary into the standard DOM. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed) + */ + get composed(): boolean; + /** + * The **`bubbles`** read-only property of the Event interface indicates whether the event bubbles up through the DOM tree or not. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/bubbles) + */ + get bubbles(): boolean; + /** + * The **`cancelable`** read-only property of the Event interface indicates whether the event can be canceled, and therefore prevented as if the event never happened. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelable) + */ + get cancelable(): boolean; + /** + * The **`defaultPrevented`** read-only property of the Event interface returns a boolean value indicating whether or not the call to Event.preventDefault() canceled the event. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/defaultPrevented) + */ + get defaultPrevented(): boolean; + /** + * The Event property **`returnValue`** indicates whether the default action for this event has been prevented or not. + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/returnValue) + */ + get returnValue(): boolean; + /** + * The **`currentTarget`** read-only property of the Event interface identifies the element to which the event handler has been attached. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/currentTarget) + */ + get currentTarget(): EventTarget | undefined; + /** + * The read-only **`target`** property of the dispatched. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target) + */ + get target(): EventTarget | undefined; + /** + * The deprecated **`Event.srcElement`** is an alias for the Event.target property. + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement) + */ + get srcElement(): EventTarget | undefined; + /** + * The **`timeStamp`** read-only property of the Event interface returns the time (in milliseconds) at which the event was created. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/timeStamp) + */ + get timeStamp(): number; + /** + * The **`isTrusted`** read-only property of the when the event was generated by the user agent (including via user actions and programmatic methods such as HTMLElement.focus()), and `false` when the event was dispatched via The only exception is the `click` event, which initializes the `isTrusted` property to `false` in user agents. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted) + */ + get isTrusted(): boolean; + /** + * The **`cancelBubble`** property of the Event interface is deprecated. + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) + */ + get cancelBubble(): boolean; + /** + * The **`cancelBubble`** property of the Event interface is deprecated. + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) + */ + set cancelBubble(value: boolean); + /** + * The **`stopImmediatePropagation()`** method of the If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation) + */ + stopImmediatePropagation(): void; + /** + * The **`preventDefault()`** method of the Event interface tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) + */ + preventDefault(): void; + /** + * The **`stopPropagation()`** method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) + */ + stopPropagation(): void; + /** + * The **`composedPath()`** method of the Event interface returns the event's path which is an array of the objects on which listeners will be invoked. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath) + */ + composedPath(): EventTarget[]; + static readonly NONE: number; + static readonly CAPTURING_PHASE: number; + static readonly AT_TARGET: number; + static readonly BUBBLING_PHASE: number; +} +interface EventInit { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; +} +type EventListener = (event: EventType) => void; +interface EventListenerObject { + handleEvent(event: EventType): void; +} +type EventListenerOrEventListenerObject = EventListener | EventListenerObject; +/** + * The **`EventTarget`** interface is implemented by objects that can receive events and may have listeners for them. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) + */ +declare class EventTarget = Record> { + constructor(); + /** + * The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) + */ + addEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetAddEventListenerOptions | boolean): void; + /** + * The **`removeEventListener()`** method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) + */ + removeEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetEventListenerOptions | boolean): void; + /** + * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) + */ + dispatchEvent(event: EventMap[keyof EventMap]): boolean; +} +interface EventTargetEventListenerOptions { + capture?: boolean; +} +interface EventTargetAddEventListenerOptions { + capture?: boolean; + passive?: boolean; + once?: boolean; + signal?: AbortSignal; +} +interface EventTargetHandlerObject { + handleEvent: (event: Event) => any | undefined; +} +/** + * The **`AbortController`** interface represents a controller object that allows you to abort one or more Web requests as and when desired. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController) + */ +declare class AbortController { + constructor(); + /** + * The **`signal`** read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal) + */ + get signal(): AbortSignal; + /** + * The **`abort()`** method of the AbortController interface aborts an asynchronous operation before it has completed. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort) + */ + abort(reason?: any): void; +} +/** + * The **`AbortSignal`** interface represents a signal object that allows you to communicate with an asynchronous operation (such as a fetch request) and abort it if required via an AbortController object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal) + */ +declare abstract class AbortSignal extends EventTarget { + /** + * The **`AbortSignal.abort()`** static method returns an AbortSignal that is already set as aborted (and which does not trigger an AbortSignal/abort_event event). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static) + */ + static abort(reason?: any): AbortSignal; + /** + * The **`AbortSignal.timeout()`** static method returns an AbortSignal that will automatically abort after a specified time. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/timeout_static) + */ + static timeout(delay: number): AbortSignal; + /** + * The **`AbortSignal.any()`** static method takes an iterable of abort signals and returns an AbortSignal. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static) + */ + static any(signals: AbortSignal[]): AbortSignal; + /** + * The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (`true`) or not (`false`). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted) + */ + get aborted(): boolean; + /** + * The **`reason`** read-only property returns a JavaScript value that indicates the abort reason. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/reason) + */ + get reason(): any; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ + get onabort(): any | null; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ + set onabort(value: any | null); + /** + * The **`throwIfAborted()`** method throws the signal's abort AbortSignal.reason if the signal has been aborted; otherwise it does nothing. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted) + */ + throwIfAborted(): void; +} +interface Scheduler { + wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise; +} +interface SchedulerWaitOptions { + signal?: AbortSignal; +} +/** + * The **`ExtendableEvent`** interface extends the lifetime of the `install` and `activate` events dispatched on the global scope as part of the service worker lifecycle. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent) + */ +declare abstract class ExtendableEvent extends Event { + /** + * The **`ExtendableEvent.waitUntil()`** method tells the event dispatcher that work is ongoing. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) + */ + waitUntil(promise: Promise): void; +} +/** + * The **`CustomEvent`** interface represents events initialized by an application for any purpose. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent) + */ +declare class CustomEvent extends Event { + constructor(type: string, init?: CustomEventCustomEventInit); + /** + * The read-only **`detail`** property of the CustomEvent interface returns any data passed when initializing the event. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent/detail) + */ + get detail(): T; +} +interface CustomEventCustomEventInit { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; + detail?: any; +} +/** + * The **`Blob`** interface represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data, or converted into a ReadableStream so its methods can be used for processing the data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob) + */ +declare class Blob { + constructor(type?: ((ArrayBuffer | ArrayBufferView) | string | Blob)[], options?: BlobOptions); + /** + * The **`size`** read-only property of the Blob interface returns the size of the Blob or File in bytes. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) + */ + get size(): number; + /** + * The **`type`** read-only property of the Blob interface returns the MIME type of the file. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) + */ + get type(): string; + /** + * The **`slice()`** method of the Blob interface creates and returns a new `Blob` object which contains data from a subset of the blob on which it's called. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) + */ + slice(start?: number, end?: number, type?: string): Blob; + /** + * The **`arrayBuffer()`** method of the Blob interface returns a Promise that resolves with the contents of the blob as binary data contained in an ArrayBuffer. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/arrayBuffer) + */ + arrayBuffer(): Promise; + /** + * The **`bytes()`** method of the Blob interface returns a Promise that resolves with a Uint8Array containing the contents of the blob as an array of bytes. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/bytes) + */ + bytes(): Promise; + /** + * The **`text()`** method of the string containing the contents of the blob, interpreted as UTF-8. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) + */ + text(): Promise; + /** + * The **`stream()`** method of the Blob interface returns a ReadableStream which upon reading returns the data contained within the `Blob`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream) + */ + stream(): ReadableStream; +} +interface BlobOptions { + type?: string; +} +/** + * The **`File`** interface provides information about files and allows JavaScript in a web page to access their content. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File) + */ +declare class File extends Blob { + constructor(bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, name: string, options?: FileOptions); + /** + * The **`name`** read-only property of the File interface returns the name of the file represented by a File object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) + */ + get name(): string; + /** + * The **`lastModified`** read-only property of the File interface provides the last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) + */ + get lastModified(): number; +} +interface FileOptions { + type?: string; + lastModified?: number; +} +/** +* The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) +*/ +declare abstract class CacheStorage { + /** + * The **`open()`** method of the the Cache object matching the `cacheName`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open) + */ + open(cacheName: string): Promise; + readonly default: Cache; +} +/** +* The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) +*/ +declare abstract class Cache { + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#delete) */ + delete(request: RequestInfo | URL, options?: CacheQueryOptions): Promise; + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#match) */ + match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise; + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#put) */ + put(request: RequestInfo | URL, response: Response): Promise; +} +interface CacheQueryOptions { + ignoreMethod?: boolean; +} +/** +* The Web Crypto API provides a set of low-level functions for common cryptographic tasks. +* The Workers runtime implements the full surface of this API, but with some differences in +* the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms) +* compared to those implemented in most browsers. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/) +*/ +declare abstract class Crypto { + /** + * The **`Crypto.subtle`** read-only property returns a cryptographic operations. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle) + */ + get subtle(): SubtleCrypto; + /** + * The **`Crypto.getRandomValues()`** method lets you get cryptographically strong random values. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) + */ + getRandomValues(buffer: T): T; + /** + * The **`randomUUID()`** method of the Crypto interface is used to generate a v4 UUID using a cryptographically secure random number generator. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID) + */ + randomUUID(): string; + DigestStream: typeof DigestStream; +} +/** + * The **`SubtleCrypto`** interface of the Web Crypto API provides a number of low-level cryptographic functions. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto) + */ +declare abstract class SubtleCrypto { + /** + * The **`encrypt()`** method of the SubtleCrypto interface encrypts data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/encrypt) + */ + encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView): Promise; + /** + * The **`decrypt()`** method of the SubtleCrypto interface decrypts some encrypted data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt) + */ + decrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, cipherText: ArrayBuffer | ArrayBufferView): Promise; + /** + * The **`sign()`** method of the SubtleCrypto interface generates a digital signature. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/sign) + */ + sign(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, data: ArrayBuffer | ArrayBufferView): Promise; + /** + * The **`verify()`** method of the SubtleCrypto interface verifies a digital signature. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/verify) + */ + verify(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, signature: ArrayBuffer | ArrayBufferView, data: ArrayBuffer | ArrayBufferView): Promise; + /** + * The **`digest()`** method of the SubtleCrypto interface generates a _digest_ of the given data, using the specified hash function. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest) + */ + digest(algorithm: string | SubtleCryptoHashAlgorithm, data: ArrayBuffer | ArrayBufferView): Promise; + /** + * The **`generateKey()`** method of the SubtleCrypto interface is used to generate a new key (for symmetric algorithms) or key pair (for public-key algorithms). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/generateKey) + */ + generateKey(algorithm: string | SubtleCryptoGenerateKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise; + /** + * The **`deriveKey()`** method of the SubtleCrypto interface can be used to derive a secret key from a master key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveKey) + */ + deriveKey(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise; + /** + * The **`deriveBits()`** method of the key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits) + */ + deriveBits(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, length?: number | null): Promise; + /** + * The **`importKey()`** method of the SubtleCrypto interface imports a key: that is, it takes as input a key in an external, portable format and gives you a CryptoKey object that you can use in the Web Crypto API. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/importKey) + */ + importKey(format: string, keyData: (ArrayBuffer | ArrayBufferView) | JsonWebKey, algorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise; + /** + * The **`exportKey()`** method of the SubtleCrypto interface exports a key: that is, it takes as input a CryptoKey object and gives you the key in an external, portable format. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/exportKey) + */ + exportKey(format: string, key: CryptoKey): Promise; + /** + * The **`wrapKey()`** method of the SubtleCrypto interface 'wraps' a key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey) + */ + wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm): Promise; + /** + * The **`unwrapKey()`** method of the SubtleCrypto interface 'unwraps' a key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey) + */ + unwrapKey(format: string, wrappedKey: ArrayBuffer | ArrayBufferView, unwrappingKey: CryptoKey, unwrapAlgorithm: string | SubtleCryptoEncryptAlgorithm, unwrappedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise; + timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean; +} +/** + * The **`CryptoKey`** interface of the Web Crypto API represents a cryptographic key obtained from one of the SubtleCrypto methods SubtleCrypto.generateKey, SubtleCrypto.deriveKey, SubtleCrypto.importKey, or SubtleCrypto.unwrapKey. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey) + */ +declare abstract class CryptoKey { + /** + * The read-only **`type`** property of the CryptoKey interface indicates which kind of key is represented by the object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type) + */ + readonly type: string; + /** + * The read-only **`extractable`** property of the CryptoKey interface indicates whether or not the key may be extracted using `SubtleCrypto.exportKey()` or `SubtleCrypto.wrapKey()`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable) + */ + readonly extractable: boolean; + /** + * The read-only **`algorithm`** property of the CryptoKey interface returns an object describing the algorithm for which this key can be used, and any associated extra parameters. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/algorithm) + */ + readonly algorithm: CryptoKeyKeyAlgorithm | CryptoKeyAesKeyAlgorithm | CryptoKeyHmacKeyAlgorithm | CryptoKeyRsaKeyAlgorithm | CryptoKeyEllipticKeyAlgorithm | CryptoKeyArbitraryKeyAlgorithm; + /** + * The read-only **`usages`** property of the CryptoKey interface indicates what can be done with the key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/usages) + */ + readonly usages: string[]; +} +interface CryptoKeyPair { + publicKey: CryptoKey; + privateKey: CryptoKey; +} +interface JsonWebKey { + kty: string; + use?: string; + key_ops?: string[]; + alg?: string; + ext?: boolean; + crv?: string; + x?: string; + y?: string; + d?: string; + n?: string; + e?: string; + p?: string; + q?: string; + dp?: string; + dq?: string; + qi?: string; + oth?: RsaOtherPrimesInfo[]; + k?: string; +} +interface RsaOtherPrimesInfo { + r?: string; + d?: string; + t?: string; +} +interface SubtleCryptoDeriveKeyAlgorithm { + name: string; + salt?: (ArrayBuffer | ArrayBufferView); + iterations?: number; + hash?: (string | SubtleCryptoHashAlgorithm); + $public?: CryptoKey; + info?: (ArrayBuffer | ArrayBufferView); +} +interface SubtleCryptoEncryptAlgorithm { + name: string; + iv?: (ArrayBuffer | ArrayBufferView); + additionalData?: (ArrayBuffer | ArrayBufferView); + tagLength?: number; + counter?: (ArrayBuffer | ArrayBufferView); + length?: number; + label?: (ArrayBuffer | ArrayBufferView); +} +interface SubtleCryptoGenerateKeyAlgorithm { + name: string; + hash?: (string | SubtleCryptoHashAlgorithm); + modulusLength?: number; + publicExponent?: (ArrayBuffer | ArrayBufferView); + length?: number; + namedCurve?: string; +} +interface SubtleCryptoHashAlgorithm { + name: string; +} +interface SubtleCryptoImportKeyAlgorithm { + name: string; + hash?: (string | SubtleCryptoHashAlgorithm); + length?: number; + namedCurve?: string; + compressed?: boolean; +} +interface SubtleCryptoSignAlgorithm { + name: string; + hash?: (string | SubtleCryptoHashAlgorithm); + dataLength?: number; + saltLength?: number; +} +interface CryptoKeyKeyAlgorithm { + name: string; +} +interface CryptoKeyAesKeyAlgorithm { + name: string; + length: number; +} +interface CryptoKeyHmacKeyAlgorithm { + name: string; + hash: CryptoKeyKeyAlgorithm; + length: number; +} +interface CryptoKeyRsaKeyAlgorithm { + name: string; + modulusLength: number; + publicExponent: ArrayBuffer | ArrayBufferView; + hash?: CryptoKeyKeyAlgorithm; +} +interface CryptoKeyEllipticKeyAlgorithm { + name: string; + namedCurve: string; +} +interface CryptoKeyArbitraryKeyAlgorithm { + name: string; + hash?: CryptoKeyKeyAlgorithm; + namedCurve?: string; + length?: number; +} +declare class DigestStream extends WritableStream { + constructor(algorithm: string | SubtleCryptoHashAlgorithm); + readonly digest: Promise; + get bytesWritten(): number | bigint; +} +/** + * The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as `UTF-8`, `ISO-8859-2`, `KOI8-R`, `GBK`, etc. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder) + */ +declare class TextDecoder { + constructor(label?: string, options?: TextDecoderConstructorOptions); + /** + * The **`TextDecoder.decode()`** method returns a string containing text decoded from the buffer passed as a parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/decode) + */ + decode(input?: (ArrayBuffer | ArrayBufferView), options?: TextDecoderDecodeOptions): string; + get encoding(): string; + get fatal(): boolean; + get ignoreBOM(): boolean; +} +/** + * The **`TextEncoder`** interface takes a stream of code points as input and emits a stream of UTF-8 bytes. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder) + */ +declare class TextEncoder { + constructor(); + /** + * The **`TextEncoder.encode()`** method takes a string as input, and returns a Global_Objects/Uint8Array containing the text given in parameters encoded with the specific method for that TextEncoder object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode) + */ + encode(input?: string): Uint8Array; + /** + * The **`TextEncoder.encodeInto()`** method takes a string to encode and a destination Uint8Array to put resulting UTF-8 encoded text into, and returns a dictionary object indicating the progress of the encoding. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto) + */ + encodeInto(input: string, buffer: Uint8Array): TextEncoderEncodeIntoResult; + get encoding(): string; +} +interface TextDecoderConstructorOptions { + fatal: boolean; + ignoreBOM: boolean; +} +interface TextDecoderDecodeOptions { + stream: boolean; +} +interface TextEncoderEncodeIntoResult { + read: number; + written: number; +} +/** + * The **`ErrorEvent`** interface represents events providing information related to errors in scripts or in files. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent) + */ +declare class ErrorEvent extends Event { + constructor(type: string, init?: ErrorEventErrorEventInit); + /** + * The **`filename`** read-only property of the ErrorEvent interface returns a string containing the name of the script file in which the error occurred. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/filename) + */ + get filename(): string; + /** + * The **`message`** read-only property of the ErrorEvent interface returns a string containing a human-readable error message describing the problem. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/message) + */ + get message(): string; + /** + * The **`lineno`** read-only property of the ErrorEvent interface returns an integer containing the line number of the script file on which the error occurred. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/lineno) + */ + get lineno(): number; + /** + * The **`colno`** read-only property of the ErrorEvent interface returns an integer containing the column number of the script file on which the error occurred. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/colno) + */ + get colno(): number; + /** + * The **`error`** read-only property of the ErrorEvent interface returns a JavaScript value, such as an Error or DOMException, representing the error associated with this event. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/error) + */ + get error(): any; +} +interface ErrorEventErrorEventInit { + message?: string; + filename?: string; + lineno?: number; + colno?: number; + error?: any; +} +/** + * The **`MessageEvent`** interface represents a message received by a target object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent) + */ +declare class MessageEvent extends Event { + constructor(type: string, initializer: MessageEventInit); + /** + * The **`data`** read-only property of the The data sent by the message emitter; this can be any data type, depending on what originated this event. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data) + */ + readonly data: any; + /** + * The **`origin`** read-only property of the origin of the message emitter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin) + */ + readonly origin: string | null; + /** + * The **`lastEventId`** read-only property of the unique ID for the event. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId) + */ + readonly lastEventId: string; + /** + * The **`source`** read-only property of the a WindowProxy, MessagePort, or a `MessageEventSource` (which can be a WindowProxy, message emitter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source) + */ + readonly source: MessagePort | null; + /** + * The **`ports`** read-only property of the containing all MessagePort objects sent with the message, in order. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports) + */ + readonly ports: MessagePort[]; +} +interface MessageEventInit { + data: ArrayBuffer | string; +} +/** + * The **`PromiseRejectionEvent`** interface represents events which are sent to the global script context when JavaScript Promises are rejected. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) + */ +declare abstract class PromiseRejectionEvent extends Event { + /** + * The PromiseRejectionEvent interface's **`promise`** read-only property indicates the JavaScript rejected. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) + */ + readonly promise: Promise; + /** + * The PromiseRejectionEvent **`reason`** read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) + */ + readonly reason: any; +} +/** + * The **`FormData`** interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the Window/fetch, XMLHttpRequest.send() or navigator.sendBeacon() methods. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData) + */ +declare class FormData { + constructor(); + /** + * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) + */ + append(name: string, value: string): void; + /** + * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) + */ + append(name: string, value: Blob, filename?: string): void; + /** + * The **`delete()`** method of the FormData interface deletes a key and its value(s) from a `FormData` object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete) + */ + delete(name: string): void; + /** + * The **`get()`** method of the FormData interface returns the first value associated with a given key from within a `FormData` object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get) + */ + get(name: string): (File | string) | null; + /** + * The **`getAll()`** method of the FormData interface returns all the values associated with a given key from within a `FormData` object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll) + */ + getAll(name: string): (File | string)[]; + /** + * The **`has()`** method of the FormData interface returns whether a `FormData` object contains a certain key. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has) + */ + has(name: string): boolean; + /** + * The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) + */ + set(name: string, value: string): void; + /** + * The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) + */ + set(name: string, value: Blob, filename?: string): void; + /* Returns an array of key, value pairs for every entry in the list. */ + entries(): IterableIterator<[ + key: string, + value: File | string + ]>; + /* Returns a list of keys in the list. */ + keys(): IterableIterator; + /* Returns a list of values in the list. */ + values(): IterableIterator<(File | string)>; + forEach(callback: (this: This, value: File | string, key: string, parent: FormData) => void, thisArg?: This): void; + [Symbol.iterator](): IterableIterator<[ + key: string, + value: File | string + ]>; +} +interface ContentOptions { + html?: boolean; +} +declare class HTMLRewriter { + constructor(); + on(selector: string, handlers: HTMLRewriterElementContentHandlers): HTMLRewriter; + onDocument(handlers: HTMLRewriterDocumentContentHandlers): HTMLRewriter; + transform(response: Response): Response; +} +interface HTMLRewriterElementContentHandlers { + element?(element: Element): void | Promise; + comments?(comment: Comment): void | Promise; + text?(element: Text): void | Promise; +} +interface HTMLRewriterDocumentContentHandlers { + doctype?(doctype: Doctype): void | Promise; + comments?(comment: Comment): void | Promise; + text?(text: Text): void | Promise; + end?(end: DocumentEnd): void | Promise; +} +interface Doctype { + readonly name: string | null; + readonly publicId: string | null; + readonly systemId: string | null; +} +interface Element { + tagName: string; + readonly attributes: IterableIterator; + readonly removed: boolean; + readonly namespaceURI: string; + getAttribute(name: string): string | null; + hasAttribute(name: string): boolean; + setAttribute(name: string, value: string): Element; + removeAttribute(name: string): Element; + before(content: string | ReadableStream | Response, options?: ContentOptions): Element; + after(content: string | ReadableStream | Response, options?: ContentOptions): Element; + prepend(content: string | ReadableStream | Response, options?: ContentOptions): Element; + append(content: string | ReadableStream | Response, options?: ContentOptions): Element; + replace(content: string | ReadableStream | Response, options?: ContentOptions): Element; + remove(): Element; + removeAndKeepContent(): Element; + setInnerContent(content: string | ReadableStream | Response, options?: ContentOptions): Element; + onEndTag(handler: (tag: EndTag) => void | Promise): void; +} +interface EndTag { + name: string; + before(content: string | ReadableStream | Response, options?: ContentOptions): EndTag; + after(content: string | ReadableStream | Response, options?: ContentOptions): EndTag; + remove(): EndTag; +} +interface Comment { + text: string; + readonly removed: boolean; + before(content: string, options?: ContentOptions): Comment; + after(content: string, options?: ContentOptions): Comment; + replace(content: string, options?: ContentOptions): Comment; + remove(): Comment; +} +interface Text { + readonly text: string; + readonly lastInTextNode: boolean; + readonly removed: boolean; + before(content: string | ReadableStream | Response, options?: ContentOptions): Text; + after(content: string | ReadableStream | Response, options?: ContentOptions): Text; + replace(content: string | ReadableStream | Response, options?: ContentOptions): Text; + remove(): Text; +} +interface DocumentEnd { + append(content: string, options?: ContentOptions): DocumentEnd; +} +/** + * This is the event type for `fetch` events dispatched on the ServiceWorkerGlobalScope. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent) + */ +declare abstract class FetchEvent extends ExtendableEvent { + /** + * The **`request`** read-only property of the the event handler. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request) + */ + readonly request: Request; + /** + * The **`respondWith()`** method of allows you to provide a promise for a Response yourself. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) + */ + respondWith(promise: Response | Promise): void; + passThroughOnException(): void; +} +type HeadersInit = Headers | Iterable> | Record; +/** + * The **`Headers`** interface of the Fetch API allows you to perform various actions on HTTP request and response headers. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers) + */ +declare class Headers { + constructor(init?: HeadersInit); + /** + * The **`get()`** method of the Headers interface returns a byte string of all the values of a header within a `Headers` object with a given name. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get) + */ + get(name: string): string | null; + getAll(name: string): string[]; + /** + * The **`getSetCookie()`** method of the Headers interface returns an array containing the values of all Set-Cookie headers associated with a response. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie) + */ + getSetCookie(): string[]; + /** + * The **`has()`** method of the Headers interface returns a boolean stating whether a `Headers` object contains a certain header. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has) + */ + has(name: string): boolean; + /** + * The **`set()`** method of the Headers interface sets a new value for an existing header inside a `Headers` object, or adds the header if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set) + */ + set(name: string, value: string): void; + /** + * The **`append()`** method of the Headers interface appends a new value onto an existing header inside a `Headers` object, or adds the header if it does not already exist. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append) + */ + append(name: string, value: string): void; + /** + * The **`delete()`** method of the Headers interface deletes a header from the current `Headers` object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete) + */ + delete(name: string): void; + forEach(callback: (this: This, value: string, key: string, parent: Headers) => void, thisArg?: This): void; + /* Returns an iterator allowing to go through all key/value pairs contained in this object. */ + entries(): IterableIterator<[ + key: string, + value: string + ]>; + /* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object. */ + keys(): IterableIterator; + /* Returns an iterator allowing to go through all values of the key/value pairs contained in this object. */ + values(): IterableIterator; + [Symbol.iterator](): IterableIterator<[ + key: string, + value: string + ]>; +} +type BodyInit = ReadableStream | string | ArrayBuffer | ArrayBufferView | Blob | URLSearchParams | FormData | Iterable | AsyncIterable; +declare abstract class Body { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */ + get body(): ReadableStream | null; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bodyUsed) */ + get bodyUsed(): boolean; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/arrayBuffer) */ + arrayBuffer(): Promise; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bytes) */ + bytes(): Promise; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/text) */ + text(): Promise; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */ + json(): Promise; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/formData) */ + formData(): Promise; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob) */ + blob(): Promise; +} +/** + * The **`Response`** interface of the Fetch API represents the response to a request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response) + */ +declare var Response: { + prototype: Response; + new (body?: BodyInit | null, init?: ResponseInit): Response; + error(): Response; + redirect(url: string, status?: number): Response; + json(any: any, maybeInit?: (ResponseInit | Response)): Response; +}; +/** + * The **`Response`** interface of the Fetch API represents the response to a request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response) + */ +interface Response extends Body { + /** + * The **`clone()`** method of the Response interface creates a clone of a response object, identical in every way, but stored in a different variable. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/clone) + */ + clone(): Response; + /** + * The **`status`** read-only property of the Response interface contains the HTTP status codes of the response. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/status) + */ + status: number; + /** + * The **`statusText`** read-only property of the Response interface contains the status message corresponding to the HTTP status code in Response.status. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/statusText) + */ + statusText: string; + /** + * The **`headers`** read-only property of the with the response. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) + */ + headers: Headers; + /** + * The **`ok`** read-only property of the Response interface contains a Boolean stating whether the response was successful (status in the range 200-299) or not. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/ok) + */ + ok: boolean; + /** + * The **`redirected`** read-only property of the Response interface indicates whether or not the response is the result of a request you made which was redirected. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/redirected) + */ + redirected: boolean; + /** + * The **`url`** read-only property of the Response interface contains the URL of the response. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url) + */ + url: string; + webSocket: WebSocket | null; + cf: any | undefined; + /** + * The **`type`** read-only property of the Response interface contains the type of the response. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type) + */ + type: "default" | "error"; +} +interface ResponseInit { + status?: number; + statusText?: string; + headers?: HeadersInit; + cf?: any; + webSocket?: (WebSocket | null); + encodeBody?: "automatic" | "manual"; +} +type RequestInfo> = Request | string; +/** + * The **`Request`** interface of the Fetch API represents a resource request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request) + */ +declare var Request: { + prototype: Request; + new >(input: RequestInfo | URL, init?: RequestInit): Request; +}; +/** + * The **`Request`** interface of the Fetch API represents a resource request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request) + */ +interface Request> extends Body { + /** + * The **`clone()`** method of the Request interface creates a copy of the current `Request` object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone) + */ + clone(): Request; + /** + * The **`method`** read-only property of the `POST`, etc.) A String indicating the method of the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method) + */ + method: string; + /** + * The **`url`** read-only property of the Request interface contains the URL of the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/url) + */ + url: string; + /** + * The **`headers`** read-only property of the with the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers) + */ + headers: Headers; + /** + * The **`redirect`** read-only property of the Request interface contains the mode for how redirects are handled. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/redirect) + */ + redirect: string; + fetcher: Fetcher | null; + /** + * The read-only **`signal`** property of the Request interface returns the AbortSignal associated with the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/signal) + */ + signal: AbortSignal; + cf: Cf | undefined; + /** + * The **`integrity`** read-only property of the Request interface contains the subresource integrity value of the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/integrity) + */ + integrity: string; + /** + * The **`keepalive`** read-only property of the Request interface contains the request's `keepalive` setting (`true` or `false`), which indicates whether the browser will keep the associated request alive if the page that initiated it is unloaded before the request is complete. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive) + */ + keepalive: boolean; + /** + * The **`cache`** read-only property of the Request interface contains the cache mode of the request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache) + */ + cache?: "no-store" | "no-cache"; +} +interface RequestInit { + /* A string to set request's method. */ + method?: string; + /* A Headers object, an object literal, or an array of two-item arrays to set request's headers. */ + headers?: HeadersInit; + /* A BodyInit object or null to set request's body. */ + body?: BodyInit | null; + /* A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */ + redirect?: string; + fetcher?: (Fetcher | null); + cf?: Cf; + /* A string indicating how the request will interact with the browser's cache to set request's cache. */ + cache?: "no-store" | "no-cache"; + /* A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */ + integrity?: string; + /* An AbortSignal to set request's signal. */ + signal?: (AbortSignal | null); + encodeResponseBody?: "automatic" | "manual"; +} +type Service Rpc.WorkerEntrypointBranded) | Rpc.WorkerEntrypointBranded | ExportedHandler | undefined = undefined> = T extends new (...args: any[]) => Rpc.WorkerEntrypointBranded ? Fetcher> : T extends Rpc.WorkerEntrypointBranded ? Fetcher : T extends Exclude ? never : Fetcher; +type Fetcher = (T extends Rpc.EntrypointBranded ? Rpc.Provider : unknown) & { + fetch(input: RequestInfo | URL, init?: RequestInit): Promise; + connect(address: SocketAddress | string, options?: SocketOptions): Socket; +}; +interface KVNamespaceListKey { + name: Key; + expiration?: number; + metadata?: Metadata; +} +type KVNamespaceListResult = { + list_complete: false; + keys: KVNamespaceListKey[]; + cursor: string; + cacheStatus: string | null; +} | { + list_complete: true; + keys: KVNamespaceListKey[]; + cacheStatus: string | null; +}; +interface KVNamespace { + get(key: Key, options?: Partial>): Promise; + get(key: Key, type: "text"): Promise; + get(key: Key, type: "json"): Promise; + get(key: Key, type: "arrayBuffer"): Promise; + get(key: Key, type: "stream"): Promise; + get(key: Key, options?: KVNamespaceGetOptions<"text">): Promise; + get(key: Key, options?: KVNamespaceGetOptions<"json">): Promise; + get(key: Key, options?: KVNamespaceGetOptions<"arrayBuffer">): Promise; + get(key: Key, options?: KVNamespaceGetOptions<"stream">): Promise; + get(key: Array, type: "text"): Promise>; + get(key: Array, type: "json"): Promise>; + get(key: Array, options?: Partial>): Promise>; + get(key: Array, options?: KVNamespaceGetOptions<"text">): Promise>; + get(key: Array, options?: KVNamespaceGetOptions<"json">): Promise>; + list(options?: KVNamespaceListOptions): Promise>; + put(key: Key, value: string | ArrayBuffer | ArrayBufferView | ReadableStream, options?: KVNamespacePutOptions): Promise; + getWithMetadata(key: Key, options?: Partial>): Promise>; + getWithMetadata(key: Key, type: "text"): Promise>; + getWithMetadata(key: Key, type: "json"): Promise>; + getWithMetadata(key: Key, type: "arrayBuffer"): Promise>; + getWithMetadata(key: Key, type: "stream"): Promise>; + getWithMetadata(key: Key, options: KVNamespaceGetOptions<"text">): Promise>; + getWithMetadata(key: Key, options: KVNamespaceGetOptions<"json">): Promise>; + getWithMetadata(key: Key, options: KVNamespaceGetOptions<"arrayBuffer">): Promise>; + getWithMetadata(key: Key, options: KVNamespaceGetOptions<"stream">): Promise>; + getWithMetadata(key: Array, type: "text"): Promise>>; + getWithMetadata(key: Array, type: "json"): Promise>>; + getWithMetadata(key: Array, options?: Partial>): Promise>>; + getWithMetadata(key: Array, options?: KVNamespaceGetOptions<"text">): Promise>>; + getWithMetadata(key: Array, options?: KVNamespaceGetOptions<"json">): Promise>>; + delete(key: Key): Promise; +} +interface KVNamespaceListOptions { + limit?: number; + prefix?: (string | null); + cursor?: (string | null); +} +interface KVNamespaceGetOptions { + type: Type; + cacheTtl?: number; +} +interface KVNamespacePutOptions { + expiration?: number; + expirationTtl?: number; + metadata?: (any | null); +} +interface KVNamespaceGetWithMetadataResult { + value: Value | null; + metadata: Metadata | null; + cacheStatus: string | null; +} +type QueueContentType = "text" | "bytes" | "json" | "v8"; +interface Queue { + send(message: Body, options?: QueueSendOptions): Promise; + sendBatch(messages: Iterable>, options?: QueueSendBatchOptions): Promise; +} +interface QueueSendOptions { + contentType?: QueueContentType; + delaySeconds?: number; +} +interface QueueSendBatchOptions { + delaySeconds?: number; +} +interface MessageSendRequest { + body: Body; + contentType?: QueueContentType; + delaySeconds?: number; +} +interface QueueRetryOptions { + delaySeconds?: number; +} +interface Message { + readonly id: string; + readonly timestamp: Date; + readonly body: Body; + readonly attempts: number; + retry(options?: QueueRetryOptions): void; + ack(): void; +} +interface QueueEvent extends ExtendableEvent { + readonly messages: readonly Message[]; + readonly queue: string; + retryAll(options?: QueueRetryOptions): void; + ackAll(): void; +} +interface MessageBatch { + readonly messages: readonly Message[]; + readonly queue: string; + retryAll(options?: QueueRetryOptions): void; + ackAll(): void; +} +interface R2Error extends Error { + readonly name: string; + readonly code: number; + readonly message: string; + readonly action: string; + readonly stack: any; +} +interface R2ListOptions { + limit?: number; + prefix?: string; + cursor?: string; + delimiter?: string; + startAfter?: string; + include?: ("httpMetadata" | "customMetadata")[]; +} +declare abstract class R2Bucket { + head(key: string): Promise; + get(key: string, options: R2GetOptions & { + onlyIf: R2Conditional | Headers; + }): Promise; + get(key: string, options?: R2GetOptions): Promise; + put(key: string, value: ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob, options?: R2PutOptions & { + onlyIf: R2Conditional | Headers; + }): Promise; + put(key: string, value: ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob, options?: R2PutOptions): Promise; + createMultipartUpload(key: string, options?: R2MultipartOptions): Promise; + resumeMultipartUpload(key: string, uploadId: string): R2MultipartUpload; + delete(keys: string | string[]): Promise; + list(options?: R2ListOptions): Promise; +} +interface R2MultipartUpload { + readonly key: string; + readonly uploadId: string; + uploadPart(partNumber: number, value: ReadableStream | (ArrayBuffer | ArrayBufferView) | string | Blob, options?: R2UploadPartOptions): Promise; + abort(): Promise; + complete(uploadedParts: R2UploadedPart[]): Promise; +} +interface R2UploadedPart { + partNumber: number; + etag: string; +} +declare abstract class R2Object { + readonly key: string; + readonly version: string; + readonly size: number; + readonly etag: string; + readonly httpEtag: string; + readonly checksums: R2Checksums; + readonly uploaded: Date; + readonly httpMetadata?: R2HTTPMetadata; + readonly customMetadata?: Record; + readonly range?: R2Range; + readonly storageClass: string; + readonly ssecKeyMd5?: string; + writeHttpMetadata(headers: Headers): void; +} +interface R2ObjectBody extends R2Object { + get body(): ReadableStream; + get bodyUsed(): boolean; + arrayBuffer(): Promise; + bytes(): Promise; + text(): Promise; + json(): Promise; + blob(): Promise; +} +type R2Range = { + offset: number; + length?: number; +} | { + offset?: number; + length: number; +} | { + suffix: number; +}; +interface R2Conditional { + etagMatches?: string; + etagDoesNotMatch?: string; + uploadedBefore?: Date; + uploadedAfter?: Date; + secondsGranularity?: boolean; +} +interface R2GetOptions { + onlyIf?: (R2Conditional | Headers); + range?: (R2Range | Headers); + ssecKey?: (ArrayBuffer | string); +} +interface R2PutOptions { + onlyIf?: (R2Conditional | Headers); + httpMetadata?: (R2HTTPMetadata | Headers); + customMetadata?: Record; + md5?: ((ArrayBuffer | ArrayBufferView) | string); + sha1?: ((ArrayBuffer | ArrayBufferView) | string); + sha256?: ((ArrayBuffer | ArrayBufferView) | string); + sha384?: ((ArrayBuffer | ArrayBufferView) | string); + sha512?: ((ArrayBuffer | ArrayBufferView) | string); + storageClass?: string; + ssecKey?: (ArrayBuffer | string); +} +interface R2MultipartOptions { + httpMetadata?: (R2HTTPMetadata | Headers); + customMetadata?: Record; + storageClass?: string; + ssecKey?: (ArrayBuffer | string); +} +interface R2Checksums { + readonly md5?: ArrayBuffer; + readonly sha1?: ArrayBuffer; + readonly sha256?: ArrayBuffer; + readonly sha384?: ArrayBuffer; + readonly sha512?: ArrayBuffer; + toJSON(): R2StringChecksums; +} +interface R2StringChecksums { + md5?: string; + sha1?: string; + sha256?: string; + sha384?: string; + sha512?: string; +} +interface R2HTTPMetadata { + contentType?: string; + contentLanguage?: string; + contentDisposition?: string; + contentEncoding?: string; + cacheControl?: string; + cacheExpiry?: Date; +} +type R2Objects = { + objects: R2Object[]; + delimitedPrefixes: string[]; +} & ({ + truncated: true; + cursor: string; +} | { + truncated: false; +}); +interface R2UploadPartOptions { + ssecKey?: (ArrayBuffer | string); +} +declare abstract class ScheduledEvent extends ExtendableEvent { + readonly scheduledTime: number; + readonly cron: string; + noRetry(): void; +} +interface ScheduledController { + readonly scheduledTime: number; + readonly cron: string; + noRetry(): void; +} +interface QueuingStrategy { + highWaterMark?: (number | bigint); + size?: (chunk: T) => number | bigint; +} +interface UnderlyingSink { + type?: string; + start?: (controller: WritableStreamDefaultController) => void | Promise; + write?: (chunk: W, controller: WritableStreamDefaultController) => void | Promise; + abort?: (reason: any) => void | Promise; + close?: () => void | Promise; +} +interface UnderlyingByteSource { + type: "bytes"; + autoAllocateChunkSize?: number; + start?: (controller: ReadableByteStreamController) => void | Promise; + pull?: (controller: ReadableByteStreamController) => void | Promise; + cancel?: (reason: any) => void | Promise; +} +interface UnderlyingSource { + type?: "" | undefined; + start?: (controller: ReadableStreamDefaultController) => void | Promise; + pull?: (controller: ReadableStreamDefaultController) => void | Promise; + cancel?: (reason: any) => void | Promise; + expectedLength?: (number | bigint); +} +interface Transformer { + readableType?: string; + writableType?: string; + start?: (controller: TransformStreamDefaultController) => void | Promise; + transform?: (chunk: I, controller: TransformStreamDefaultController) => void | Promise; + flush?: (controller: TransformStreamDefaultController) => void | Promise; + cancel?: (reason: any) => void | Promise; + expectedLength?: number; +} +interface StreamPipeOptions { + /** + * Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + * + * Errors and closures of the source and destination streams propagate as follows: + * + * An error in this source readable stream will abort destination, unless preventAbort is truthy. The returned promise will be rejected with the source's error, or with any error that occurs during aborting the destination. + * + * An error in destination will cancel this source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination's error, or with any error that occurs during canceling the source. + * + * When this source readable stream closes, destination will be closed, unless preventClose is truthy. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error. + * + * If destination starts out closed or closing, this source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source. + * + * The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set. + */ + preventClose?: boolean; + preventAbort?: boolean; + preventCancel?: boolean; + signal?: AbortSignal; +} +type ReadableStreamReadResult = { + done: false; + value: R; +} | { + done: true; + value?: undefined; +}; +/** + * The `ReadableStream` interface of the Streams API represents a readable stream of byte data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) + */ +interface ReadableStream { + /** + * The **`locked`** read-only property of the ReadableStream interface returns whether or not the readable stream is locked to a reader. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/locked) + */ + get locked(): boolean; + /** + * The **`cancel()`** method of the ReadableStream interface returns a Promise that resolves when the stream is canceled. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/cancel) + */ + cancel(reason?: any): Promise; + /** + * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) + */ + getReader(): ReadableStreamDefaultReader; + /** + * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) + */ + getReader(options: ReadableStreamGetReaderOptions): ReadableStreamBYOBReader; + /** + * The **`pipeThrough()`** method of the ReadableStream interface provides a chainable way of piping the current stream through a transform stream or any other writable/readable pair. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeThrough) + */ + pipeThrough(transform: ReadableWritablePair, options?: StreamPipeOptions): ReadableStream; + /** + * The **`pipeTo()`** method of the ReadableStream interface pipes the current `ReadableStream` to a given WritableStream and returns a Promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo) + */ + pipeTo(destination: WritableStream, options?: StreamPipeOptions): Promise; + /** + * The **`tee()`** method of the two-element array containing the two resulting branches as new ReadableStream instances. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee) + */ + tee(): [ + ReadableStream, + ReadableStream + ]; + values(options?: ReadableStreamValuesOptions): AsyncIterableIterator; + [Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator; +} +/** + * The `ReadableStream` interface of the Streams API represents a readable stream of byte data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) + */ +declare const ReadableStream: { + prototype: ReadableStream; + new (underlyingSource: UnderlyingByteSource, strategy?: QueuingStrategy): ReadableStream; + new (underlyingSource?: UnderlyingSource, strategy?: QueuingStrategy): ReadableStream; +}; +/** + * The **`ReadableStreamDefaultReader`** interface of the Streams API represents a default reader that can be used to read stream data supplied from a network (such as a fetch request). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader) + */ +declare class ReadableStreamDefaultReader { + constructor(stream: ReadableStream); + get closed(): Promise; + cancel(reason?: any): Promise; + /** + * The **`read()`** method of the ReadableStreamDefaultReader interface returns a Promise providing access to the next chunk in the stream's internal queue. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader/read) + */ + read(): Promise>; + /** + * The **`releaseLock()`** method of the ReadableStreamDefaultReader interface releases the reader's lock on the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader/releaseLock) + */ + releaseLock(): void; +} +/** + * The `ReadableStreamBYOBReader` interface of the Streams API defines a reader for a ReadableStream that supports zero-copy reading from an underlying byte source. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) + */ +declare class ReadableStreamBYOBReader { + constructor(stream: ReadableStream); + get closed(): Promise; + cancel(reason?: any): Promise; + /** + * The **`read()`** method of the ReadableStreamBYOBReader interface is used to read data into a view on a user-supplied buffer from an associated readable byte stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read) + */ + read(view: T): Promise>; + /** + * The **`releaseLock()`** method of the ReadableStreamBYOBReader interface releases the reader's lock on the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock) + */ + releaseLock(): void; + readAtLeast(minElements: number, view: T): Promise>; +} +interface ReadableStreamBYOBReaderReadableStreamBYOBReaderReadOptions { + min?: number; +} +interface ReadableStreamGetReaderOptions { + /** + * Creates a ReadableStreamBYOBReader and locks the stream to the new reader. + * + * This call behaves the same way as the no-argument variant, except that it only works on readable byte streams, i.e. streams which were constructed specifically with the ability to handle "bring your own buffer" reading. The returned BYOB reader provides the ability to directly read individual chunks from the stream via its read() method, into developer-supplied buffers, allowing more precise control over allocation. + */ + mode: "byob"; +} +/** + * The **`ReadableStreamBYOBRequest`** interface of the Streams API represents a 'pull request' for data from an underlying source that will made as a zero-copy transfer to a consumer (bypassing the stream's internal queues). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest) + */ +declare abstract class ReadableStreamBYOBRequest { + /** + * The **`view`** getter property of the ReadableStreamBYOBRequest interface returns the current view. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/view) + */ + get view(): Uint8Array | null; + /** + * The **`respond()`** method of the ReadableStreamBYOBRequest interface is used to signal to the associated readable byte stream that the specified number of bytes were written into the ReadableStreamBYOBRequest.view. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respond) + */ + respond(bytesWritten: number): void; + /** + * The **`respondWithNewView()`** method of the ReadableStreamBYOBRequest interface specifies a new view that the consumer of the associated readable byte stream should write to instead of ReadableStreamBYOBRequest.view. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respondWithNewView) + */ + respondWithNewView(view: ArrayBuffer | ArrayBufferView): void; + get atLeast(): number | null; +} +/** + * The **`ReadableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a ReadableStream's state and internal queue. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController) + */ +declare abstract class ReadableStreamDefaultController { + /** + * The **`desiredSize`** read-only property of the required to fill the stream's internal queue. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize) + */ + get desiredSize(): number | null; + /** + * The **`close()`** method of the ReadableStreamDefaultController interface closes the associated stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/close) + */ + close(): void; + /** + * The **`enqueue()`** method of the ```js-nolint enqueue(chunk) ``` - `chunk` - : The chunk to enqueue. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue) + */ + enqueue(chunk?: R): void; + /** + * The **`error()`** method of the with the associated stream to error. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error) + */ + error(reason: any): void; +} +/** + * The **`ReadableByteStreamController`** interface of the Streams API represents a controller for a readable byte stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController) + */ +declare abstract class ReadableByteStreamController { + /** + * The **`byobRequest`** read-only property of the ReadableByteStreamController interface returns the current BYOB request, or `null` if there are no pending requests. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest) + */ + get byobRequest(): ReadableStreamBYOBRequest | null; + /** + * The **`desiredSize`** read-only property of the ReadableByteStreamController interface returns the number of bytes required to fill the stream's internal queue to its 'desired size'. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize) + */ + get desiredSize(): number | null; + /** + * The **`close()`** method of the ReadableByteStreamController interface closes the associated stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/close) + */ + close(): void; + /** + * The **`enqueue()`** method of the ReadableByteStreamController interface enqueues a given chunk on the associated readable byte stream (the chunk is copied into the stream's internal queues). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue) + */ + enqueue(chunk: ArrayBuffer | ArrayBufferView): void; + /** + * The **`error()`** method of the ReadableByteStreamController interface causes any future interactions with the associated stream to error with the specified reason. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/error) + */ + error(reason: any): void; +} +/** + * The **`WritableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a WritableStream's state. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController) + */ +declare abstract class WritableStreamDefaultController { + /** + * The read-only **`signal`** property of the WritableStreamDefaultController interface returns the AbortSignal associated with the controller. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/signal) + */ + get signal(): AbortSignal; + /** + * The **`error()`** method of the with the associated stream to error. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error) + */ + error(reason?: any): void; +} +/** + * The **`TransformStreamDefaultController`** interface of the Streams API provides methods to manipulate the associated ReadableStream and WritableStream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController) + */ +declare abstract class TransformStreamDefaultController { + /** + * The **`desiredSize`** read-only property of the TransformStreamDefaultController interface returns the desired size to fill the queue of the associated ReadableStream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/desiredSize) + */ + get desiredSize(): number | null; + /** + * The **`enqueue()`** method of the TransformStreamDefaultController interface enqueues the given chunk in the readable side of the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/enqueue) + */ + enqueue(chunk?: O): void; + /** + * The **`error()`** method of the TransformStreamDefaultController interface errors both sides of the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error) + */ + error(reason: any): void; + /** + * The **`terminate()`** method of the TransformStreamDefaultController interface closes the readable side and errors the writable side of the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/terminate) + */ + terminate(): void; +} +interface ReadableWritablePair { + /** + * Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + */ + writable: WritableStream; + readable: ReadableStream; +} +/** + * The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream) + */ +declare class WritableStream { + constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy); + /** + * The **`locked`** read-only property of the WritableStream interface returns a boolean indicating whether the `WritableStream` is locked to a writer. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked) + */ + get locked(): boolean; + /** + * The **`abort()`** method of the WritableStream interface aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/abort) + */ + abort(reason?: any): Promise; + /** + * The **`close()`** method of the WritableStream interface closes the associated stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close) + */ + close(): Promise; + /** + * The **`getWriter()`** method of the WritableStream interface returns a new instance of WritableStreamDefaultWriter and locks the stream to that instance. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter) + */ + getWriter(): WritableStreamDefaultWriter; +} +/** + * The **`WritableStreamDefaultWriter`** interface of the Streams API is the object returned by WritableStream.getWriter() and once created locks the writer to the `WritableStream` ensuring that no other streams can write to the underlying sink. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter) + */ +declare class WritableStreamDefaultWriter { + constructor(stream: WritableStream); + /** + * The **`closed`** read-only property of the the stream errors or the writer's lock is released. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed) + */ + get closed(): Promise; + /** + * The **`ready`** read-only property of the that resolves when the desired size of the stream's internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready) + */ + get ready(): Promise; + /** + * The **`desiredSize`** read-only property of the to fill the stream's internal queue. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize) + */ + get desiredSize(): number | null; + /** + * The **`abort()`** method of the the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort) + */ + abort(reason?: any): Promise; + /** + * The **`close()`** method of the stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close) + */ + close(): Promise; + /** + * The **`write()`** method of the operation. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write) + */ + write(chunk?: W): Promise; + /** + * The **`releaseLock()`** method of the corresponding stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock) + */ + releaseLock(): void; +} +/** + * The **`TransformStream`** interface of the Streams API represents a concrete implementation of the pipe chain _transform stream_ concept. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream) + */ +declare class TransformStream { + constructor(transformer?: Transformer, writableStrategy?: QueuingStrategy, readableStrategy?: QueuingStrategy); + /** + * The **`readable`** read-only property of the TransformStream interface returns the ReadableStream instance controlled by this `TransformStream`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable) + */ + get readable(): ReadableStream; + /** + * The **`writable`** read-only property of the TransformStream interface returns the WritableStream instance controlled by this `TransformStream`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable) + */ + get writable(): WritableStream; +} +declare class FixedLengthStream extends IdentityTransformStream { + constructor(expectedLength: number | bigint, queuingStrategy?: IdentityTransformStreamQueuingStrategy); +} +declare class IdentityTransformStream extends TransformStream { + constructor(queuingStrategy?: IdentityTransformStreamQueuingStrategy); +} +interface IdentityTransformStreamQueuingStrategy { + highWaterMark?: (number | bigint); +} +interface ReadableStreamValuesOptions { + preventCancel?: boolean; +} +/** + * The **`CompressionStream`** interface of the Compression Streams API is an API for compressing a stream of data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream) + */ +declare class CompressionStream extends TransformStream { + constructor(format: "gzip" | "deflate" | "deflate-raw"); +} +/** + * The **`DecompressionStream`** interface of the Compression Streams API is an API for decompressing a stream of data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream) + */ +declare class DecompressionStream extends TransformStream { + constructor(format: "gzip" | "deflate" | "deflate-raw"); +} +/** + * The **`TextEncoderStream`** interface of the Encoding API converts a stream of strings into bytes in the UTF-8 encoding. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream) + */ +declare class TextEncoderStream extends TransformStream { + constructor(); + get encoding(): string; +} +/** + * The **`TextDecoderStream`** interface of the Encoding API converts a stream of text in a binary encoding, such as UTF-8 etc., to a stream of strings. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream) + */ +declare class TextDecoderStream extends TransformStream { + constructor(label?: string, options?: TextDecoderStreamTextDecoderStreamInit); + get encoding(): string; + get fatal(): boolean; + get ignoreBOM(): boolean; +} +interface TextDecoderStreamTextDecoderStreamInit { + fatal?: boolean; + ignoreBOM?: boolean; +} +/** + * The **`ByteLengthQueuingStrategy`** interface of the Streams API provides a built-in byte length queuing strategy that can be used when constructing streams. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy) + */ +declare class ByteLengthQueuingStrategy implements QueuingStrategy { + constructor(init: QueuingStrategyInit); + /** + * The read-only **`ByteLengthQueuingStrategy.highWaterMark`** property returns the total number of bytes that can be contained in the internal queue before backpressure is applied. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy/highWaterMark) + */ + get highWaterMark(): number; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy/size) */ + get size(): (chunk?: any) => number; +} +/** + * The **`CountQueuingStrategy`** interface of the Streams API provides a built-in chunk counting queuing strategy that can be used when constructing streams. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy) + */ +declare class CountQueuingStrategy implements QueuingStrategy { + constructor(init: QueuingStrategyInit); + /** + * The read-only **`CountQueuingStrategy.highWaterMark`** property returns the total number of chunks that can be contained in the internal queue before backpressure is applied. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy/highWaterMark) + */ + get highWaterMark(): number; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy/size) */ + get size(): (chunk?: any) => number; +} +interface QueuingStrategyInit { + /** + * Creates a new ByteLengthQueuingStrategy with the provided high water mark. + * + * Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting ByteLengthQueuingStrategy will cause the corresponding stream constructor to throw. + */ + highWaterMark: number; +} +interface ScriptVersion { + id?: string; + tag?: string; + message?: string; +} +declare abstract class TailEvent extends ExtendableEvent { + readonly events: TraceItem[]; + readonly traces: TraceItem[]; +} +interface TraceItem { + readonly event: (TraceItemFetchEventInfo | TraceItemJsRpcEventInfo | TraceItemScheduledEventInfo | TraceItemAlarmEventInfo | TraceItemQueueEventInfo | TraceItemEmailEventInfo | TraceItemTailEventInfo | TraceItemCustomEventInfo | TraceItemHibernatableWebSocketEventInfo) | null; + readonly eventTimestamp: number | null; + readonly logs: TraceLog[]; + readonly exceptions: TraceException[]; + readonly diagnosticsChannelEvents: TraceDiagnosticChannelEvent[]; + readonly scriptName: string | null; + readonly entrypoint?: string; + readonly scriptVersion?: ScriptVersion; + readonly dispatchNamespace?: string; + readonly scriptTags?: string[]; + readonly durableObjectId?: string; + readonly outcome: string; + readonly executionModel: string; + readonly truncated: boolean; + readonly cpuTime: number; + readonly wallTime: number; +} +interface TraceItemAlarmEventInfo { + readonly scheduledTime: Date; +} +interface TraceItemCustomEventInfo { +} +interface TraceItemScheduledEventInfo { + readonly scheduledTime: number; + readonly cron: string; +} +interface TraceItemQueueEventInfo { + readonly queue: string; + readonly batchSize: number; +} +interface TraceItemEmailEventInfo { + readonly mailFrom: string; + readonly rcptTo: string; + readonly rawSize: number; +} +interface TraceItemTailEventInfo { + readonly consumedEvents: TraceItemTailEventInfoTailItem[]; +} +interface TraceItemTailEventInfoTailItem { + readonly scriptName: string | null; +} +interface TraceItemFetchEventInfo { + readonly response?: TraceItemFetchEventInfoResponse; + readonly request: TraceItemFetchEventInfoRequest; +} +interface TraceItemFetchEventInfoRequest { + readonly cf?: any; + readonly headers: Record; + readonly method: string; + readonly url: string; + getUnredacted(): TraceItemFetchEventInfoRequest; +} +interface TraceItemFetchEventInfoResponse { + readonly status: number; +} +interface TraceItemJsRpcEventInfo { + readonly rpcMethod: string; +} +interface TraceItemHibernatableWebSocketEventInfo { + readonly getWebSocketEvent: TraceItemHibernatableWebSocketEventInfoMessage | TraceItemHibernatableWebSocketEventInfoClose | TraceItemHibernatableWebSocketEventInfoError; +} +interface TraceItemHibernatableWebSocketEventInfoMessage { + readonly webSocketEventType: string; +} +interface TraceItemHibernatableWebSocketEventInfoClose { + readonly webSocketEventType: string; + readonly code: number; + readonly wasClean: boolean; +} +interface TraceItemHibernatableWebSocketEventInfoError { + readonly webSocketEventType: string; +} +interface TraceLog { + readonly timestamp: number; + readonly level: string; + readonly message: any; +} +interface TraceException { + readonly timestamp: number; + readonly message: string; + readonly name: string; + readonly stack?: string; +} +interface TraceDiagnosticChannelEvent { + readonly timestamp: number; + readonly channel: string; + readonly message: any; +} +interface TraceMetrics { + readonly cpuTime: number; + readonly wallTime: number; +} +interface UnsafeTraceMetrics { + fromTrace(item: TraceItem): TraceMetrics; +} +/** + * The **`URL`** interface is used to parse, construct, normalize, and encode URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) + */ +declare class URL { + constructor(url: string | URL, base?: string | URL); + /** + * The **`origin`** read-only property of the URL interface returns a string containing the Unicode serialization of the origin of the represented URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/origin) + */ + get origin(): string; + /** + * The **`href`** property of the URL interface is a string containing the whole URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/href) + */ + get href(): string; + /** + * The **`href`** property of the URL interface is a string containing the whole URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/href) + */ + set href(value: string); + /** + * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) + */ + get protocol(): string; + /** + * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) + */ + set protocol(value: string); + /** + * The **`username`** property of the URL interface is a string containing the username component of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) + */ + get username(): string; + /** + * The **`username`** property of the URL interface is a string containing the username component of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) + */ + set username(value: string); + /** + * The **`password`** property of the URL interface is a string containing the password component of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) + */ + get password(): string; + /** + * The **`password`** property of the URL interface is a string containing the password component of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) + */ + set password(value: string); + /** + * The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) + */ + get host(): string; + /** + * The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) + */ + set host(value: string); + /** + * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) + */ + get hostname(): string; + /** + * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) + */ + set hostname(value: string); + /** + * The **`port`** property of the URL interface is a string containing the port number of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) + */ + get port(): string; + /** + * The **`port`** property of the URL interface is a string containing the port number of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) + */ + set port(value: string); + /** + * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) + */ + get pathname(): string; + /** + * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) + */ + set pathname(value: string); + /** + * The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) + */ + get search(): string; + /** + * The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) + */ + set search(value: string); + /** + * The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) + */ + get hash(): string; + /** + * The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) + */ + set hash(value: string); + /** + * The **`searchParams`** read-only property of the access to the [MISSING: httpmethod('GET')] decoded query arguments contained in the URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams) + */ + get searchParams(): URLSearchParams; + /** + * The **`toJSON()`** method of the URL interface returns a string containing a serialized version of the URL, although in practice it seems to have the same effect as ```js-nolint toJSON() ``` None. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON) + */ + toJSON(): string; + /*function toString() { [native code] }*/ + toString(): string; + /** + * The **`URL.canParse()`** static method of the URL interface returns a boolean indicating whether or not an absolute URL, or a relative URL combined with a base URL, are parsable and valid. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/canParse_static) + */ + static canParse(url: string, base?: string): boolean; + /** + * The **`URL.parse()`** static method of the URL interface returns a newly created URL object representing the URL defined by the parameters. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/parse_static) + */ + static parse(url: string, base?: string): URL | null; + /** + * The **`createObjectURL()`** static method of the URL interface creates a string containing a URL representing the object given in the parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static) + */ + static createObjectURL(object: File | Blob): string; + /** + * The **`revokeObjectURL()`** static method of the URL interface releases an existing object URL which was previously created by calling Call this method when you've finished using an object URL to let the browser know not to keep the reference to the file any longer. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static) + */ + static revokeObjectURL(object_url: string): void; +} +/** + * The **`URLSearchParams`** interface defines utility methods to work with the query string of a URL. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams) + */ +declare class URLSearchParams { + constructor(init?: (Iterable> | Record | string)); + /** + * The **`size`** read-only property of the URLSearchParams interface indicates the total number of search parameter entries. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/size) + */ + get size(): number; + /** + * The **`append()`** method of the URLSearchParams interface appends a specified key/value pair as a new search parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/append) + */ + append(name: string, value: string): void; + /** + * The **`delete()`** method of the URLSearchParams interface deletes specified parameters and their associated value(s) from the list of all search parameters. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/delete) + */ + delete(name: string, value?: string): void; + /** + * The **`get()`** method of the URLSearchParams interface returns the first value associated to the given search parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/get) + */ + get(name: string): string | null; + /** + * The **`getAll()`** method of the URLSearchParams interface returns all the values associated with a given search parameter as an array. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll) + */ + getAll(name: string): string[]; + /** + * The **`has()`** method of the URLSearchParams interface returns a boolean value that indicates whether the specified parameter is in the search parameters. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/has) + */ + has(name: string, value?: string): boolean; + /** + * The **`set()`** method of the URLSearchParams interface sets the value associated with a given search parameter to the given value. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set) + */ + set(name: string, value: string): void; + /** + * The **`URLSearchParams.sort()`** method sorts all key/value pairs contained in this object in place and returns `undefined`. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort) + */ + sort(): void; + /* Returns an array of key, value pairs for every entry in the search params. */ + entries(): IterableIterator<[ + key: string, + value: string + ]>; + /* Returns a list of keys in the search params. */ + keys(): IterableIterator; + /* Returns a list of values in the search params. */ + values(): IterableIterator; + forEach(callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, thisArg?: This): void; + /*function toString() { [native code] }*/ + toString(): string; + [Symbol.iterator](): IterableIterator<[ + key: string, + value: string + ]>; +} +declare class URLPattern { + constructor(input?: (string | URLPatternInit), baseURL?: (string | URLPatternOptions), patternOptions?: URLPatternOptions); + get protocol(): string; + get username(): string; + get password(): string; + get hostname(): string; + get port(): string; + get pathname(): string; + get search(): string; + get hash(): string; + get hasRegExpGroups(): boolean; + test(input?: (string | URLPatternInit), baseURL?: string): boolean; + exec(input?: (string | URLPatternInit), baseURL?: string): URLPatternResult | null; +} +interface URLPatternInit { + protocol?: string; + username?: string; + password?: string; + hostname?: string; + port?: string; + pathname?: string; + search?: string; + hash?: string; + baseURL?: string; +} +interface URLPatternComponentResult { + input: string; + groups: Record; +} +interface URLPatternResult { + inputs: (string | URLPatternInit)[]; + protocol: URLPatternComponentResult; + username: URLPatternComponentResult; + password: URLPatternComponentResult; + hostname: URLPatternComponentResult; + port: URLPatternComponentResult; + pathname: URLPatternComponentResult; + search: URLPatternComponentResult; + hash: URLPatternComponentResult; +} +interface URLPatternOptions { + ignoreCase?: boolean; +} +/** + * A `CloseEvent` is sent to clients using WebSockets when the connection is closed. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent) + */ +declare class CloseEvent extends Event { + constructor(type: string, initializer?: CloseEventInit); + /** + * The **`code`** read-only property of the CloseEvent interface returns a WebSocket connection close code indicating the reason the connection was closed. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/code) + */ + readonly code: number; + /** + * The **`reason`** read-only property of the CloseEvent interface returns the WebSocket connection close reason the server gave for closing the connection; that is, a concise human-readable prose explanation for the closure. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/reason) + */ + readonly reason: string; + /** + * The **`wasClean`** read-only property of the CloseEvent interface returns `true` if the connection closed cleanly. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean) + */ + readonly wasClean: boolean; +} +interface CloseEventInit { + code?: number; + reason?: string; + wasClean?: boolean; +} +type WebSocketEventMap = { + close: CloseEvent; + message: MessageEvent; + open: Event; + error: ErrorEvent; +}; +/** + * The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) + */ +declare var WebSocket: { + prototype: WebSocket; + new (url: string, protocols?: (string[] | string)): WebSocket; + readonly READY_STATE_CONNECTING: number; + readonly CONNECTING: number; + readonly READY_STATE_OPEN: number; + readonly OPEN: number; + readonly READY_STATE_CLOSING: number; + readonly CLOSING: number; + readonly READY_STATE_CLOSED: number; + readonly CLOSED: number; +}; +/** + * The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) + */ +interface WebSocket extends EventTarget { + accept(): void; + /** + * The **`WebSocket.send()`** method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of `bufferedAmount` by the number of bytes needed to contain the data. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send) + */ + send(message: (ArrayBuffer | ArrayBufferView) | string): void; + /** + * The **`WebSocket.close()`** method closes the already `CLOSED`, this method does nothing. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close) + */ + close(code?: number, reason?: string): void; + serializeAttachment(attachment: any): void; + deserializeAttachment(): any | null; + /** + * The **`WebSocket.readyState`** read-only property returns the current state of the WebSocket connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/readyState) + */ + readyState: number; + /** + * The **`WebSocket.url`** read-only property returns the absolute URL of the WebSocket as resolved by the constructor. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/url) + */ + url: string | null; + /** + * The **`WebSocket.protocol`** read-only property returns the name of the sub-protocol the server selected; this will be one of the strings specified in the `protocols` parameter when creating the WebSocket object, or the empty string if no connection is established. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol) + */ + protocol: string | null; + /** + * The **`WebSocket.extensions`** read-only property returns the extensions selected by the server. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions) + */ + extensions: string | null; +} +declare const WebSocketPair: { + new (): { + 0: WebSocket; + 1: WebSocket; + }; +}; +interface SqlStorage { + exec>(query: string, ...bindings: any[]): SqlStorageCursor; + get databaseSize(): number; + Cursor: typeof SqlStorageCursor; + Statement: typeof SqlStorageStatement; +} +declare abstract class SqlStorageStatement { +} +type SqlStorageValue = ArrayBuffer | string | number | null; +declare abstract class SqlStorageCursor> { + next(): { + done?: false; + value: T; + } | { + done: true; + value?: never; + }; + toArray(): T[]; + one(): T; + raw(): IterableIterator; + columnNames: string[]; + get rowsRead(): number; + get rowsWritten(): number; + [Symbol.iterator](): IterableIterator; +} +interface Socket { + get readable(): ReadableStream; + get writable(): WritableStream; + get closed(): Promise; + get opened(): Promise; + get upgraded(): boolean; + get secureTransport(): "on" | "off" | "starttls"; + close(): Promise; + startTls(options?: TlsOptions): Socket; +} +interface SocketOptions { + secureTransport?: string; + allowHalfOpen: boolean; + highWaterMark?: (number | bigint); +} +interface SocketAddress { + hostname: string; + port: number; +} +interface TlsOptions { + expectedServerHostname?: string; +} +interface SocketInfo { + remoteAddress?: string; + localAddress?: string; +} +/** + * The **`EventSource`** interface is web content's interface to server-sent events. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource) + */ +declare class EventSource extends EventTarget { + constructor(url: string, init?: EventSourceEventSourceInit); + /** + * The **`close()`** method of the EventSource interface closes the connection, if one is made, and sets the ```js-nolint close() ``` None. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close) + */ + close(): void; + /** + * The **`url`** read-only property of the URL of the source. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url) + */ + get url(): string; + /** + * The **`withCredentials`** read-only property of the the `EventSource` object was instantiated with CORS credentials set. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials) + */ + get withCredentials(): boolean; + /** + * The **`readyState`** read-only property of the connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState) + */ + get readyState(): number; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */ + get onopen(): any | null; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */ + set onopen(value: any | null); + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */ + get onmessage(): any | null; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */ + set onmessage(value: any | null); + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */ + get onerror(): any | null; + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */ + set onerror(value: any | null); + static readonly CONNECTING: number; + static readonly OPEN: number; + static readonly CLOSED: number; + static from(stream: ReadableStream): EventSource; +} +interface EventSourceEventSourceInit { + withCredentials?: boolean; + fetcher?: Fetcher; +} +interface Container { + get running(): boolean; + start(options?: ContainerStartupOptions): void; + monitor(): Promise; + destroy(error?: any): Promise; + signal(signo: number): void; + getTcpPort(port: number): Fetcher; + setInactivityTimeout(durationMs: number | bigint): Promise; +} +interface ContainerStartupOptions { + entrypoint?: string[]; + enableInternet: boolean; + env?: Record; + hardTimeout?: (number | bigint); +} +/** + * The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort) + */ +declare abstract class MessagePort extends EventTarget { + /** + * The **`postMessage()`** method of the transfers ownership of objects to other browsing contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage) + */ + postMessage(data?: any, options?: (any[] | MessagePortPostMessageOptions)): void; + /** + * The **`close()`** method of the MessagePort interface disconnects the port, so it is no longer active. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close) + */ + close(): void; + /** + * The **`start()`** method of the MessagePort interface starts the sending of messages queued on the port. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start) + */ + start(): void; + get onmessage(): any | null; + set onmessage(value: any | null); +} +/** + * The **`MessageChannel`** interface of the Channel Messaging API allows us to create a new message channel and send data through it via its two MessagePort properties. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel) + */ +declare class MessageChannel { + constructor(); + /** + * The **`port1`** read-only property of the the port attached to the context that originated the channel. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1) + */ + readonly port1: MessagePort; + /** + * The **`port2`** read-only property of the the port attached to the context at the other end of the channel, which the message is initially sent to. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2) + */ + readonly port2: MessagePort; +} +interface MessagePortPostMessageOptions { + transfer?: any[]; +} +type LoopbackForExport Rpc.EntrypointBranded) | ExportedHandler | undefined = undefined> = T extends new (...args: any[]) => Rpc.WorkerEntrypointBranded ? LoopbackServiceStub> : T extends new (...args: any[]) => Rpc.DurableObjectBranded ? LoopbackDurableObjectClass> : T extends ExportedHandler ? LoopbackServiceStub : undefined; +type LoopbackServiceStub = Fetcher & (T extends CloudflareWorkersModule.WorkerEntrypoint ? (opts: { + props?: Props; +}) => Fetcher : (opts: { + props?: any; +}) => Fetcher); +type LoopbackDurableObjectClass = DurableObjectClass & (T extends CloudflareWorkersModule.DurableObject ? (opts: { + props?: Props; +}) => DurableObjectClass : (opts: { + props?: any; +}) => DurableObjectClass); +interface SyncKvStorage { + get(key: string): T | undefined; + list(options?: SyncKvListOptions): Iterable<[ + string, + T + ]>; + put(key: string, value: T): void; + delete(key: string): boolean; +} +interface SyncKvListOptions { + start?: string; + startAfter?: string; + end?: string; + prefix?: string; + reverse?: boolean; + limit?: number; +} +interface WorkerStub { + getEntrypoint(name?: string, options?: WorkerStubEntrypointOptions): Fetcher; +} +interface WorkerStubEntrypointOptions { + props?: any; +} +interface WorkerLoader { + get(name: string | null, getCode: () => WorkerLoaderWorkerCode | Promise): WorkerStub; +} +interface WorkerLoaderModule { + js?: string; + cjs?: string; + text?: string; + data?: ArrayBuffer; + json?: any; + py?: string; + wasm?: ArrayBuffer; +} +interface WorkerLoaderWorkerCode { + compatibilityDate: string; + compatibilityFlags?: string[]; + allowExperimental?: boolean; + mainModule: string; + modules: Record; + env?: any; + globalOutbound?: (Fetcher | null); + tails?: Fetcher[]; + streamingTails?: Fetcher[]; +} +/** +* The Workers runtime supports a subset of the Performance API, used to measure timing and performance, +* as well as timing of subrequests and other operations. +* +* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/) +*/ +declare abstract class Performance { + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancetimeorigin) */ + get timeOrigin(): number; + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */ + now(): number; +} +type AiImageClassificationInput = { + image: number[]; +}; +type AiImageClassificationOutput = { + score?: number; + label?: string; +}[]; +declare abstract class BaseAiImageClassification { + inputs: AiImageClassificationInput; + postProcessedOutputs: AiImageClassificationOutput; +} +type AiImageToTextInput = { + image: number[]; + prompt?: string; + max_tokens?: number; + temperature?: number; + top_p?: number; + top_k?: number; + seed?: number; + repetition_penalty?: number; + frequency_penalty?: number; + presence_penalty?: number; + raw?: boolean; + messages?: RoleScopedChatInput[]; +}; +type AiImageToTextOutput = { + description: string; +}; +declare abstract class BaseAiImageToText { + inputs: AiImageToTextInput; + postProcessedOutputs: AiImageToTextOutput; +} +type AiImageTextToTextInput = { + image: string; + prompt?: string; + max_tokens?: number; + temperature?: number; + ignore_eos?: boolean; + top_p?: number; + top_k?: number; + seed?: number; + repetition_penalty?: number; + frequency_penalty?: number; + presence_penalty?: number; + raw?: boolean; + messages?: RoleScopedChatInput[]; +}; +type AiImageTextToTextOutput = { + description: string; +}; +declare abstract class BaseAiImageTextToText { + inputs: AiImageTextToTextInput; + postProcessedOutputs: AiImageTextToTextOutput; +} +type AiMultimodalEmbeddingsInput = { + image: string; + text: string[]; +}; +type AiIMultimodalEmbeddingsOutput = { + data: number[][]; + shape: number[]; +}; +declare abstract class BaseAiMultimodalEmbeddings { + inputs: AiImageTextToTextInput; + postProcessedOutputs: AiImageTextToTextOutput; +} +type AiObjectDetectionInput = { + image: number[]; +}; +type AiObjectDetectionOutput = { + score?: number; + label?: string; +}[]; +declare abstract class BaseAiObjectDetection { + inputs: AiObjectDetectionInput; + postProcessedOutputs: AiObjectDetectionOutput; +} +type AiSentenceSimilarityInput = { + source: string; + sentences: string[]; +}; +type AiSentenceSimilarityOutput = number[]; +declare abstract class BaseAiSentenceSimilarity { + inputs: AiSentenceSimilarityInput; + postProcessedOutputs: AiSentenceSimilarityOutput; +} +type AiAutomaticSpeechRecognitionInput = { + audio: number[]; +}; +type AiAutomaticSpeechRecognitionOutput = { + text?: string; + words?: { + word: string; + start: number; + end: number; + }[]; + vtt?: string; +}; +declare abstract class BaseAiAutomaticSpeechRecognition { + inputs: AiAutomaticSpeechRecognitionInput; + postProcessedOutputs: AiAutomaticSpeechRecognitionOutput; +} +type AiSummarizationInput = { + input_text: string; + max_length?: number; +}; +type AiSummarizationOutput = { + summary: string; +}; +declare abstract class BaseAiSummarization { + inputs: AiSummarizationInput; + postProcessedOutputs: AiSummarizationOutput; +} +type AiTextClassificationInput = { + text: string; +}; +type AiTextClassificationOutput = { + score?: number; + label?: string; +}[]; +declare abstract class BaseAiTextClassification { + inputs: AiTextClassificationInput; + postProcessedOutputs: AiTextClassificationOutput; +} +type AiTextEmbeddingsInput = { + text: string | string[]; +}; +type AiTextEmbeddingsOutput = { + shape: number[]; + data: number[][]; +}; +declare abstract class BaseAiTextEmbeddings { + inputs: AiTextEmbeddingsInput; + postProcessedOutputs: AiTextEmbeddingsOutput; +} +type RoleScopedChatInput = { + role: "user" | "assistant" | "system" | "tool" | (string & NonNullable); + content: string; + name?: string; +}; +type AiTextGenerationToolLegacyInput = { + name: string; + description: string; + parameters?: { + type: "object" | (string & NonNullable); + properties: { + [key: string]: { + type: string; + description?: string; + }; + }; + required: string[]; + }; +}; +type AiTextGenerationToolInput = { + type: "function" | (string & NonNullable); + function: { + name: string; + description: string; + parameters?: { + type: "object" | (string & NonNullable); + properties: { + [key: string]: { + type: string; + description?: string; + }; + }; + required: string[]; + }; + }; +}; +type AiTextGenerationFunctionsInput = { + name: string; + code: string; +}; +type AiTextGenerationResponseFormat = { + type: string; + json_schema?: any; +}; +type AiTextGenerationInput = { + prompt?: string; + raw?: boolean; + stream?: boolean; + max_tokens?: number; + temperature?: number; + top_p?: number; + top_k?: number; + seed?: number; + repetition_penalty?: number; + frequency_penalty?: number; + presence_penalty?: number; + messages?: RoleScopedChatInput[]; + response_format?: AiTextGenerationResponseFormat; + tools?: AiTextGenerationToolInput[] | AiTextGenerationToolLegacyInput[] | (object & NonNullable); + functions?: AiTextGenerationFunctionsInput[]; +}; +type AiTextGenerationToolLegacyOutput = { + name: string; + arguments: unknown; +}; +type AiTextGenerationToolOutput = { + id: string; + type: "function"; + function: { + name: string; + arguments: string; + }; +}; +type UsageTags = { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; +}; +type AiTextGenerationOutput = { + response?: string; + tool_calls?: AiTextGenerationToolLegacyOutput[] & AiTextGenerationToolOutput[]; + usage?: UsageTags; +}; +declare abstract class BaseAiTextGeneration { + inputs: AiTextGenerationInput; + postProcessedOutputs: AiTextGenerationOutput; +} +type AiTextToSpeechInput = { + prompt: string; + lang?: string; +}; +type AiTextToSpeechOutput = Uint8Array | { + audio: string; +}; +declare abstract class BaseAiTextToSpeech { + inputs: AiTextToSpeechInput; + postProcessedOutputs: AiTextToSpeechOutput; +} +type AiTextToImageInput = { + prompt: string; + negative_prompt?: string; + height?: number; + width?: number; + image?: number[]; + image_b64?: string; + mask?: number[]; + num_steps?: number; + strength?: number; + guidance?: number; + seed?: number; +}; +type AiTextToImageOutput = ReadableStream; +declare abstract class BaseAiTextToImage { + inputs: AiTextToImageInput; + postProcessedOutputs: AiTextToImageOutput; +} +type AiTranslationInput = { + text: string; + target_lang: string; + source_lang?: string; +}; +type AiTranslationOutput = { + translated_text?: string; +}; +declare abstract class BaseAiTranslation { + inputs: AiTranslationInput; + postProcessedOutputs: AiTranslationOutput; +} +/** + * Workers AI support for OpenAI's Responses API + * Reference: https://github.com/openai/openai-node/blob/master/src/resources/responses/responses.ts + * + * It's a stripped down version from its source. + * It currently supports basic function calling, json mode and accepts images as input. + * + * It does not include types for WebSearch, CodeInterpreter, FileInputs, MCP, CustomTools. + * We plan to add those incrementally as model + platform capabilities evolve. + */ +type ResponsesInput = { + background?: boolean | null; + conversation?: string | ResponseConversationParam | null; + include?: Array | null; + input?: string | ResponseInput; + instructions?: string | null; + max_output_tokens?: number | null; + parallel_tool_calls?: boolean | null; + previous_response_id?: string | null; + prompt_cache_key?: string; + reasoning?: Reasoning | null; + safety_identifier?: string; + service_tier?: "auto" | "default" | "flex" | "scale" | "priority" | null; + stream?: boolean | null; + stream_options?: StreamOptions | null; + temperature?: number | null; + text?: ResponseTextConfig; + tool_choice?: ToolChoiceOptions | ToolChoiceFunction; + tools?: Array; + top_p?: number | null; + truncation?: "auto" | "disabled" | null; +}; +type ResponsesOutput = { + id?: string; + created_at?: number; + output_text?: string; + error?: ResponseError | null; + incomplete_details?: ResponseIncompleteDetails | null; + instructions?: string | Array | null; + object?: "response"; + output?: Array; + parallel_tool_calls?: boolean; + temperature?: number | null; + tool_choice?: ToolChoiceOptions | ToolChoiceFunction; + tools?: Array; + top_p?: number | null; + max_output_tokens?: number | null; + previous_response_id?: string | null; + prompt?: ResponsePrompt | null; + reasoning?: Reasoning | null; + safety_identifier?: string; + service_tier?: "auto" | "default" | "flex" | "scale" | "priority" | null; + status?: ResponseStatus; + text?: ResponseTextConfig; + truncation?: "auto" | "disabled" | null; + usage?: ResponseUsage; +}; +type EasyInputMessage = { + content: string | ResponseInputMessageContentList; + role: "user" | "assistant" | "system" | "developer"; + type?: "message"; +}; +type ResponsesFunctionTool = { + name: string; + parameters: { + [key: string]: unknown; + } | null; + strict: boolean | null; + type: "function"; + description?: string | null; +}; +type ResponseIncompleteDetails = { + reason?: "max_output_tokens" | "content_filter"; +}; +type ResponsePrompt = { + id: string; + variables?: { + [key: string]: string | ResponseInputText | ResponseInputImage; + } | null; + version?: string | null; +}; +type Reasoning = { + effort?: ReasoningEffort | null; + generate_summary?: "auto" | "concise" | "detailed" | null; + summary?: "auto" | "concise" | "detailed" | null; +}; +type ResponseContent = ResponseInputText | ResponseInputImage | ResponseOutputText | ResponseOutputRefusal | ResponseContentReasoningText; +type ResponseContentReasoningText = { + text: string; + type: "reasoning_text"; +}; +type ResponseConversationParam = { + id: string; +}; +type ResponseCreatedEvent = { + response: Response; + sequence_number: number; + type: "response.created"; +}; +type ResponseCustomToolCallOutput = { + call_id: string; + output: string | Array; + type: "custom_tool_call_output"; + id?: string; +}; +type ResponseError = { + code: "server_error" | "rate_limit_exceeded" | "invalid_prompt" | "vector_store_timeout" | "invalid_image" | "invalid_image_format" | "invalid_base64_image" | "invalid_image_url" | "image_too_large" | "image_too_small" | "image_parse_error" | "image_content_policy_violation" | "invalid_image_mode" | "image_file_too_large" | "unsupported_image_media_type" | "empty_image_file" | "failed_to_download_image" | "image_file_not_found"; + message: string; +}; +type ResponseErrorEvent = { + code: string | null; + message: string; + param: string | null; + sequence_number: number; + type: "error"; +}; +type ResponseFailedEvent = { + response: Response; + sequence_number: number; + type: "response.failed"; +}; +type ResponseFormatText = { + type: "text"; +}; +type ResponseFormatJSONObject = { + type: "json_object"; +}; +type ResponseFormatTextConfig = ResponseFormatText | ResponseFormatTextJSONSchemaConfig | ResponseFormatJSONObject; +type ResponseFormatTextJSONSchemaConfig = { + name: string; + schema: { + [key: string]: unknown; + }; + type: "json_schema"; + description?: string; + strict?: boolean | null; +}; +type ResponseFunctionCallArgumentsDeltaEvent = { + delta: string; + item_id: string; + output_index: number; + sequence_number: number; + type: "response.function_call_arguments.delta"; +}; +type ResponseFunctionCallArgumentsDoneEvent = { + arguments: string; + item_id: string; + name: string; + output_index: number; + sequence_number: number; + type: "response.function_call_arguments.done"; +}; +type ResponseFunctionCallOutputItem = ResponseInputTextContent | ResponseInputImageContent; +type ResponseFunctionCallOutputItemList = Array; +type ResponseFunctionToolCall = { + arguments: string; + call_id: string; + name: string; + type: "function_call"; + id?: string; + status?: "in_progress" | "completed" | "incomplete"; +}; +interface ResponseFunctionToolCallItem extends ResponseFunctionToolCall { + id: string; +} +type ResponseFunctionToolCallOutputItem = { + id: string; + call_id: string; + output: string | Array; + type: "function_call_output"; + status?: "in_progress" | "completed" | "incomplete"; +}; +type ResponseIncludable = "message.input_image.image_url" | "message.output_text.logprobs"; +type ResponseIncompleteEvent = { + response: Response; + sequence_number: number; + type: "response.incomplete"; +}; +type ResponseInput = Array; +type ResponseInputContent = ResponseInputText | ResponseInputImage; +type ResponseInputImage = { + detail: "low" | "high" | "auto"; + type: "input_image"; + /** + * Base64 encoded image + */ + image_url?: string | null; +}; +type ResponseInputImageContent = { + type: "input_image"; + detail?: "low" | "high" | "auto" | null; + /** + * Base64 encoded image + */ + image_url?: string | null; +}; +type ResponseInputItem = EasyInputMessage | ResponseInputItemMessage | ResponseOutputMessage | ResponseFunctionToolCall | ResponseInputItemFunctionCallOutput | ResponseReasoningItem; +type ResponseInputItemFunctionCallOutput = { + call_id: string; + output: string | ResponseFunctionCallOutputItemList; + type: "function_call_output"; + id?: string | null; + status?: "in_progress" | "completed" | "incomplete" | null; +}; +type ResponseInputItemMessage = { + content: ResponseInputMessageContentList; + role: "user" | "system" | "developer"; + status?: "in_progress" | "completed" | "incomplete"; + type?: "message"; +}; +type ResponseInputMessageContentList = Array; +type ResponseInputMessageItem = { + id: string; + content: ResponseInputMessageContentList; + role: "user" | "system" | "developer"; + status?: "in_progress" | "completed" | "incomplete"; + type?: "message"; +}; +type ResponseInputText = { + text: string; + type: "input_text"; +}; +type ResponseInputTextContent = { + text: string; + type: "input_text"; +}; +type ResponseItem = ResponseInputMessageItem | ResponseOutputMessage | ResponseFunctionToolCallItem | ResponseFunctionToolCallOutputItem; +type ResponseOutputItem = ResponseOutputMessage | ResponseFunctionToolCall | ResponseReasoningItem; +type ResponseOutputItemAddedEvent = { + item: ResponseOutputItem; + output_index: number; + sequence_number: number; + type: "response.output_item.added"; +}; +type ResponseOutputItemDoneEvent = { + item: ResponseOutputItem; + output_index: number; + sequence_number: number; + type: "response.output_item.done"; +}; +type ResponseOutputMessage = { + id: string; + content: Array; + role: "assistant"; + status: "in_progress" | "completed" | "incomplete"; + type: "message"; +}; +type ResponseOutputRefusal = { + refusal: string; + type: "refusal"; +}; +type ResponseOutputText = { + text: string; + type: "output_text"; + logprobs?: Array; +}; +type ResponseReasoningItem = { + id: string; + summary: Array; + type: "reasoning"; + content?: Array; + encrypted_content?: string | null; + status?: "in_progress" | "completed" | "incomplete"; +}; +type ResponseReasoningSummaryItem = { + text: string; + type: "summary_text"; +}; +type ResponseReasoningContentItem = { + text: string; + type: "reasoning_text"; +}; +type ResponseReasoningTextDeltaEvent = { + content_index: number; + delta: string; + item_id: string; + output_index: number; + sequence_number: number; + type: "response.reasoning_text.delta"; +}; +type ResponseReasoningTextDoneEvent = { + content_index: number; + item_id: string; + output_index: number; + sequence_number: number; + text: string; + type: "response.reasoning_text.done"; +}; +type ResponseRefusalDeltaEvent = { + content_index: number; + delta: string; + item_id: string; + output_index: number; + sequence_number: number; + type: "response.refusal.delta"; +}; +type ResponseRefusalDoneEvent = { + content_index: number; + item_id: string; + output_index: number; + refusal: string; + sequence_number: number; + type: "response.refusal.done"; +}; +type ResponseStatus = "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete"; +type ResponseStreamEvent = ResponseCompletedEvent | ResponseCreatedEvent | ResponseErrorEvent | ResponseFunctionCallArgumentsDeltaEvent | ResponseFunctionCallArgumentsDoneEvent | ResponseFailedEvent | ResponseIncompleteEvent | ResponseOutputItemAddedEvent | ResponseOutputItemDoneEvent | ResponseReasoningTextDeltaEvent | ResponseReasoningTextDoneEvent | ResponseRefusalDeltaEvent | ResponseRefusalDoneEvent | ResponseTextDeltaEvent | ResponseTextDoneEvent; +type ResponseCompletedEvent = { + response: Response; + sequence_number: number; + type: "response.completed"; +}; +type ResponseTextConfig = { + format?: ResponseFormatTextConfig; + verbosity?: "low" | "medium" | "high" | null; +}; +type ResponseTextDeltaEvent = { + content_index: number; + delta: string; + item_id: string; + logprobs: Array; + output_index: number; + sequence_number: number; + type: "response.output_text.delta"; +}; +type ResponseTextDoneEvent = { + content_index: number; + item_id: string; + logprobs: Array; + output_index: number; + sequence_number: number; + text: string; + type: "response.output_text.done"; +}; +type Logprob = { + token: string; + logprob: number; + top_logprobs?: Array; +}; +type TopLogprob = { + token?: string; + logprob?: number; +}; +type ResponseUsage = { + input_tokens: number; + output_tokens: number; + total_tokens: number; +}; +type Tool = ResponsesFunctionTool; +type ToolChoiceFunction = { + name: string; + type: "function"; +}; +type ToolChoiceOptions = "none"; +type ReasoningEffort = "minimal" | "low" | "medium" | "high" | null; +type StreamOptions = { + include_obfuscation?: boolean; +}; +type Ai_Cf_Baai_Bge_Base_En_V1_5_Input = { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; +} | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; + }[]; +}; +type Ai_Cf_Baai_Bge_Base_En_V1_5_Output = { + shape?: number[]; + /** + * Embeddings of the requested text values + */ + data?: number[][]; + /** + * The pooling method used in the embedding process. + */ + pooling?: "mean" | "cls"; +} | Ai_Cf_Baai_Bge_Base_En_V1_5_AsyncResponse; +interface Ai_Cf_Baai_Bge_Base_En_V1_5_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Baai_Bge_Base_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Base_En_V1_5_Input; + postProcessedOutputs: Ai_Cf_Baai_Bge_Base_En_V1_5_Output; +} +type Ai_Cf_Openai_Whisper_Input = string | { + /** + * An array of integers that represent the audio data constrained to 8-bit unsigned integer values + */ + audio: number[]; +}; +interface Ai_Cf_Openai_Whisper_Output { + /** + * The transcription + */ + text: string; + word_count?: number; + words?: { + word?: string; + /** + * The second this word begins in the recording + */ + start?: number; + /** + * The ending second when the word completes + */ + end?: number; + }[]; + vtt?: string; +} +declare abstract class Base_Ai_Cf_Openai_Whisper { + inputs: Ai_Cf_Openai_Whisper_Input; + postProcessedOutputs: Ai_Cf_Openai_Whisper_Output; +} +type Ai_Cf_Meta_M2M100_1_2B_Input = { + /** + * The text to be translated + */ + text: string; + /** + * The language code of the source text (e.g., 'en' for English). Defaults to 'en' if not specified + */ + source_lang?: string; + /** + * The language code to translate the text into (e.g., 'es' for Spanish) + */ + target_lang: string; +} | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + /** + * The text to be translated + */ + text: string; + /** + * The language code of the source text (e.g., 'en' for English). Defaults to 'en' if not specified + */ + source_lang?: string; + /** + * The language code to translate the text into (e.g., 'es' for Spanish) + */ + target_lang: string; + }[]; +}; +type Ai_Cf_Meta_M2M100_1_2B_Output = { + /** + * The translated text in the target language + */ + translated_text?: string; +} | Ai_Cf_Meta_M2M100_1_2B_AsyncResponse; +interface Ai_Cf_Meta_M2M100_1_2B_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Meta_M2M100_1_2B { + inputs: Ai_Cf_Meta_M2M100_1_2B_Input; + postProcessedOutputs: Ai_Cf_Meta_M2M100_1_2B_Output; +} +type Ai_Cf_Baai_Bge_Small_En_V1_5_Input = { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; +} | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; + }[]; +}; +type Ai_Cf_Baai_Bge_Small_En_V1_5_Output = { + shape?: number[]; + /** + * Embeddings of the requested text values + */ + data?: number[][]; + /** + * The pooling method used in the embedding process. + */ + pooling?: "mean" | "cls"; +} | Ai_Cf_Baai_Bge_Small_En_V1_5_AsyncResponse; +interface Ai_Cf_Baai_Bge_Small_En_V1_5_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Baai_Bge_Small_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Small_En_V1_5_Input; + postProcessedOutputs: Ai_Cf_Baai_Bge_Small_En_V1_5_Output; +} +type Ai_Cf_Baai_Bge_Large_En_V1_5_Input = { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; +} | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[]; + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: "mean" | "cls"; + }[]; +}; +type Ai_Cf_Baai_Bge_Large_En_V1_5_Output = { + shape?: number[]; + /** + * Embeddings of the requested text values + */ + data?: number[][]; + /** + * The pooling method used in the embedding process. + */ + pooling?: "mean" | "cls"; +} | Ai_Cf_Baai_Bge_Large_En_V1_5_AsyncResponse; +interface Ai_Cf_Baai_Bge_Large_En_V1_5_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Baai_Bge_Large_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Large_En_V1_5_Input; + postProcessedOutputs: Ai_Cf_Baai_Bge_Large_En_V1_5_Output; +} +type Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Input = string | { + /** + * The input text prompt for the model to generate a response. + */ + prompt?: string; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * Controls the creativity of the AI's responses by adjusting how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; + image: number[] | (string & NonNullable); + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; +}; +interface Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Output { + description?: string; +} +declare abstract class Base_Ai_Cf_Unum_Uform_Gen2_Qwen_500M { + inputs: Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Input; + postProcessedOutputs: Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Output; +} +type Ai_Cf_Openai_Whisper_Tiny_En_Input = string | { + /** + * An array of integers that represent the audio data constrained to 8-bit unsigned integer values + */ + audio: number[]; +}; +interface Ai_Cf_Openai_Whisper_Tiny_En_Output { + /** + * The transcription + */ + text: string; + word_count?: number; + words?: { + word?: string; + /** + * The second this word begins in the recording + */ + start?: number; + /** + * The ending second when the word completes + */ + end?: number; + }[]; + vtt?: string; +} +declare abstract class Base_Ai_Cf_Openai_Whisper_Tiny_En { + inputs: Ai_Cf_Openai_Whisper_Tiny_En_Input; + postProcessedOutputs: Ai_Cf_Openai_Whisper_Tiny_En_Output; +} +interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input { + /** + * Base64 encoded value of the audio data. + */ + audio: string; + /** + * Supported tasks are 'translate' or 'transcribe'. + */ + task?: string; + /** + * The language of the audio being transcribed or translated. + */ + language?: string; + /** + * Preprocess the audio with a voice activity detection model. + */ + vad_filter?: boolean; + /** + * A text prompt to help provide context to the model on the contents of the audio. + */ + initial_prompt?: string; + /** + * The prefix it appended the the beginning of the output of the transcription and can guide the transcription result. + */ + prefix?: string; +} +interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Output { + transcription_info?: { + /** + * The language of the audio being transcribed or translated. + */ + language?: string; + /** + * The confidence level or probability of the detected language being accurate, represented as a decimal between 0 and 1. + */ + language_probability?: number; + /** + * The total duration of the original audio file, in seconds. + */ + duration?: number; + /** + * The duration of the audio after applying Voice Activity Detection (VAD) to remove silent or irrelevant sections, in seconds. + */ + duration_after_vad?: number; + }; + /** + * The complete transcription of the audio. + */ + text: string; + /** + * The total number of words in the transcription. + */ + word_count?: number; + segments?: { + /** + * The starting time of the segment within the audio, in seconds. + */ + start?: number; + /** + * The ending time of the segment within the audio, in seconds. + */ + end?: number; + /** + * The transcription of the segment. + */ + text?: string; + /** + * The temperature used in the decoding process, controlling randomness in predictions. Lower values result in more deterministic outputs. + */ + temperature?: number; + /** + * The average log probability of the predictions for the words in this segment, indicating overall confidence. + */ + avg_logprob?: number; + /** + * The compression ratio of the input to the output, measuring how much the text was compressed during the transcription process. + */ + compression_ratio?: number; + /** + * The probability that the segment contains no speech, represented as a decimal between 0 and 1. + */ + no_speech_prob?: number; + words?: { + /** + * The individual word transcribed from the audio. + */ + word?: string; + /** + * The starting time of the word within the audio, in seconds. + */ + start?: number; + /** + * The ending time of the word within the audio, in seconds. + */ + end?: number; + }[]; + }[]; + /** + * The transcription in WebVTT format, which includes timing and text information for use in subtitles. + */ + vtt?: string; +} +declare abstract class Base_Ai_Cf_Openai_Whisper_Large_V3_Turbo { + inputs: Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input; + postProcessedOutputs: Ai_Cf_Openai_Whisper_Large_V3_Turbo_Output; +} +type Ai_Cf_Baai_Bge_M3_Input = Ai_Cf_Baai_Bge_M3_Input_QueryAnd_Contexts | Ai_Cf_Baai_Bge_M3_Input_Embedding | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: (Ai_Cf_Baai_Bge_M3_Input_QueryAnd_Contexts_1 | Ai_Cf_Baai_Bge_M3_Input_Embedding_1)[]; +}; +interface Ai_Cf_Baai_Bge_M3_Input_QueryAnd_Contexts { + /** + * A query you wish to perform against the provided contexts. If no query is provided the model with respond with embeddings for contexts + */ + query?: string; + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string; + }[]; + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean; +} +interface Ai_Cf_Baai_Bge_M3_Input_Embedding { + text: string | string[]; + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean; +} +interface Ai_Cf_Baai_Bge_M3_Input_QueryAnd_Contexts_1 { + /** + * A query you wish to perform against the provided contexts. If no query is provided the model with respond with embeddings for contexts + */ + query?: string; + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string; + }[]; + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean; +} +interface Ai_Cf_Baai_Bge_M3_Input_Embedding_1 { + text: string | string[]; + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean; +} +type Ai_Cf_Baai_Bge_M3_Output = Ai_Cf_Baai_Bge_M3_Ouput_Query | Ai_Cf_Baai_Bge_M3_Output_EmbeddingFor_Contexts | Ai_Cf_Baai_Bge_M3_Ouput_Embedding | Ai_Cf_Baai_Bge_M3_AsyncResponse; +interface Ai_Cf_Baai_Bge_M3_Ouput_Query { + response?: { + /** + * Index of the context in the request + */ + id?: number; + /** + * Score of the context under the index. + */ + score?: number; + }[]; +} +interface Ai_Cf_Baai_Bge_M3_Output_EmbeddingFor_Contexts { + response?: number[][]; + shape?: number[]; + /** + * The pooling method used in the embedding process. + */ + pooling?: "mean" | "cls"; +} +interface Ai_Cf_Baai_Bge_M3_Ouput_Embedding { + shape?: number[]; + /** + * Embeddings of the requested text values + */ + data?: number[][]; + /** + * The pooling method used in the embedding process. + */ + pooling?: "mean" | "cls"; +} +interface Ai_Cf_Baai_Bge_M3_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Baai_Bge_M3 { + inputs: Ai_Cf_Baai_Bge_M3_Input; + postProcessedOutputs: Ai_Cf_Baai_Bge_M3_Output; +} +interface Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Input { + /** + * A text description of the image you want to generate. + */ + prompt: string; + /** + * The number of diffusion steps; higher values can improve quality but take longer. + */ + steps?: number; +} +interface Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Output { + /** + * The generated image in Base64 format. + */ + image?: string; +} +declare abstract class Base_Ai_Cf_Black_Forest_Labs_Flux_1_Schnell { + inputs: Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Input; + postProcessedOutputs: Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Output; +} +type Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Input = Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Prompt | Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Messages; +interface Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + image?: number[] | (string & NonNullable); + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; +} +interface Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[] | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }; + }[]; + image?: number[] | (string & NonNullable); + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + /** + * If true, the response will be streamed back incrementally. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Controls the creativity of the AI's responses by adjusting how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +type Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Output = { + /** + * The generated text response from the model + */ + response?: string; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +}; +declare abstract class Base_Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct { + inputs: Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Input; + postProcessedOutputs: Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Output; +} +type Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Input = Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Prompt | Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Messages | Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Async_Batch; +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode_1; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode_1 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Async_Batch { + requests?: { + /** + * User-supplied reference. This field will be present in the response as well it can be used to reference the request and response. It's NOT validated to be unique. + */ + external_reference?: string; + /** + * Prompt for the text generation model + */ + prompt?: string; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; + response_format?: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode_2; + }[]; +} +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_JSON_Mode_2 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +type Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +} | string | Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_AsyncResponse; +interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast { + inputs: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Input; + postProcessedOutputs: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Output; +} +interface Ai_Cf_Meta_Llama_Guard_3_8B_Input { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender must alternate between 'user' and 'assistant'. + */ + role: "user" | "assistant"; + /** + * The content of the message as a string. + */ + content: string; + }[]; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Dictate the output format of the generated response. + */ + response_format?: { + /** + * Set to json_object to process and output generated text as JSON. + */ + type?: string; + }; +} +interface Ai_Cf_Meta_Llama_Guard_3_8B_Output { + response?: string | { + /** + * Whether the conversation is safe or not. + */ + safe?: boolean; + /** + * A list of what hazard categories predicted for the conversation, if the conversation is deemed unsafe. + */ + categories?: string[]; + }; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; +} +declare abstract class Base_Ai_Cf_Meta_Llama_Guard_3_8B { + inputs: Ai_Cf_Meta_Llama_Guard_3_8B_Input; + postProcessedOutputs: Ai_Cf_Meta_Llama_Guard_3_8B_Output; +} +interface Ai_Cf_Baai_Bge_Reranker_Base_Input { + /** + * A query you wish to perform against the provided contexts. + */ + /** + * Number of returned results starting with the best score. + */ + top_k?: number; + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string; + }[]; +} +interface Ai_Cf_Baai_Bge_Reranker_Base_Output { + response?: { + /** + * Index of the context in the request + */ + id?: number; + /** + * Score of the context under the index. + */ + score?: number; + }[]; +} +declare abstract class Base_Ai_Cf_Baai_Bge_Reranker_Base { + inputs: Ai_Cf_Baai_Bge_Reranker_Base_Input; + postProcessedOutputs: Ai_Cf_Baai_Bge_Reranker_Base_Output; +} +type Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Input = Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Prompt | Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Messages; +interface Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_JSON_Mode { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_JSON_Mode_1; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_JSON_Mode_1 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +type Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +}; +declare abstract class Base_Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct { + inputs: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Input; + postProcessedOutputs: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Output; +} +type Ai_Cf_Qwen_Qwq_32B_Input = Ai_Cf_Qwen_Qwq_32B_Prompt | Ai_Cf_Qwen_Qwq_32B_Messages; +interface Ai_Cf_Qwen_Qwq_32B_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwq_32B_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[] | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +type Ai_Cf_Qwen_Qwq_32B_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +}; +declare abstract class Base_Ai_Cf_Qwen_Qwq_32B { + inputs: Ai_Cf_Qwen_Qwq_32B_Input; + postProcessedOutputs: Ai_Cf_Qwen_Qwq_32B_Output; +} +type Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Input = Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Prompt | Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Messages; +interface Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[] | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +type Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +}; +declare abstract class Base_Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct { + inputs: Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Input; + postProcessedOutputs: Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Output; +} +type Ai_Cf_Google_Gemma_3_12B_It_Input = Ai_Cf_Google_Gemma_3_12B_It_Prompt | Ai_Cf_Google_Gemma_3_12B_It_Messages; +interface Ai_Cf_Google_Gemma_3_12B_It_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Google_Gemma_3_12B_It_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[]; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +type Ai_Cf_Google_Gemma_3_12B_It_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + /** + * The name of the tool to be called + */ + name?: string; + }[]; +}; +declare abstract class Base_Ai_Cf_Google_Gemma_3_12B_It { + inputs: Ai_Cf_Google_Gemma_3_12B_It_Input; + postProcessedOutputs: Ai_Cf_Google_Gemma_3_12B_It_Output; +} +type Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Input = Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Prompt | Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages | Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Async_Batch; +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object; + response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + /** + * The tool call id. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[] | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Async_Batch { + requests: (Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Prompt_Inner | Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages_Inner)[]; +} +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Prompt_Inner { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object; + response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages_Inner { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string; + /** + * The tool call id. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string; + content?: string | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }[] | { + /** + * Type of the content provided + */ + type?: string; + text?: string; + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string; + }; + }; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode; + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +type Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The tool call id. + */ + id?: string; + /** + * Specifies the type of tool (e.g., 'function'). + */ + type?: string; + /** + * Details of the function tool. + */ + function?: { + /** + * The name of the tool to be called + */ + name?: string; + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object; + }; + }[]; +}; +declare abstract class Base_Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct { + inputs: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Input; + postProcessedOutputs: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Output; +} +type Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Input = Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Prompt | Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages | Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Async_Batch; +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_1; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_1 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Async_Batch { + requests: (Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Prompt_1 | Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages_1)[]; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Prompt_1 { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_2; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_2 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages_1 { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_3; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_JSON_Mode_3 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +type Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Output = Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Chat_Completion_Response | Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Text_Completion_Response | string | Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_AsyncResponse; +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Chat_Completion_Response { + /** + * Unique identifier for the completion + */ + id?: string; + /** + * Object type identifier + */ + object?: "chat.completion"; + /** + * Unix timestamp of when the completion was created + */ + created?: number; + /** + * Model used for the completion + */ + model?: string; + /** + * List of completion choices + */ + choices?: { + /** + * Index of the choice in the list + */ + index?: number; + /** + * The message generated by the model + */ + message?: { + /** + * Role of the message author + */ + role: string; + /** + * The content of the message + */ + content: string; + /** + * Internal reasoning content (if available) + */ + reasoning_content?: string; + /** + * Tool calls made by the assistant + */ + tool_calls?: { + /** + * Unique identifier for the tool call + */ + id: string; + /** + * Type of tool call + */ + type: "function"; + function: { + /** + * Name of the function to call + */ + name: string; + /** + * JSON string of arguments for the function + */ + arguments: string; + }; + }[]; + }; + /** + * Reason why the model stopped generating + */ + finish_reason?: string; + /** + * Stop reason (may be null) + */ + stop_reason?: string | null; + /** + * Log probabilities (if requested) + */ + logprobs?: {} | null; + }[]; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * Log probabilities for the prompt (if requested) + */ + prompt_logprobs?: {} | null; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Text_Completion_Response { + /** + * Unique identifier for the completion + */ + id?: string; + /** + * Object type identifier + */ + object?: "text_completion"; + /** + * Unix timestamp of when the completion was created + */ + created?: number; + /** + * Model used for the completion + */ + model?: string; + /** + * List of completion choices + */ + choices?: { + /** + * Index of the choice in the list + */ + index: number; + /** + * The generated text completion + */ + text: string; + /** + * Reason why the model stopped generating + */ + finish_reason: string; + /** + * Stop reason (may be null) + */ + stop_reason?: string | null; + /** + * Log probabilities (if requested) + */ + logprobs?: {} | null; + /** + * Log probabilities for the prompt (if requested) + */ + prompt_logprobs?: {} | null; + }[]; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; +} +interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8 { + inputs: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Input; + postProcessedOutputs: Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Output; +} +interface Ai_Cf_Deepgram_Nova_3_Input { + audio: { + body: object; + contentType: string; + }; + /** + * Sets how the model will interpret strings submitted to the custom_topic param. When strict, the model will only return topics submitted using the custom_topic param. When extended, the model will return its own detected topics in addition to those submitted using the custom_topic param. + */ + custom_topic_mode?: "extended" | "strict"; + /** + * Custom topics you want the model to detect within your input audio or text if present Submit up to 100 + */ + custom_topic?: string; + /** + * Sets how the model will interpret intents submitted to the custom_intent param. When strict, the model will only return intents submitted using the custom_intent param. When extended, the model will return its own detected intents in addition those submitted using the custom_intents param + */ + custom_intent_mode?: "extended" | "strict"; + /** + * Custom intents you want the model to detect within your input audio if present + */ + custom_intent?: string; + /** + * Identifies and extracts key entities from content in submitted audio + */ + detect_entities?: boolean; + /** + * Identifies the dominant language spoken in submitted audio + */ + detect_language?: boolean; + /** + * Recognize speaker changes. Each word in the transcript will be assigned a speaker number starting at 0 + */ + diarize?: boolean; + /** + * Identify and extract key entities from content in submitted audio + */ + dictation?: boolean; + /** + * Specify the expected encoding of your submitted audio + */ + encoding?: "linear16" | "flac" | "mulaw" | "amr-nb" | "amr-wb" | "opus" | "speex" | "g729"; + /** + * Arbitrary key-value pairs that are attached to the API response for usage in downstream processing + */ + extra?: string; + /** + * Filler Words can help transcribe interruptions in your audio, like 'uh' and 'um' + */ + filler_words?: boolean; + /** + * Key term prompting can boost or suppress specialized terminology and brands. + */ + keyterm?: string; + /** + * Keywords can boost or suppress specialized terminology and brands. + */ + keywords?: string; + /** + * The BCP-47 language tag that hints at the primary spoken language. Depending on the Model and API endpoint you choose only certain languages are available. + */ + language?: string; + /** + * Spoken measurements will be converted to their corresponding abbreviations. + */ + measurements?: boolean; + /** + * Opts out requests from the Deepgram Model Improvement Program. Refer to our Docs for pricing impacts before setting this to true. https://dpgr.am/deepgram-mip. + */ + mip_opt_out?: boolean; + /** + * Mode of operation for the model representing broad area of topic that will be talked about in the supplied audio + */ + mode?: "general" | "medical" | "finance"; + /** + * Transcribe each audio channel independently. + */ + multichannel?: boolean; + /** + * Numerals converts numbers from written format to numerical format. + */ + numerals?: boolean; + /** + * Splits audio into paragraphs to improve transcript readability. + */ + paragraphs?: boolean; + /** + * Profanity Filter looks for recognized profanity and converts it to the nearest recognized non-profane word or removes it from the transcript completely. + */ + profanity_filter?: boolean; + /** + * Add punctuation and capitalization to the transcript. + */ + punctuate?: boolean; + /** + * Redaction removes sensitive information from your transcripts. + */ + redact?: string; + /** + * Search for terms or phrases in submitted audio and replaces them. + */ + replace?: string; + /** + * Search for terms or phrases in submitted audio. + */ + search?: string; + /** + * Recognizes the sentiment throughout a transcript or text. + */ + sentiment?: boolean; + /** + * Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability. + */ + smart_format?: boolean; + /** + * Detect topics throughout a transcript or text. + */ + topics?: boolean; + /** + * Segments speech into meaningful semantic units. + */ + utterances?: boolean; + /** + * Seconds to wait before detecting a pause between words in submitted audio. + */ + utt_split?: number; + /** + * The number of channels in the submitted audio + */ + channels?: number; + /** + * Specifies whether the streaming endpoint should provide ongoing transcription updates as more audio is received. When set to true, the endpoint sends continuous updates, meaning transcription results may evolve over time. Note: Supported only for webosockets. + */ + interim_results?: boolean; + /** + * Indicates how long model will wait to detect whether a speaker has finished speaking or pauses for a significant period of time. When set to a value, the streaming endpoint immediately finalizes the transcription for the processed time range and returns the transcript with a speech_final parameter set to true. Can also be set to false to disable endpointing + */ + endpointing?: string; + /** + * Indicates that speech has started. You'll begin receiving Speech Started messages upon speech starting. Note: Supported only for webosockets. + */ + vad_events?: boolean; + /** + * Indicates how long model will wait to send an UtteranceEnd message after a word has been transcribed. Use with interim_results. Note: Supported only for webosockets. + */ + utterance_end_ms?: boolean; +} +interface Ai_Cf_Deepgram_Nova_3_Output { + results?: { + channels?: { + alternatives?: { + confidence?: number; + transcript?: string; + words?: { + confidence?: number; + end?: number; + start?: number; + word?: string; + }[]; + }[]; + }[]; + summary?: { + result?: string; + short?: string; + }; + sentiments?: { + segments?: { + text?: string; + start_word?: number; + end_word?: number; + sentiment?: string; + sentiment_score?: number; + }[]; + average?: { + sentiment?: string; + sentiment_score?: number; + }; + }; + }; +} +declare abstract class Base_Ai_Cf_Deepgram_Nova_3 { + inputs: Ai_Cf_Deepgram_Nova_3_Input; + postProcessedOutputs: Ai_Cf_Deepgram_Nova_3_Output; +} +interface Ai_Cf_Qwen_Qwen3_Embedding_0_6B_Input { + queries?: string | string[]; + /** + * Optional instruction for the task + */ + instruction?: string; + documents?: string | string[]; + text?: string | string[]; +} +interface Ai_Cf_Qwen_Qwen3_Embedding_0_6B_Output { + data?: number[][]; + shape?: number[]; +} +declare abstract class Base_Ai_Cf_Qwen_Qwen3_Embedding_0_6B { + inputs: Ai_Cf_Qwen_Qwen3_Embedding_0_6B_Input; + postProcessedOutputs: Ai_Cf_Qwen_Qwen3_Embedding_0_6B_Output; +} +type Ai_Cf_Pipecat_Ai_Smart_Turn_V2_Input = { + /** + * readable stream with audio data and content-type specified for that data + */ + audio: { + body: object; + contentType: string; + }; + /** + * type of data PCM data that's sent to the inference server as raw array + */ + dtype?: "uint8" | "float32" | "float64"; +} | { + /** + * base64 encoded audio data + */ + audio: string; + /** + * type of data PCM data that's sent to the inference server as raw array + */ + dtype?: "uint8" | "float32" | "float64"; +}; +interface Ai_Cf_Pipecat_Ai_Smart_Turn_V2_Output { + /** + * if true, end-of-turn was detected + */ + is_complete?: boolean; + /** + * probability of the end-of-turn detection + */ + probability?: number; +} +declare abstract class Base_Ai_Cf_Pipecat_Ai_Smart_Turn_V2 { + inputs: Ai_Cf_Pipecat_Ai_Smart_Turn_V2_Input; + postProcessedOutputs: Ai_Cf_Pipecat_Ai_Smart_Turn_V2_Output; +} +declare abstract class Base_Ai_Cf_Openai_Gpt_Oss_120B { + inputs: ResponsesInput; + postProcessedOutputs: ResponsesOutput; +} +declare abstract class Base_Ai_Cf_Openai_Gpt_Oss_20B { + inputs: ResponsesInput; + postProcessedOutputs: ResponsesOutput; +} +interface Ai_Cf_Leonardo_Phoenix_1_0_Input { + /** + * A text description of the image you want to generate. + */ + prompt: string; + /** + * Controls how closely the generated image should adhere to the prompt; higher values make the image more aligned with the prompt + */ + guidance?: number; + /** + * Random seed for reproducibility of the image generation + */ + seed?: number; + /** + * The height of the generated image in pixels + */ + height?: number; + /** + * The width of the generated image in pixels + */ + width?: number; + /** + * The number of diffusion steps; higher values can improve quality but take longer + */ + num_steps?: number; + /** + * Specify what to exclude from the generated images + */ + negative_prompt?: string; +} +/** + * The generated image in JPEG format + */ +type Ai_Cf_Leonardo_Phoenix_1_0_Output = string; +declare abstract class Base_Ai_Cf_Leonardo_Phoenix_1_0 { + inputs: Ai_Cf_Leonardo_Phoenix_1_0_Input; + postProcessedOutputs: Ai_Cf_Leonardo_Phoenix_1_0_Output; +} +interface Ai_Cf_Leonardo_Lucid_Origin_Input { + /** + * A text description of the image you want to generate. + */ + prompt: string; + /** + * Controls how closely the generated image should adhere to the prompt; higher values make the image more aligned with the prompt + */ + guidance?: number; + /** + * Random seed for reproducibility of the image generation + */ + seed?: number; + /** + * The height of the generated image in pixels + */ + height?: number; + /** + * The width of the generated image in pixels + */ + width?: number; + /** + * The number of diffusion steps; higher values can improve quality but take longer + */ + num_steps?: number; + /** + * The number of diffusion steps; higher values can improve quality but take longer + */ + steps?: number; +} +interface Ai_Cf_Leonardo_Lucid_Origin_Output { + /** + * The generated image in Base64 format. + */ + image?: string; +} +declare abstract class Base_Ai_Cf_Leonardo_Lucid_Origin { + inputs: Ai_Cf_Leonardo_Lucid_Origin_Input; + postProcessedOutputs: Ai_Cf_Leonardo_Lucid_Origin_Output; +} +interface Ai_Cf_Deepgram_Aura_1_Input { + /** + * Speaker used to produce the audio. + */ + speaker?: "angus" | "asteria" | "arcas" | "orion" | "orpheus" | "athena" | "luna" | "zeus" | "perseus" | "helios" | "hera" | "stella"; + /** + * Encoding of the output audio. + */ + encoding?: "linear16" | "flac" | "mulaw" | "alaw" | "mp3" | "opus" | "aac"; + /** + * Container specifies the file format wrapper for the output audio. The available options depend on the encoding type.. + */ + container?: "none" | "wav" | "ogg"; + /** + * The text content to be converted to speech + */ + text: string; + /** + * Sample Rate specifies the sample rate for the output audio. Based on the encoding, different sample rates are supported. For some encodings, the sample rate is not configurable + */ + sample_rate?: number; + /** + * The bitrate of the audio in bits per second. Choose from predefined ranges or specific values based on the encoding type. + */ + bit_rate?: number; +} +/** + * The generated audio in MP3 format + */ +type Ai_Cf_Deepgram_Aura_1_Output = string; +declare abstract class Base_Ai_Cf_Deepgram_Aura_1 { + inputs: Ai_Cf_Deepgram_Aura_1_Input; + postProcessedOutputs: Ai_Cf_Deepgram_Aura_1_Output; +} +interface Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B_Input { + /** + * Input text to translate. Can be a single string or a list of strings. + */ + text: string | string[]; + /** + * Target langauge to translate to + */ + target_language: "asm_Beng" | "awa_Deva" | "ben_Beng" | "bho_Deva" | "brx_Deva" | "doi_Deva" | "eng_Latn" | "gom_Deva" | "gon_Deva" | "guj_Gujr" | "hin_Deva" | "hne_Deva" | "kan_Knda" | "kas_Arab" | "kas_Deva" | "kha_Latn" | "lus_Latn" | "mag_Deva" | "mai_Deva" | "mal_Mlym" | "mar_Deva" | "mni_Beng" | "mni_Mtei" | "npi_Deva" | "ory_Orya" | "pan_Guru" | "san_Deva" | "sat_Olck" | "snd_Arab" | "snd_Deva" | "tam_Taml" | "tel_Telu" | "urd_Arab" | "unr_Deva"; +} +interface Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B_Output { + /** + * Translated texts + */ + translations: string[]; +} +declare abstract class Base_Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B { + inputs: Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B_Input; + postProcessedOutputs: Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B_Output; +} +type Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Input = Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Prompt | Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages | Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Async_Batch; +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_1; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_1 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Async_Batch { + requests: (Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Prompt_1 | Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages_1)[]; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Prompt_1 { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string; + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string; + response_format?: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_2; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_2 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages_1 { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string; + /** + * The content of the message as a string. + */ + content: string; + }[]; + functions?: { + name: string; + code: string; + }[]; + /** + * A list of tools available for the assistant to use. + */ + tools?: ({ + /** + * The name of the tool. More descriptive the better. + */ + name: string; + /** + * A brief description of what the tool does. + */ + description: string; + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + } | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string; + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string; + /** + * A brief description of what the function does. + */ + description: string; + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string; + /** + * List of required parameter names. + */ + required?: string[]; + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string; + /** + * A description of the expected parameter. + */ + description: string; + }; + }; + }; + }; + })[]; + response_format?: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_3; + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean; + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean; + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number; + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number; + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number; + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number; + /** + * Random seed for reproducibility of the generation. + */ + seed?: number; + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number; + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number; + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_JSON_Mode_3 { + type?: "json_object" | "json_schema"; + json_schema?: unknown; +} +type Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Output = Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Chat_Completion_Response | Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Text_Completion_Response | string | Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_AsyncResponse; +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Chat_Completion_Response { + /** + * Unique identifier for the completion + */ + id?: string; + /** + * Object type identifier + */ + object?: "chat.completion"; + /** + * Unix timestamp of when the completion was created + */ + created?: number; + /** + * Model used for the completion + */ + model?: string; + /** + * List of completion choices + */ + choices?: { + /** + * Index of the choice in the list + */ + index?: number; + /** + * The message generated by the model + */ + message?: { + /** + * Role of the message author + */ + role: string; + /** + * The content of the message + */ + content: string; + /** + * Internal reasoning content (if available) + */ + reasoning_content?: string; + /** + * Tool calls made by the assistant + */ + tool_calls?: { + /** + * Unique identifier for the tool call + */ + id: string; + /** + * Type of tool call + */ + type: "function"; + function: { + /** + * Name of the function to call + */ + name: string; + /** + * JSON string of arguments for the function + */ + arguments: string; + }; + }[]; + }; + /** + * Reason why the model stopped generating + */ + finish_reason?: string; + /** + * Stop reason (may be null) + */ + stop_reason?: string | null; + /** + * Log probabilities (if requested) + */ + logprobs?: {} | null; + }[]; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; + /** + * Log probabilities for the prompt (if requested) + */ + prompt_logprobs?: {} | null; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Text_Completion_Response { + /** + * Unique identifier for the completion + */ + id?: string; + /** + * Object type identifier + */ + object?: "text_completion"; + /** + * Unix timestamp of when the completion was created + */ + created?: number; + /** + * Model used for the completion + */ + model?: string; + /** + * List of completion choices + */ + choices?: { + /** + * Index of the choice in the list + */ + index: number; + /** + * The generated text completion + */ + text: string; + /** + * Reason why the model stopped generating + */ + finish_reason: string; + /** + * Stop reason (may be null) + */ + stop_reason?: string | null; + /** + * Log probabilities (if requested) + */ + logprobs?: {} | null; + /** + * Log probabilities for the prompt (if requested) + */ + prompt_logprobs?: {} | null; + }[]; + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number; + /** + * Total number of tokens in output + */ + completion_tokens?: number; + /** + * Total number of input and output tokens + */ + total_tokens?: number; + }; +} +interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string; +} +declare abstract class Base_Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It { + inputs: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Input; + postProcessedOutputs: Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Output; +} +interface Ai_Cf_Pfnet_Plamo_Embedding_1B_Input { + /** + * Input text to embed. Can be a single string or a list of strings. + */ + text: string | string[]; +} +interface Ai_Cf_Pfnet_Plamo_Embedding_1B_Output { + /** + * Embedding vectors, where each vector is a list of floats. + */ + data: number[][]; + /** + * Shape of the embedding data as [number_of_embeddings, embedding_dimension]. + * + * @minItems 2 + * @maxItems 2 + */ + shape: [ + number, + number + ]; +} +declare abstract class Base_Ai_Cf_Pfnet_Plamo_Embedding_1B { + inputs: Ai_Cf_Pfnet_Plamo_Embedding_1B_Input; + postProcessedOutputs: Ai_Cf_Pfnet_Plamo_Embedding_1B_Output; +} +interface Ai_Cf_Deepgram_Flux_Input { + /** + * Encoding of the audio stream. Currently only supports raw signed little-endian 16-bit PCM. + */ + encoding: "linear16"; + /** + * Sample rate of the audio stream in Hz. + */ + sample_rate: string; + /** + * End-of-turn confidence required to fire an eager end-of-turn event. When set, enables EagerEndOfTurn and TurnResumed events. Valid Values 0.3 - 0.9. + */ + eager_eot_threshold?: string; + /** + * End-of-turn confidence required to finish a turn. Valid Values 0.5 - 0.9. + */ + eot_threshold?: string; + /** + * A turn will be finished when this much time has passed after speech, regardless of EOT confidence. + */ + eot_timeout_ms?: string; + /** + * Keyterm prompting can improve recognition of specialized terminology. Pass multiple keyterm query parameters to boost multiple keyterms. + */ + keyterm?: string; + /** + * Opts out requests from the Deepgram Model Improvement Program. Refer to Deepgram Docs for pricing impacts before setting this to true. https://dpgr.am/deepgram-mip + */ + mip_opt_out?: "true" | "false"; + /** + * Label your requests for the purpose of identification during usage reporting + */ + tag?: string; +} +/** + * Output will be returned as websocket messages. + */ +interface Ai_Cf_Deepgram_Flux_Output { + /** + * The unique identifier of the request (uuid) + */ + request_id?: string; + /** + * Starts at 0 and increments for each message the server sends to the client. + */ + sequence_id?: number; + /** + * The type of event being reported. + */ + event?: "Update" | "StartOfTurn" | "EagerEndOfTurn" | "TurnResumed" | "EndOfTurn"; + /** + * The index of the current turn + */ + turn_index?: number; + /** + * Start time in seconds of the audio range that was transcribed + */ + audio_window_start?: number; + /** + * End time in seconds of the audio range that was transcribed + */ + audio_window_end?: number; + /** + * Text that was said over the course of the current turn + */ + transcript?: string; + /** + * The words in the transcript + */ + words?: { + /** + * The individual punctuated, properly-cased word from the transcript + */ + word: string; + /** + * Confidence that this word was transcribed correctly + */ + confidence: number; + }[]; + /** + * Confidence that no more speech is coming in this turn + */ + end_of_turn_confidence?: number; +} +declare abstract class Base_Ai_Cf_Deepgram_Flux { + inputs: Ai_Cf_Deepgram_Flux_Input; + postProcessedOutputs: Ai_Cf_Deepgram_Flux_Output; +} +interface Ai_Cf_Deepgram_Aura_2_En_Input { + /** + * Speaker used to produce the audio. + */ + speaker?: "amalthea" | "andromeda" | "apollo" | "arcas" | "aries" | "asteria" | "athena" | "atlas" | "aurora" | "callista" | "cora" | "cordelia" | "delia" | "draco" | "electra" | "harmonia" | "helena" | "hera" | "hermes" | "hyperion" | "iris" | "janus" | "juno" | "jupiter" | "luna" | "mars" | "minerva" | "neptune" | "odysseus" | "ophelia" | "orion" | "orpheus" | "pandora" | "phoebe" | "pluto" | "saturn" | "thalia" | "theia" | "vesta" | "zeus"; + /** + * Encoding of the output audio. + */ + encoding?: "linear16" | "flac" | "mulaw" | "alaw" | "mp3" | "opus" | "aac"; + /** + * Container specifies the file format wrapper for the output audio. The available options depend on the encoding type.. + */ + container?: "none" | "wav" | "ogg"; + /** + * The text content to be converted to speech + */ + text: string; + /** + * Sample Rate specifies the sample rate for the output audio. Based on the encoding, different sample rates are supported. For some encodings, the sample rate is not configurable + */ + sample_rate?: number; + /** + * The bitrate of the audio in bits per second. Choose from predefined ranges or specific values based on the encoding type. + */ + bit_rate?: number; +} +/** + * The generated audio in MP3 format + */ +type Ai_Cf_Deepgram_Aura_2_En_Output = string; +declare abstract class Base_Ai_Cf_Deepgram_Aura_2_En { + inputs: Ai_Cf_Deepgram_Aura_2_En_Input; + postProcessedOutputs: Ai_Cf_Deepgram_Aura_2_En_Output; +} +interface Ai_Cf_Deepgram_Aura_2_Es_Input { + /** + * Speaker used to produce the audio. + */ + speaker?: "sirio" | "nestor" | "carina" | "celeste" | "alvaro" | "diana" | "aquila" | "selena" | "estrella" | "javier"; + /** + * Encoding of the output audio. + */ + encoding?: "linear16" | "flac" | "mulaw" | "alaw" | "mp3" | "opus" | "aac"; + /** + * Container specifies the file format wrapper for the output audio. The available options depend on the encoding type.. + */ + container?: "none" | "wav" | "ogg"; + /** + * The text content to be converted to speech + */ + text: string; + /** + * Sample Rate specifies the sample rate for the output audio. Based on the encoding, different sample rates are supported. For some encodings, the sample rate is not configurable + */ + sample_rate?: number; + /** + * The bitrate of the audio in bits per second. Choose from predefined ranges or specific values based on the encoding type. + */ + bit_rate?: number; +} +/** + * The generated audio in MP3 format + */ +type Ai_Cf_Deepgram_Aura_2_Es_Output = string; +declare abstract class Base_Ai_Cf_Deepgram_Aura_2_Es { + inputs: Ai_Cf_Deepgram_Aura_2_Es_Input; + postProcessedOutputs: Ai_Cf_Deepgram_Aura_2_Es_Output; +} +interface AiModels { + "@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification; + "@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage; + "@cf/runwayml/stable-diffusion-v1-5-inpainting": BaseAiTextToImage; + "@cf/runwayml/stable-diffusion-v1-5-img2img": BaseAiTextToImage; + "@cf/lykon/dreamshaper-8-lcm": BaseAiTextToImage; + "@cf/bytedance/stable-diffusion-xl-lightning": BaseAiTextToImage; + "@cf/myshell-ai/melotts": BaseAiTextToSpeech; + "@cf/google/embeddinggemma-300m": BaseAiTextEmbeddings; + "@cf/microsoft/resnet-50": BaseAiImageClassification; + "@cf/meta/llama-2-7b-chat-int8": BaseAiTextGeneration; + "@cf/mistral/mistral-7b-instruct-v0.1": BaseAiTextGeneration; + "@cf/meta/llama-2-7b-chat-fp16": BaseAiTextGeneration; + "@hf/thebloke/llama-2-13b-chat-awq": BaseAiTextGeneration; + "@hf/thebloke/mistral-7b-instruct-v0.1-awq": BaseAiTextGeneration; + "@hf/thebloke/zephyr-7b-beta-awq": BaseAiTextGeneration; + "@hf/thebloke/openhermes-2.5-mistral-7b-awq": BaseAiTextGeneration; + "@hf/thebloke/neural-chat-7b-v3-1-awq": BaseAiTextGeneration; + "@hf/thebloke/llamaguard-7b-awq": BaseAiTextGeneration; + "@hf/thebloke/deepseek-coder-6.7b-base-awq": BaseAiTextGeneration; + "@hf/thebloke/deepseek-coder-6.7b-instruct-awq": BaseAiTextGeneration; + "@cf/deepseek-ai/deepseek-math-7b-instruct": BaseAiTextGeneration; + "@cf/defog/sqlcoder-7b-2": BaseAiTextGeneration; + "@cf/openchat/openchat-3.5-0106": BaseAiTextGeneration; + "@cf/tiiuae/falcon-7b-instruct": BaseAiTextGeneration; + "@cf/thebloke/discolm-german-7b-v1-awq": BaseAiTextGeneration; + "@cf/qwen/qwen1.5-0.5b-chat": BaseAiTextGeneration; + "@cf/qwen/qwen1.5-7b-chat-awq": BaseAiTextGeneration; + "@cf/qwen/qwen1.5-14b-chat-awq": BaseAiTextGeneration; + "@cf/tinyllama/tinyllama-1.1b-chat-v1.0": BaseAiTextGeneration; + "@cf/microsoft/phi-2": BaseAiTextGeneration; + "@cf/qwen/qwen1.5-1.8b-chat": BaseAiTextGeneration; + "@cf/mistral/mistral-7b-instruct-v0.2-lora": BaseAiTextGeneration; + "@hf/nousresearch/hermes-2-pro-mistral-7b": BaseAiTextGeneration; + "@hf/nexusflow/starling-lm-7b-beta": BaseAiTextGeneration; + "@hf/google/gemma-7b-it": BaseAiTextGeneration; + "@cf/meta-llama/llama-2-7b-chat-hf-lora": BaseAiTextGeneration; + "@cf/google/gemma-2b-it-lora": BaseAiTextGeneration; + "@cf/google/gemma-7b-it-lora": BaseAiTextGeneration; + "@hf/mistral/mistral-7b-instruct-v0.2": BaseAiTextGeneration; + "@cf/meta/llama-3-8b-instruct": BaseAiTextGeneration; + "@cf/fblgit/una-cybertron-7b-v2-bf16": BaseAiTextGeneration; + "@cf/meta/llama-3-8b-instruct-awq": BaseAiTextGeneration; + "@cf/meta/llama-3.1-8b-instruct-fp8": BaseAiTextGeneration; + "@cf/meta/llama-3.1-8b-instruct-awq": BaseAiTextGeneration; + "@cf/meta/llama-3.2-3b-instruct": BaseAiTextGeneration; + "@cf/meta/llama-3.2-1b-instruct": BaseAiTextGeneration; + "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": BaseAiTextGeneration; + "@cf/ibm-granite/granite-4.0-h-micro": BaseAiTextGeneration; + "@cf/facebook/bart-large-cnn": BaseAiSummarization; + "@cf/llava-hf/llava-1.5-7b-hf": BaseAiImageToText; + "@cf/baai/bge-base-en-v1.5": Base_Ai_Cf_Baai_Bge_Base_En_V1_5; + "@cf/openai/whisper": Base_Ai_Cf_Openai_Whisper; + "@cf/meta/m2m100-1.2b": Base_Ai_Cf_Meta_M2M100_1_2B; + "@cf/baai/bge-small-en-v1.5": Base_Ai_Cf_Baai_Bge_Small_En_V1_5; + "@cf/baai/bge-large-en-v1.5": Base_Ai_Cf_Baai_Bge_Large_En_V1_5; + "@cf/unum/uform-gen2-qwen-500m": Base_Ai_Cf_Unum_Uform_Gen2_Qwen_500M; + "@cf/openai/whisper-tiny-en": Base_Ai_Cf_Openai_Whisper_Tiny_En; + "@cf/openai/whisper-large-v3-turbo": Base_Ai_Cf_Openai_Whisper_Large_V3_Turbo; + "@cf/baai/bge-m3": Base_Ai_Cf_Baai_Bge_M3; + "@cf/black-forest-labs/flux-1-schnell": Base_Ai_Cf_Black_Forest_Labs_Flux_1_Schnell; + "@cf/meta/llama-3.2-11b-vision-instruct": Base_Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct; + "@cf/meta/llama-3.3-70b-instruct-fp8-fast": Base_Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast; + "@cf/meta/llama-guard-3-8b": Base_Ai_Cf_Meta_Llama_Guard_3_8B; + "@cf/baai/bge-reranker-base": Base_Ai_Cf_Baai_Bge_Reranker_Base; + "@cf/qwen/qwen2.5-coder-32b-instruct": Base_Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct; + "@cf/qwen/qwq-32b": Base_Ai_Cf_Qwen_Qwq_32B; + "@cf/mistralai/mistral-small-3.1-24b-instruct": Base_Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct; + "@cf/google/gemma-3-12b-it": Base_Ai_Cf_Google_Gemma_3_12B_It; + "@cf/meta/llama-4-scout-17b-16e-instruct": Base_Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct; + "@cf/qwen/qwen3-30b-a3b-fp8": Base_Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8; + "@cf/deepgram/nova-3": Base_Ai_Cf_Deepgram_Nova_3; + "@cf/qwen/qwen3-embedding-0.6b": Base_Ai_Cf_Qwen_Qwen3_Embedding_0_6B; + "@cf/pipecat-ai/smart-turn-v2": Base_Ai_Cf_Pipecat_Ai_Smart_Turn_V2; + "@cf/openai/gpt-oss-120b": Base_Ai_Cf_Openai_Gpt_Oss_120B; + "@cf/openai/gpt-oss-20b": Base_Ai_Cf_Openai_Gpt_Oss_20B; + "@cf/leonardo/phoenix-1.0": Base_Ai_Cf_Leonardo_Phoenix_1_0; + "@cf/leonardo/lucid-origin": Base_Ai_Cf_Leonardo_Lucid_Origin; + "@cf/deepgram/aura-1": Base_Ai_Cf_Deepgram_Aura_1; + "@cf/ai4bharat/indictrans2-en-indic-1B": Base_Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B; + "@cf/aisingapore/gemma-sea-lion-v4-27b-it": Base_Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It; + "@cf/pfnet/plamo-embedding-1b": Base_Ai_Cf_Pfnet_Plamo_Embedding_1B; + "@cf/deepgram/flux": Base_Ai_Cf_Deepgram_Flux; + "@cf/deepgram/aura-2-en": Base_Ai_Cf_Deepgram_Aura_2_En; + "@cf/deepgram/aura-2-es": Base_Ai_Cf_Deepgram_Aura_2_Es; +} +type AiOptions = { + /** + * Send requests as an asynchronous batch job, only works for supported models + * https://developers.cloudflare.com/workers-ai/features/batch-api + */ + queueRequest?: boolean; + /** + * Establish websocket connections, only works for supported models + */ + websocket?: boolean; + /** + * Tag your requests to group and view them in Cloudflare dashboard. + * + * Rules: + * Tags must only contain letters, numbers, and the symbols: : - . / @ + * Each tag can have maximum 50 characters. + * Maximum 5 tags are allowed each request. + * Duplicate tags will removed. + */ + tags?: string[]; + gateway?: GatewayOptions; + returnRawResponse?: boolean; + prefix?: string; + extraHeaders?: object; +}; +type AiModelsSearchParams = { + author?: string; + hide_experimental?: boolean; + page?: number; + per_page?: number; + search?: string; + source?: number; + task?: string; +}; +type AiModelsSearchObject = { + id: string; + source: number; + name: string; + description: string; + task: { + id: string; + name: string; + description: string; + }; + tags: string[]; + properties: { + property_id: string; + value: string; + }[]; +}; +interface InferenceUpstreamError extends Error { +} +interface AiInternalError extends Error { +} +type AiModelListType = Record; +declare abstract class Ai { + aiGatewayLogId: string | null; + gateway(gatewayId: string): AiGateway; + autorag(autoragId: string): AutoRAG; + run(model: Name, inputs: InputOptions, options?: Options): Promise; + models(params?: AiModelsSearchParams): Promise; + toMarkdown(): ToMarkdownService; + toMarkdown(files: MarkdownDocument[], options?: ConversionRequestOptions): Promise; + toMarkdown(files: MarkdownDocument, options?: ConversionRequestOptions): Promise; +} +type GatewayRetries = { + maxAttempts?: 1 | 2 | 3 | 4 | 5; + retryDelayMs?: number; + backoff?: 'constant' | 'linear' | 'exponential'; +}; +type GatewayOptions = { + id: string; + cacheKey?: string; + cacheTtl?: number; + skipCache?: boolean; + metadata?: Record; + collectLog?: boolean; + eventId?: string; + requestTimeoutMs?: number; + retries?: GatewayRetries; +}; +type UniversalGatewayOptions = Exclude & { + /** + ** @deprecated + */ + id?: string; +}; +type AiGatewayPatchLog = { + score?: number | null; + feedback?: -1 | 1 | null; + metadata?: Record | null; +}; +type AiGatewayLog = { + id: string; + provider: string; + model: string; + model_type?: string; + path: string; + duration: number; + request_type?: string; + request_content_type?: string; + status_code: number; + response_content_type?: string; + success: boolean; + cached: boolean; + tokens_in?: number; + tokens_out?: number; + metadata?: Record; + step?: number; + cost?: number; + custom_cost?: boolean; + request_size: number; + request_head?: string; + request_head_complete: boolean; + response_size: number; + response_head?: string; + response_head_complete: boolean; + created_at: Date; +}; +type AIGatewayProviders = 'workers-ai' | 'anthropic' | 'aws-bedrock' | 'azure-openai' | 'google-vertex-ai' | 'huggingface' | 'openai' | 'perplexity-ai' | 'replicate' | 'groq' | 'cohere' | 'google-ai-studio' | 'mistral' | 'grok' | 'openrouter' | 'deepseek' | 'cerebras' | 'cartesia' | 'elevenlabs' | 'adobe-firefly'; +type AIGatewayHeaders = { + 'cf-aig-metadata': Record | string; + 'cf-aig-custom-cost': { + per_token_in?: number; + per_token_out?: number; + } | { + total_cost?: number; + } | string; + 'cf-aig-cache-ttl': number | string; + 'cf-aig-skip-cache': boolean | string; + 'cf-aig-cache-key': string; + 'cf-aig-event-id': string; + 'cf-aig-request-timeout': number | string; + 'cf-aig-max-attempts': number | string; + 'cf-aig-retry-delay': number | string; + 'cf-aig-backoff': string; + 'cf-aig-collect-log': boolean | string; + Authorization: string; + 'Content-Type': string; + [key: string]: string | number | boolean | object; +}; +type AIGatewayUniversalRequest = { + provider: AIGatewayProviders | string; // eslint-disable-line + endpoint: string; + headers: Partial; + query: unknown; +}; +interface AiGatewayInternalError extends Error { +} +interface AiGatewayLogNotFound extends Error { +} +declare abstract class AiGateway { + patchLog(logId: string, data: AiGatewayPatchLog): Promise; + getLog(logId: string): Promise; + run(data: AIGatewayUniversalRequest | AIGatewayUniversalRequest[], options?: { + gateway?: UniversalGatewayOptions; + extraHeaders?: object; + }): Promise; + getUrl(provider?: AIGatewayProviders | string): Promise; // eslint-disable-line +} +interface AutoRAGInternalError extends Error { +} +interface AutoRAGNotFoundError extends Error { +} +interface AutoRAGUnauthorizedError extends Error { +} +interface AutoRAGNameNotSetError extends Error { +} +type ComparisonFilter = { + key: string; + type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; + value: string | number | boolean; +}; +type CompoundFilter = { + type: 'and' | 'or'; + filters: ComparisonFilter[]; +}; +type AutoRagSearchRequest = { + query: string; + filters?: CompoundFilter | ComparisonFilter; + max_num_results?: number; + ranking_options?: { + ranker?: string; + score_threshold?: number; + }; + reranking?: { + enabled?: boolean; + model?: string; + }; + rewrite_query?: boolean; +}; +type AutoRagAiSearchRequest = AutoRagSearchRequest & { + stream?: boolean; + system_prompt?: string; +}; +type AutoRagAiSearchRequestStreaming = Omit & { + stream: true; +}; +type AutoRagSearchResponse = { + object: 'vector_store.search_results.page'; + search_query: string; + data: { + file_id: string; + filename: string; + score: number; + attributes: Record; + content: { + type: 'text'; + text: string; + }[]; + }[]; + has_more: boolean; + next_page: string | null; +}; +type AutoRagListResponse = { + id: string; + enable: boolean; + type: string; + source: string; + vectorize_name: string; + paused: boolean; + status: string; +}[]; +type AutoRagAiSearchResponse = AutoRagSearchResponse & { + response: string; +}; +declare abstract class AutoRAG { + list(): Promise; + search(params: AutoRagSearchRequest): Promise; + aiSearch(params: AutoRagAiSearchRequestStreaming): Promise; + aiSearch(params: AutoRagAiSearchRequest): Promise; + aiSearch(params: AutoRagAiSearchRequest): Promise; +} +interface BasicImageTransformations { + /** + * Maximum width in image pixels. The value must be an integer. + */ + width?: number; + /** + * Maximum height in image pixels. The value must be an integer. + */ + height?: number; + /** + * Resizing mode as a string. It affects interpretation of width and height + * options: + * - scale-down: Similar to contain, but the image is never enlarged. If + * the image is larger than given width or height, it will be resized. + * Otherwise its original size will be kept. + * - contain: Resizes to maximum size that fits within the given width and + * height. If only a single dimension is given (e.g. only width), the + * image will be shrunk or enlarged to exactly match that dimension. + * Aspect ratio is always preserved. + * - cover: Resizes (shrinks or enlarges) to fill the entire area of width + * and height. If the image has an aspect ratio different from the ratio + * of width and height, it will be cropped to fit. + * - crop: The image will be shrunk and cropped to fit within the area + * specified by width and height. The image will not be enlarged. For images + * smaller than the given dimensions it's the same as scale-down. For + * images larger than the given dimensions, it's the same as cover. + * See also trim. + * - pad: Resizes to the maximum size that fits within the given width and + * height, and then fills the remaining area with a background color + * (white by default). Use of this mode is not recommended, as the same + * effect can be more efficiently achieved with the contain mode and the + * CSS object-fit: contain property. + * - squeeze: Stretches and deforms to the width and height given, even if it + * breaks aspect ratio + */ + fit?: "scale-down" | "contain" | "cover" | "crop" | "pad" | "squeeze"; + /** + * Image segmentation using artificial intelligence models. Sets pixels not + * within selected segment area to transparent e.g "foreground" sets every + * background pixel as transparent. + */ + segment?: "foreground"; + /** + * When cropping with fit: "cover", this defines the side or point that should + * be left uncropped. The value is either a string + * "left", "right", "top", "bottom", "auto", or "center" (the default), + * or an object {x, y} containing focal point coordinates in the original + * image expressed as fractions ranging from 0.0 (top or left) to 1.0 + * (bottom or right), 0.5 being the center. {fit: "cover", gravity: "top"} will + * crop bottom or left and right sides as necessary, but won’t crop anything + * from the top. {fit: "cover", gravity: {x:0.5, y:0.2}} will crop each side to + * preserve as much as possible around a point at 20% of the height of the + * source image. + */ + gravity?: 'face' | 'left' | 'right' | 'top' | 'bottom' | 'center' | 'auto' | 'entropy' | BasicImageTransformationsGravityCoordinates; + /** + * Background color to add underneath the image. Applies only to images with + * transparency (such as PNG). Accepts any CSS color (#RRGGBB, rgba(â€Ļ), + * hsl(â€Ļ), etc.) + */ + background?: string; + /** + * Number of degrees (90, 180, 270) to rotate the image by. width and height + * options refer to axes after rotation. + */ + rotate?: 0 | 90 | 180 | 270 | 360; +} +interface BasicImageTransformationsGravityCoordinates { + x?: number; + y?: number; + mode?: 'remainder' | 'box-center'; +} +/** + * In addition to the properties you can set in the RequestInit dict + * that you pass as an argument to the Request constructor, you can + * set certain properties of a `cf` object to control how Cloudflare + * features are applied to that new Request. + * + * Note: Currently, these properties cannot be tested in the + * playground. + */ +interface RequestInitCfProperties extends Record { + cacheEverything?: boolean; + /** + * A request's cache key is what determines if two requests are + * "the same" for caching purposes. If a request has the same cache key + * as some previous request, then we can serve the same cached response for + * both. (e.g. 'some-key') + * + * Only available for Enterprise customers. + */ + cacheKey?: string; + /** + * This allows you to append additional Cache-Tag response headers + * to the origin response without modifications to the origin server. + * This will allow for greater control over the Purge by Cache Tag feature + * utilizing changes only in the Workers process. + * + * Only available for Enterprise customers. + */ + cacheTags?: string[]; + /** + * Force response to be cached for a given number of seconds. (e.g. 300) + */ + cacheTtl?: number; + /** + * Force response to be cached for a given number of seconds based on the Origin status code. + * (e.g. { '200-299': 86400, '404': 1, '500-599': 0 }) + */ + cacheTtlByStatus?: Record; + scrapeShield?: boolean; + apps?: boolean; + image?: RequestInitCfPropertiesImage; + minify?: RequestInitCfPropertiesImageMinify; + mirage?: boolean; + polish?: "lossy" | "lossless" | "off"; + r2?: RequestInitCfPropertiesR2; + /** + * Redirects the request to an alternate origin server. You can use this, + * for example, to implement load balancing across several origins. + * (e.g.us-east.example.com) + * + * Note - For security reasons, the hostname set in resolveOverride must + * be proxied on the same Cloudflare zone of the incoming request. + * Otherwise, the setting is ignored. CNAME hosts are allowed, so to + * resolve to a host under a different domain or a DNS only domain first + * declare a CNAME record within your own zone’s DNS mapping to the + * external hostname, set proxy on Cloudflare, then set resolveOverride + * to point to that CNAME record. + */ + resolveOverride?: string; +} +interface RequestInitCfPropertiesImageDraw extends BasicImageTransformations { + /** + * Absolute URL of the image file to use for the drawing. It can be any of + * the supported file formats. For drawing of watermarks or non-rectangular + * overlays we recommend using PNG or WebP images. + */ + url: string; + /** + * Floating-point number between 0 (transparent) and 1 (opaque). + * For example, opacity: 0.5 makes overlay semitransparent. + */ + opacity?: number; + /** + * - If set to true, the overlay image will be tiled to cover the entire + * area. This is useful for stock-photo-like watermarks. + * - If set to "x", the overlay image will be tiled horizontally only + * (form a line). + * - If set to "y", the overlay image will be tiled vertically only + * (form a line). + */ + repeat?: true | "x" | "y"; + /** + * Position of the overlay image relative to a given edge. Each property is + * an offset in pixels. 0 aligns exactly to the edge. For example, left: 10 + * positions left side of the overlay 10 pixels from the left edge of the + * image it's drawn over. bottom: 0 aligns bottom of the overlay with bottom + * of the background image. + * + * Setting both left & right, or both top & bottom is an error. + * + * If no position is specified, the image will be centered. + */ + top?: number; + left?: number; + bottom?: number; + right?: number; +} +interface RequestInitCfPropertiesImage extends BasicImageTransformations { + /** + * Device Pixel Ratio. Default 1. Multiplier for width/height that makes it + * easier to specify higher-DPI sizes in . + */ + dpr?: number; + /** + * Allows you to trim your image. Takes dpr into account and is performed before + * resizing or rotation. + * + * It can be used as: + * - left, top, right, bottom - it will specify the number of pixels to cut + * off each side + * - width, height - the width/height you'd like to end up with - can be used + * in combination with the properties above + * - border - this will automatically trim the surroundings of an image based on + * it's color. It consists of three properties: + * - color: rgb or hex representation of the color you wish to trim (todo: verify the rgba bit) + * - tolerance: difference from color to treat as color + * - keep: the number of pixels of border to keep + */ + trim?: "border" | { + top?: number; + bottom?: number; + left?: number; + right?: number; + width?: number; + height?: number; + border?: boolean | { + color?: string; + tolerance?: number; + keep?: number; + }; + }; + /** + * Quality setting from 1-100 (useful values are in 60-90 range). Lower values + * make images look worse, but load faster. The default is 85. It applies only + * to JPEG and WebP images. It doesn’t have any effect on PNG. + */ + quality?: number | "low" | "medium-low" | "medium-high" | "high"; + /** + * Output format to generate. It can be: + * - avif: generate images in AVIF format. + * - webp: generate images in Google WebP format. Set quality to 100 to get + * the WebP-lossless format. + * - json: instead of generating an image, outputs information about the + * image, in JSON format. The JSON object will contain image size + * (before and after resizing), source image’s MIME type, file size, etc. + * - jpeg: generate images in JPEG format. + * - png: generate images in PNG format. + */ + format?: "avif" | "webp" | "json" | "jpeg" | "png" | "baseline-jpeg" | "png-force" | "svg"; + /** + * Whether to preserve animation frames from input files. Default is true. + * Setting it to false reduces animations to still images. This setting is + * recommended when enlarging images or processing arbitrary user content, + * because large GIF animations can weigh tens or even hundreds of megabytes. + * It is also useful to set anim:false when using format:"json" to get the + * response quicker without the number of frames. + */ + anim?: boolean; + /** + * What EXIF data should be preserved in the output image. Note that EXIF + * rotation and embedded color profiles are always applied ("baked in" into + * the image), and aren't affected by this option. Note that if the Polish + * feature is enabled, all metadata may have been removed already and this + * option may have no effect. + * - keep: Preserve most of EXIF metadata, including GPS location if there's + * any. + * - copyright: Only keep the copyright tag, and discard everything else. + * This is the default behavior for JPEG files. + * - none: Discard all invisible EXIF metadata. Currently WebP and PNG + * output formats always discard metadata. + */ + metadata?: "keep" | "copyright" | "none"; + /** + * Strength of sharpening filter to apply to the image. Floating-point + * number between 0 (no sharpening, default) and 10 (maximum). 1.0 is a + * recommended value for downscaled images. + */ + sharpen?: number; + /** + * Radius of a blur filter (approximate gaussian). Maximum supported radius + * is 250. + */ + blur?: number; + /** + * Overlays are drawn in the order they appear in the array (last array + * entry is the topmost layer). + */ + draw?: RequestInitCfPropertiesImageDraw[]; + /** + * Fetching image from authenticated origin. Setting this property will + * pass authentication headers (Authorization, Cookie, etc.) through to + * the origin. + */ + "origin-auth"?: "share-publicly"; + /** + * Adds a border around the image. The border is added after resizing. Border + * width takes dpr into account, and can be specified either using a single + * width property, or individually for each side. + */ + border?: { + color: string; + width: number; + } | { + color: string; + top: number; + right: number; + bottom: number; + left: number; + }; + /** + * Increase brightness by a factor. A value of 1.0 equals no change, a value + * of 0.5 equals half brightness, and a value of 2.0 equals twice as bright. + * 0 is ignored. + */ + brightness?: number; + /** + * Increase contrast by a factor. A value of 1.0 equals no change, a value of + * 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is + * ignored. + */ + contrast?: number; + /** + * Increase exposure by a factor. A value of 1.0 equals no change, a value of + * 0.5 darkens the image, and a value of 2.0 lightens the image. 0 is ignored. + */ + gamma?: number; + /** + * Increase contrast by a factor. A value of 1.0 equals no change, a value of + * 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is + * ignored. + */ + saturation?: number; + /** + * Flips the images horizontally, vertically, or both. Flipping is applied before + * rotation, so if you apply flip=h,rotate=90 then the image will be flipped + * horizontally, then rotated by 90 degrees. + */ + flip?: 'h' | 'v' | 'hv'; + /** + * Slightly reduces latency on a cache miss by selecting a + * quickest-to-compress file format, at a cost of increased file size and + * lower image quality. It will usually override the format option and choose + * JPEG over WebP or AVIF. We do not recommend using this option, except in + * unusual circumstances like resizing uncacheable dynamically-generated + * images. + */ + compression?: "fast"; +} +interface RequestInitCfPropertiesImageMinify { + javascript?: boolean; + css?: boolean; + html?: boolean; +} +interface RequestInitCfPropertiesR2 { + /** + * Colo id of bucket that an object is stored in + */ + bucketColoId?: number; +} +/** + * Request metadata provided by Cloudflare's edge. + */ +type IncomingRequestCfProperties = IncomingRequestCfPropertiesBase & IncomingRequestCfPropertiesBotManagementEnterprise & IncomingRequestCfPropertiesCloudflareForSaaSEnterprise & IncomingRequestCfPropertiesGeographicInformation & IncomingRequestCfPropertiesCloudflareAccessOrApiShield; +interface IncomingRequestCfPropertiesBase extends Record { + /** + * [ASN](https://www.iana.org/assignments/as-numbers/as-numbers.xhtml) of the incoming request. + * + * @example 395747 + */ + asn?: number; + /** + * The organization which owns the ASN of the incoming request. + * + * @example "Google Cloud" + */ + asOrganization?: string; + /** + * The original value of the `Accept-Encoding` header if Cloudflare modified it. + * + * @example "gzip, deflate, br" + */ + clientAcceptEncoding?: string; + /** + * The number of milliseconds it took for the request to reach your worker. + * + * @example 22 + */ + clientTcpRtt?: number; + /** + * The three-letter [IATA](https://en.wikipedia.org/wiki/IATA_airport_code) + * airport code of the data center that the request hit. + * + * @example "DFW" + */ + colo: string; + /** + * Represents the upstream's response to a + * [TCP `keepalive` message](https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) + * from cloudflare. + * + * For workers with no upstream, this will always be `1`. + * + * @example 3 + */ + edgeRequestKeepAliveStatus: IncomingRequestCfPropertiesEdgeRequestKeepAliveStatus; + /** + * The HTTP Protocol the request used. + * + * @example "HTTP/2" + */ + httpProtocol: string; + /** + * The browser-requested prioritization information in the request object. + * + * If no information was set, defaults to the empty string `""` + * + * @example "weight=192;exclusive=0;group=3;group-weight=127" + * @default "" + */ + requestPriority: string; + /** + * The TLS version of the connection to Cloudflare. + * In requests served over plaintext (without TLS), this property is the empty string `""`. + * + * @example "TLSv1.3" + */ + tlsVersion: string; + /** + * The cipher for the connection to Cloudflare. + * In requests served over plaintext (without TLS), this property is the empty string `""`. + * + * @example "AEAD-AES128-GCM-SHA256" + */ + tlsCipher: string; + /** + * Metadata containing the [`HELLO`](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2) and [`FINISHED`](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9) messages from this request's TLS handshake. + * + * If the incoming request was served over plaintext (without TLS) this field is undefined. + */ + tlsExportedAuthenticator?: IncomingRequestCfPropertiesExportedAuthenticatorMetadata; +} +interface IncomingRequestCfPropertiesBotManagementBase { + /** + * Cloudflare’s [level of certainty](https://developers.cloudflare.com/bots/concepts/bot-score/) that a request comes from a bot, + * represented as an integer percentage between `1` (almost certainly a bot) and `99` (almost certainly human). + * + * @example 54 + */ + score: number; + /** + * A boolean value that is true if the request comes from a good bot, like Google or Bing. + * Most customers choose to allow this traffic. For more details, see [Traffic from known bots](https://developers.cloudflare.com/firewall/known-issues-and-faq/#how-does-firewall-rules-handle-traffic-from-known-bots). + */ + verifiedBot: boolean; + /** + * A boolean value that is true if the request originates from a + * Cloudflare-verified proxy service. + */ + corporateProxy: boolean; + /** + * A boolean value that's true if the request matches [file extensions](https://developers.cloudflare.com/bots/reference/static-resources/) for many types of static resources. + */ + staticResource: boolean; + /** + * List of IDs that correlate to the Bot Management heuristic detections made on a request (you can have multiple heuristic detections on the same request). + */ + detectionIds: number[]; +} +interface IncomingRequestCfPropertiesBotManagement { + /** + * Results of Cloudflare's Bot Management analysis + */ + botManagement: IncomingRequestCfPropertiesBotManagementBase; + /** + * Duplicate of `botManagement.score`. + * + * @deprecated + */ + clientTrustScore: number; +} +interface IncomingRequestCfPropertiesBotManagementEnterprise extends IncomingRequestCfPropertiesBotManagement { + /** + * Results of Cloudflare's Bot Management analysis + */ + botManagement: IncomingRequestCfPropertiesBotManagementBase & { + /** + * A [JA3 Fingerprint](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/) to help profile specific SSL/TLS clients + * across different destination IPs, Ports, and X509 certificates. + */ + ja3Hash: string; + }; +} +interface IncomingRequestCfPropertiesCloudflareForSaaSEnterprise { + /** + * Custom metadata set per-host in [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/). + * + * This field is only present if you have Cloudflare for SaaS enabled on your account + * and you have followed the [required steps to enable it]((https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/)). + */ + hostMetadata?: HostMetadata; +} +interface IncomingRequestCfPropertiesCloudflareAccessOrApiShield { + /** + * Information about the client certificate presented to Cloudflare. + * + * This is populated when the incoming request is served over TLS using + * either Cloudflare Access or API Shield (mTLS) + * and the presented SSL certificate has a valid + * [Certificate Serial Number](https://ldapwiki.com/wiki/Certificate%20Serial%20Number) + * (i.e., not `null` or `""`). + * + * Otherwise, a set of placeholder values are used. + * + * The property `certPresented` will be set to `"1"` when + * the object is populated (i.e. the above conditions were met). + */ + tlsClientAuth: IncomingRequestCfPropertiesTLSClientAuth | IncomingRequestCfPropertiesTLSClientAuthPlaceholder; +} +/** + * Metadata about the request's TLS handshake + */ +interface IncomingRequestCfPropertiesExportedAuthenticatorMetadata { + /** + * The client's [`HELLO` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2), encoded in hexadecimal + * + * @example "44372ba35fa1270921d318f34c12f155dc87b682cf36a790cfaa3ba8737a1b5d" + */ + clientHandshake: string; + /** + * The server's [`HELLO` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2), encoded in hexadecimal + * + * @example "44372ba35fa1270921d318f34c12f155dc87b682cf36a790cfaa3ba8737a1b5d" + */ + serverHandshake: string; + /** + * The client's [`FINISHED` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9), encoded in hexadecimal + * + * @example "084ee802fe1348f688220e2a6040a05b2199a761f33cf753abb1b006792d3f8b" + */ + clientFinished: string; + /** + * The server's [`FINISHED` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9), encoded in hexadecimal + * + * @example "084ee802fe1348f688220e2a6040a05b2199a761f33cf753abb1b006792d3f8b" + */ + serverFinished: string; +} +/** + * Geographic data about the request's origin. + */ +interface IncomingRequestCfPropertiesGeographicInformation { + /** + * The [ISO 3166-1 Alpha 2](https://www.iso.org/iso-3166-country-codes.html) country code the request originated from. + * + * If your worker is [configured to accept TOR connections](https://support.cloudflare.com/hc/en-us/articles/203306930-Understanding-Cloudflare-Tor-support-and-Onion-Routing), this may also be `"T1"`, indicating a request that originated over TOR. + * + * If Cloudflare is unable to determine where the request originated this property is omitted. + * + * The country code `"T1"` is used for requests originating on TOR. + * + * @example "GB" + */ + country?: Iso3166Alpha2Code | "T1"; + /** + * If present, this property indicates that the request originated in the EU + * + * @example "1" + */ + isEUCountry?: "1"; + /** + * A two-letter code indicating the continent the request originated from. + * + * @example "AN" + */ + continent?: ContinentCode; + /** + * The city the request originated from + * + * @example "Austin" + */ + city?: string; + /** + * Postal code of the incoming request + * + * @example "78701" + */ + postalCode?: string; + /** + * Latitude of the incoming request + * + * @example "30.27130" + */ + latitude?: string; + /** + * Longitude of the incoming request + * + * @example "-97.74260" + */ + longitude?: string; + /** + * Timezone of the incoming request + * + * @example "America/Chicago" + */ + timezone?: string; + /** + * If known, the ISO 3166-2 name for the first level region associated with + * the IP address of the incoming request + * + * @example "Texas" + */ + region?: string; + /** + * If known, the ISO 3166-2 code for the first-level region associated with + * the IP address of the incoming request + * + * @example "TX" + */ + regionCode?: string; + /** + * Metro code (DMA) of the incoming request + * + * @example "635" + */ + metroCode?: string; +} +/** Data about the incoming request's TLS certificate */ +interface IncomingRequestCfPropertiesTLSClientAuth { + /** Always `"1"`, indicating that the certificate was presented */ + certPresented: "1"; + /** + * Result of certificate verification. + * + * @example "FAILED:self signed certificate" + */ + certVerified: Exclude; + /** The presented certificate's revokation status. + * + * - A value of `"1"` indicates the certificate has been revoked + * - A value of `"0"` indicates the certificate has not been revoked + */ + certRevoked: "1" | "0"; + /** + * The certificate issuer's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) + * + * @example "CN=cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certIssuerDN: string; + /** + * The certificate subject's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) + * + * @example "CN=*.cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certSubjectDN: string; + /** + * The certificate issuer's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) ([RFC 2253](https://www.rfc-editor.org/rfc/rfc2253.html) formatted) + * + * @example "CN=cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certIssuerDNRFC2253: string; + /** + * The certificate subject's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) ([RFC 2253](https://www.rfc-editor.org/rfc/rfc2253.html) formatted) + * + * @example "CN=*.cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certSubjectDNRFC2253: string; + /** The certificate issuer's distinguished name (legacy policies) */ + certIssuerDNLegacy: string; + /** The certificate subject's distinguished name (legacy policies) */ + certSubjectDNLegacy: string; + /** + * The certificate's serial number + * + * @example "00936EACBE07F201DF" + */ + certSerial: string; + /** + * The certificate issuer's serial number + * + * @example "2489002934BDFEA34" + */ + certIssuerSerial: string; + /** + * The certificate's Subject Key Identifier + * + * @example "BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4" + */ + certSKI: string; + /** + * The certificate issuer's Subject Key Identifier + * + * @example "BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4" + */ + certIssuerSKI: string; + /** + * The certificate's SHA-1 fingerprint + * + * @example "6b9109f323999e52259cda7373ff0b4d26bd232e" + */ + certFingerprintSHA1: string; + /** + * The certificate's SHA-256 fingerprint + * + * @example "acf77cf37b4156a2708e34c4eb755f9b5dbbe5ebb55adfec8f11493438d19e6ad3f157f81fa3b98278453d5652b0c1fd1d71e5695ae4d709803a4d3f39de9dea" + */ + certFingerprintSHA256: string; + /** + * The effective starting date of the certificate + * + * @example "Dec 22 19:39:00 2018 GMT" + */ + certNotBefore: string; + /** + * The effective expiration date of the certificate + * + * @example "Dec 22 19:39:00 2018 GMT" + */ + certNotAfter: string; +} +/** Placeholder values for TLS Client Authorization */ +interface IncomingRequestCfPropertiesTLSClientAuthPlaceholder { + certPresented: "0"; + certVerified: "NONE"; + certRevoked: "0"; + certIssuerDN: ""; + certSubjectDN: ""; + certIssuerDNRFC2253: ""; + certSubjectDNRFC2253: ""; + certIssuerDNLegacy: ""; + certSubjectDNLegacy: ""; + certSerial: ""; + certIssuerSerial: ""; + certSKI: ""; + certIssuerSKI: ""; + certFingerprintSHA1: ""; + certFingerprintSHA256: ""; + certNotBefore: ""; + certNotAfter: ""; +} +/** Possible outcomes of TLS verification */ +declare type CertVerificationStatus = +/** Authentication succeeded */ +"SUCCESS" +/** No certificate was presented */ + | "NONE" +/** Failed because the certificate was self-signed */ + | "FAILED:self signed certificate" +/** Failed because the certificate failed a trust chain check */ + | "FAILED:unable to verify the first certificate" +/** Failed because the certificate not yet valid */ + | "FAILED:certificate is not yet valid" +/** Failed because the certificate is expired */ + | "FAILED:certificate has expired" +/** Failed for another unspecified reason */ + | "FAILED"; +/** + * An upstream endpoint's response to a TCP `keepalive` message from Cloudflare. + */ +declare type IncomingRequestCfPropertiesEdgeRequestKeepAliveStatus = 0 /** Unknown */ | 1 /** no keepalives (not found) */ | 2 /** no connection re-use, opening keepalive connection failed */ | 3 /** no connection re-use, keepalive accepted and saved */ | 4 /** connection re-use, refused by the origin server (`TCP FIN`) */ | 5; /** connection re-use, accepted by the origin server */ +/** ISO 3166-1 Alpha-2 codes */ +declare type Iso3166Alpha2Code = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GS" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW"; +/** The 2-letter continent codes Cloudflare uses */ +declare type ContinentCode = "AF" | "AN" | "AS" | "EU" | "NA" | "OC" | "SA"; +type CfProperties = IncomingRequestCfProperties | RequestInitCfProperties; +interface D1Meta { + duration: number; + size_after: number; + rows_read: number; + rows_written: number; + last_row_id: number; + changed_db: boolean; + changes: number; + /** + * The region of the database instance that executed the query. + */ + served_by_region?: string; + /** + * True if-and-only-if the database instance that executed the query was the primary. + */ + served_by_primary?: boolean; + timings?: { + /** + * The duration of the SQL query execution by the database instance. It doesn't include any network time. + */ + sql_duration_ms: number; + }; + /** + * Number of total attempts to execute the query, due to automatic retries. + * Note: All other fields in the response like `timings` only apply to the last attempt. + */ + total_attempts?: number; +} +interface D1Response { + success: true; + meta: D1Meta & Record; + error?: never; +} +type D1Result = D1Response & { + results: T[]; +}; +interface D1ExecResult { + count: number; + duration: number; +} +type D1SessionConstraint = +// Indicates that the first query should go to the primary, and the rest queries +// using the same D1DatabaseSession will go to any replica that is consistent with +// the bookmark maintained by the session (returned by the first query). +'first-primary' +// Indicates that the first query can go anywhere (primary or replica), and the rest queries +// using the same D1DatabaseSession will go to any replica that is consistent with +// the bookmark maintained by the session (returned by the first query). + | 'first-unconstrained'; +type D1SessionBookmark = string; +declare abstract class D1Database { + prepare(query: string): D1PreparedStatement; + batch(statements: D1PreparedStatement[]): Promise[]>; + exec(query: string): Promise; + /** + * Creates a new D1 Session anchored at the given constraint or the bookmark. + * All queries executed using the created session will have sequential consistency, + * meaning that all writes done through the session will be visible in subsequent reads. + * + * @param constraintOrBookmark Either the session constraint or the explicit bookmark to anchor the created session. + */ + withSession(constraintOrBookmark?: D1SessionBookmark | D1SessionConstraint): D1DatabaseSession; + /** + * @deprecated dump() will be removed soon, only applies to deprecated alpha v1 databases. + */ + dump(): Promise; +} +declare abstract class D1DatabaseSession { + prepare(query: string): D1PreparedStatement; + batch(statements: D1PreparedStatement[]): Promise[]>; + /** + * @returns The latest session bookmark across all executed queries on the session. + * If no query has been executed yet, `null` is returned. + */ + getBookmark(): D1SessionBookmark | null; +} +declare abstract class D1PreparedStatement { + bind(...values: unknown[]): D1PreparedStatement; + first(colName: string): Promise; + first>(): Promise; + run>(): Promise>; + all>(): Promise>; + raw(options: { + columnNames: true; + }): Promise<[ + string[], + ...T[] + ]>; + raw(options?: { + columnNames?: false; + }): Promise; +} +// `Disposable` was added to TypeScript's standard lib types in version 5.2. +// To support older TypeScript versions, define an empty `Disposable` interface. +// Users won't be able to use `using`/`Symbol.dispose` without upgrading to 5.2, +// but this will ensure type checking on older versions still passes. +// TypeScript's interface merging will ensure our empty interface is effectively +// ignored when `Disposable` is included in the standard lib. +interface Disposable { +} +/** + * An email message that can be sent from a Worker. + */ +interface EmailMessage { + /** + * Envelope From attribute of the email message. + */ + readonly from: string; + /** + * Envelope To attribute of the email message. + */ + readonly to: string; +} +/** + * An email message that is sent to a consumer Worker and can be rejected/forwarded. + */ +interface ForwardableEmailMessage extends EmailMessage { + /** + * Stream of the email message content. + */ + readonly raw: ReadableStream; + /** + * An [Headers object](https://developer.mozilla.org/en-US/docs/Web/API/Headers). + */ + readonly headers: Headers; + /** + * Size of the email message content. + */ + readonly rawSize: number; + /** + * Reject this email message by returning a permanent SMTP error back to the connecting client including the given reason. + * @param reason The reject reason. + * @returns void + */ + setReject(reason: string): void; + /** + * Forward this email message to a verified destination address of the account. + * @param rcptTo Verified destination address. + * @param headers A [Headers object](https://developer.mozilla.org/en-US/docs/Web/API/Headers). + * @returns A promise that resolves when the email message is forwarded. + */ + forward(rcptTo: string, headers?: Headers): Promise; + /** + * Reply to the sender of this email message with a new EmailMessage object. + * @param message The reply message. + * @returns A promise that resolves when the email message is replied. + */ + reply(message: EmailMessage): Promise; +} +/** + * A binding that allows a Worker to send email messages. + */ +interface SendEmail { + send(message: EmailMessage): Promise; +} +declare abstract class EmailEvent extends ExtendableEvent { + readonly message: ForwardableEmailMessage; +} +declare type EmailExportedHandler = (message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext) => void | Promise; +declare module "cloudflare:email" { + let _EmailMessage: { + prototype: EmailMessage; + new (from: string, to: string, raw: ReadableStream | string): EmailMessage; + }; + export { _EmailMessage as EmailMessage }; +} +/** + * Hello World binding to serve as an explanatory example. DO NOT USE + */ +interface HelloWorldBinding { + /** + * Retrieve the current stored value + */ + get(): Promise<{ + value: string; + ms?: number; + }>; + /** + * Set a new stored value + */ + set(value: string): Promise; +} +interface Hyperdrive { + /** + * Connect directly to Hyperdrive as if it's your database, returning a TCP socket. + * + * Calling this method returns an idential socket to if you call + * `connect("host:port")` using the `host` and `port` fields from this object. + * Pick whichever approach works better with your preferred DB client library. + * + * Note that this socket is not yet authenticated -- it's expected that your + * code (or preferably, the client library of your choice) will authenticate + * using the information in this class's readonly fields. + */ + connect(): Socket; + /** + * A valid DB connection string that can be passed straight into the typical + * client library/driver/ORM. This will typically be the easiest way to use + * Hyperdrive. + */ + readonly connectionString: string; + /* + * A randomly generated hostname that is only valid within the context of the + * currently running Worker which, when passed into `connect()` function from + * the "cloudflare:sockets" module, will connect to the Hyperdrive instance + * for your database. + */ + readonly host: string; + /* + * The port that must be paired the the host field when connecting. + */ + readonly port: number; + /* + * The username to use when authenticating to your database via Hyperdrive. + * Unlike the host and password, this will be the same every time + */ + readonly user: string; + /* + * The randomly generated password to use when authenticating to your + * database via Hyperdrive. Like the host field, this password is only valid + * within the context of the currently running Worker instance from which + * it's read. + */ + readonly password: string; + /* + * The name of the database to connect to. + */ + readonly database: string; +} +// Copyright (c) 2024 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +type ImageInfoResponse = { + format: 'image/svg+xml'; +} | { + format: string; + fileSize: number; + width: number; + height: number; +}; +type ImageTransform = { + width?: number; + height?: number; + background?: string; + blur?: number; + border?: { + color?: string; + width?: number; + } | { + top?: number; + bottom?: number; + left?: number; + right?: number; + }; + brightness?: number; + contrast?: number; + fit?: 'scale-down' | 'contain' | 'pad' | 'squeeze' | 'cover' | 'crop'; + flip?: 'h' | 'v' | 'hv'; + gamma?: number; + segment?: 'foreground'; + gravity?: 'face' | 'left' | 'right' | 'top' | 'bottom' | 'center' | 'auto' | 'entropy' | { + x?: number; + y?: number; + mode: 'remainder' | 'box-center'; + }; + rotate?: 0 | 90 | 180 | 270; + saturation?: number; + sharpen?: number; + trim?: 'border' | { + top?: number; + bottom?: number; + left?: number; + right?: number; + width?: number; + height?: number; + border?: boolean | { + color?: string; + tolerance?: number; + keep?: number; + }; + }; +}; +type ImageDrawOptions = { + opacity?: number; + repeat?: boolean | string; + top?: number; + left?: number; + bottom?: number; + right?: number; +}; +type ImageInputOptions = { + encoding?: 'base64'; +}; +type ImageOutputOptions = { + format: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'image/avif' | 'rgb' | 'rgba'; + quality?: number; + background?: string; + anim?: boolean; +}; +interface ImagesBinding { + /** + * Get image metadata (type, width and height) + * @throws {@link ImagesError} with code 9412 if input is not an image + * @param stream The image bytes + */ + info(stream: ReadableStream, options?: ImageInputOptions): Promise; + /** + * Begin applying a series of transformations to an image + * @param stream The image bytes + * @returns A transform handle + */ + input(stream: ReadableStream, options?: ImageInputOptions): ImageTransformer; +} +interface ImageTransformer { + /** + * Apply transform next, returning a transform handle. + * You can then apply more transformations, draw, or retrieve the output. + * @param transform + */ + transform(transform: ImageTransform): ImageTransformer; + /** + * Draw an image on this transformer, returning a transform handle. + * You can then apply more transformations, draw, or retrieve the output. + * @param image The image (or transformer that will give the image) to draw + * @param options The options configuring how to draw the image + */ + draw(image: ReadableStream | ImageTransformer, options?: ImageDrawOptions): ImageTransformer; + /** + * Retrieve the image that results from applying the transforms to the + * provided input + * @param options Options that apply to the output e.g. output format + */ + output(options: ImageOutputOptions): Promise; +} +type ImageTransformationOutputOptions = { + encoding?: 'base64'; +}; +interface ImageTransformationResult { + /** + * The image as a response, ready to store in cache or return to users + */ + response(): Response; + /** + * The content type of the returned image + */ + contentType(): string; + /** + * The bytes of the response + */ + image(options?: ImageTransformationOutputOptions): ReadableStream; +} +interface ImagesError extends Error { + readonly code: number; + readonly message: string; + readonly stack?: string; +} +/** + * Media binding for transforming media streams. + * Provides the entry point for media transformation operations. + */ +interface MediaBinding { + /** + * Creates a media transformer from an input stream. + * @param media - The input media bytes + * @returns A MediaTransformer instance for applying transformations + */ + input(media: ReadableStream): MediaTransformer; +} +/** + * Media transformer for applying transformation operations to media content. + * Handles sizing, fitting, and other input transformation parameters. + */ +interface MediaTransformer { + /** + * Applies transformation options to the media content. + * @param transform - Configuration for how the media should be transformed + * @returns A generator for producing the transformed media output + */ + transform(transform: MediaTransformationInputOptions): MediaTransformationGenerator; +} +/** + * Generator for producing media transformation results. + * Configures the output format and parameters for the transformed media. + */ +interface MediaTransformationGenerator { + /** + * Generates the final media output with specified options. + * @param output - Configuration for the output format and parameters + * @returns The final transformation result containing the transformed media + */ + output(output: MediaTransformationOutputOptions): MediaTransformationResult; +} +/** + * Result of a media transformation operation. + * Provides multiple ways to access the transformed media content. + */ +interface MediaTransformationResult { + /** + * Returns the transformed media as a readable stream of bytes. + * @returns A stream containing the transformed media data + */ + media(): ReadableStream; + /** + * Returns the transformed media as an HTTP response object. + * @returns The transformed media as a Response, ready to store in cache or return to users + */ + response(): Response; + /** + * Returns the MIME type of the transformed media. + * @returns The content type string (e.g., 'image/jpeg', 'video/mp4') + */ + contentType(): string; +} +/** + * Configuration options for transforming media input. + * Controls how the media should be resized and fitted. + */ +type MediaTransformationInputOptions = { + /** How the media should be resized to fit the specified dimensions */ + fit?: 'contain' | 'cover' | 'scale-down'; + /** Target width in pixels */ + width?: number; + /** Target height in pixels */ + height?: number; +}; +/** + * Configuration options for Media Transformations output. + * Controls the format, timing, and type of the generated output. + */ +type MediaTransformationOutputOptions = { + /** + * Output mode determining the type of media to generate + */ + mode?: 'video' | 'spritesheet' | 'frame' | 'audio'; + /** Whether to include audio in the output */ + audio?: boolean; + /** + * Starting timestamp for frame extraction or start time for clips. (e.g. '2s'). + */ + time?: string; + /** + * Duration for video clips, audio extraction, and spritesheet generation (e.g. '5s'). + */ + duration?: string; + /** + * Number of frames in the spritesheet. + */ + imageCount?: number; + /** + * Output format for the generated media. + */ + format?: 'jpg' | 'png' | 'm4a'; +}; +/** + * Error object for media transformation operations. + * Extends the standard Error interface with additional media-specific information. + */ +interface MediaError extends Error { + readonly code: number; + readonly message: string; + readonly stack?: string; +} +declare module 'cloudflare:node' { + interface NodeStyleServer { + listen(...args: unknown[]): this; + address(): { + port?: number | null | undefined; + }; + } + export function httpServerHandler(port: number): ExportedHandler; + export function httpServerHandler(options: { + port: number; + }): ExportedHandler; + export function httpServerHandler(server: NodeStyleServer): ExportedHandler; +} +type Params

= Record; +type EventContext = { + request: Request>; + functionPath: string; + waitUntil: (promise: Promise) => void; + passThroughOnException: () => void; + next: (input?: Request | string, init?: RequestInit) => Promise; + env: Env & { + ASSETS: { + fetch: typeof fetch; + }; + }; + params: Params

; + data: Data; +}; +type PagesFunction = Record> = (context: EventContext) => Response | Promise; +type EventPluginContext = { + request: Request>; + functionPath: string; + waitUntil: (promise: Promise) => void; + passThroughOnException: () => void; + next: (input?: Request | string, init?: RequestInit) => Promise; + env: Env & { + ASSETS: { + fetch: typeof fetch; + }; + }; + params: Params

; + data: Data; + pluginArgs: PluginArgs; +}; +type PagesPluginFunction = Record, PluginArgs = unknown> = (context: EventPluginContext) => Response | Promise; +declare module "assets:*" { + export const onRequest: PagesFunction; +} +// Copyright (c) 2022-2023 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +declare module "cloudflare:pipelines" { + export abstract class PipelineTransformationEntrypoint { + protected env: Env; + protected ctx: ExecutionContext; + constructor(ctx: ExecutionContext, env: Env); + /** + * run recieves an array of PipelineRecord which can be + * transformed and returned to the pipeline + * @param records Incoming records from the pipeline to be transformed + * @param metadata Information about the specific pipeline calling the transformation entrypoint + * @returns A promise containing the transformed PipelineRecord array + */ + public run(records: I[], metadata: PipelineBatchMetadata): Promise; + } + export type PipelineRecord = Record; + export type PipelineBatchMetadata = { + pipelineId: string; + pipelineName: string; + }; + export interface Pipeline { + /** + * The Pipeline interface represents the type of a binding to a Pipeline + * + * @param records The records to send to the pipeline + */ + send(records: T[]): Promise; + } +} +// PubSubMessage represents an incoming PubSub message. +// The message includes metadata about the broker, the client, and the payload +// itself. +// https://developers.cloudflare.com/pub-sub/ +interface PubSubMessage { + // Message ID + readonly mid: number; + // MQTT broker FQDN in the form mqtts://BROKER.NAMESPACE.cloudflarepubsub.com:PORT + readonly broker: string; + // The MQTT topic the message was sent on. + readonly topic: string; + // The client ID of the client that published this message. + readonly clientId: string; + // The unique identifier (JWT ID) used by the client to authenticate, if token + // auth was used. + readonly jti?: string; + // A Unix timestamp (seconds from Jan 1, 1970), set when the Pub/Sub Broker + // received the message from the client. + readonly receivedAt: number; + // An (optional) string with the MIME type of the payload, if set by the + // client. + readonly contentType: string; + // Set to 1 when the payload is a UTF-8 string + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901063 + readonly payloadFormatIndicator: number; + // Pub/Sub (MQTT) payloads can be UTF-8 strings, or byte arrays. + // You can use payloadFormatIndicator to inspect this before decoding. + payload: string | Uint8Array; +} +// JsonWebKey extended by kid parameter +interface JsonWebKeyWithKid extends JsonWebKey { + // Key Identifier of the JWK + readonly kid: string; +} +interface RateLimitOptions { + key: string; +} +interface RateLimitOutcome { + success: boolean; +} +interface RateLimit { + /** + * Rate limit a request based on the provided options. + * @see https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/ + * @returns A promise that resolves with the outcome of the rate limit. + */ + limit(options: RateLimitOptions): Promise; +} +// Namespace for RPC utility types. Unfortunately, we can't use a `module` here as these types need +// to referenced by `Fetcher`. This is included in the "importable" version of the types which +// strips all `module` blocks. +declare namespace Rpc { + // Branded types for identifying `WorkerEntrypoint`/`DurableObject`/`Target`s. + // TypeScript uses *structural* typing meaning anything with the same shape as type `T` is a `T`. + // For the classes exported by `cloudflare:workers` we want *nominal* typing (i.e. we only want to + // accept `WorkerEntrypoint` from `cloudflare:workers`, not any other class with the same shape) + export const __RPC_STUB_BRAND: '__RPC_STUB_BRAND'; + export const __RPC_TARGET_BRAND: '__RPC_TARGET_BRAND'; + export const __WORKER_ENTRYPOINT_BRAND: '__WORKER_ENTRYPOINT_BRAND'; + export const __DURABLE_OBJECT_BRAND: '__DURABLE_OBJECT_BRAND'; + export const __WORKFLOW_ENTRYPOINT_BRAND: '__WORKFLOW_ENTRYPOINT_BRAND'; + export interface RpcTargetBranded { + [__RPC_TARGET_BRAND]: never; + } + export interface WorkerEntrypointBranded { + [__WORKER_ENTRYPOINT_BRAND]: never; + } + export interface DurableObjectBranded { + [__DURABLE_OBJECT_BRAND]: never; + } + export interface WorkflowEntrypointBranded { + [__WORKFLOW_ENTRYPOINT_BRAND]: never; + } + export type EntrypointBranded = WorkerEntrypointBranded | DurableObjectBranded | WorkflowEntrypointBranded; + // Types that can be used through `Stub`s + export type Stubable = RpcTargetBranded | ((...args: any[]) => any); + // Types that can be passed over RPC + // The reason for using a generic type here is to build a serializable subset of structured + // cloneable composite types. This allows types defined with the "interface" keyword to pass the + // serializable check as well. Otherwise, only types defined with the "type" keyword would pass. + type Serializable = + // Structured cloneables + BaseType + // Structured cloneable composites + | Map ? Serializable : never, T extends Map ? Serializable : never> | Set ? Serializable : never> | ReadonlyArray ? Serializable : never> | { + [K in keyof T]: K extends number | string ? Serializable : never; + } + // Special types + | Stub + // Serialized as stubs, see `Stubify` + | Stubable; + // Base type for all RPC stubs, including common memory management methods. + // `T` is used as a marker type for unwrapping `Stub`s later. + interface StubBase extends Disposable { + [__RPC_STUB_BRAND]: T; + dup(): this; + } + export type Stub = Provider & StubBase; + // This represents all the types that can be sent as-is over an RPC boundary + type BaseType = void | undefined | null | boolean | number | bigint | string | TypedArray | ArrayBuffer | DataView | Date | Error | RegExp | ReadableStream | WritableStream | Request | Response | Headers; + // Recursively rewrite all `Stubable` types with `Stub`s + // prettier-ignore + type Stubify = T extends Stubable ? Stub : T extends Map ? Map, Stubify> : T extends Set ? Set> : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> : T extends BaseType ? T : T extends { + [key: string | number]: any; + } ? { + [K in keyof T]: Stubify; + } : T; + // Recursively rewrite all `Stub`s with the corresponding `T`s. + // Note we use `StubBase` instead of `Stub` here to avoid circular dependencies: + // `Stub` depends on `Provider`, which depends on `Unstubify`, which would depend on `Stub`. + // prettier-ignore + type Unstubify = T extends StubBase ? V : T extends Map ? Map, Unstubify> : T extends Set ? Set> : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> : T extends BaseType ? T : T extends { + [key: string | number]: unknown; + } ? { + [K in keyof T]: Unstubify; + } : T; + type UnstubifyAll = { + [I in keyof A]: Unstubify; + }; + // Utility type for adding `Provider`/`Disposable`s to `object` types only. + // Note `unknown & T` is equivalent to `T`. + type MaybeProvider = T extends object ? Provider : unknown; + type MaybeDisposable = T extends object ? Disposable : unknown; + // Type for method return or property on an RPC interface. + // - Stubable types are replaced by stubs. + // - Serializable types are passed by value, with stubable types replaced by stubs + // and a top-level `Disposer`. + // Everything else can't be passed over PRC. + // Technically, we use custom thenables here, but they quack like `Promise`s. + // Intersecting with `(Maybe)Provider` allows pipelining. + // prettier-ignore + type Result = R extends Stubable ? Promise> & Provider : R extends Serializable ? Promise & MaybeDisposable> & MaybeProvider : never; + // Type for method or property on an RPC interface. + // For methods, unwrap `Stub`s in parameters, and rewrite returns to be `Result`s. + // Unwrapping `Stub`s allows calling with `Stubable` arguments. + // For properties, rewrite types to be `Result`s. + // In each case, unwrap `Promise`s. + type MethodOrProperty = V extends (...args: infer P) => infer R ? (...args: UnstubifyAll

) => Result> : Result>; + // Type for the callable part of an `Provider` if `T` is callable. + // This is intersected with methods/properties. + type MaybeCallableProvider = T extends (...args: any[]) => any ? MethodOrProperty : unknown; + // Base type for all other types providing RPC-like interfaces. + // Rewrites all methods/properties to be `MethodOrProperty`s, while preserving callable types. + // `Reserved` names (e.g. stub method names like `dup()`) and symbols can't be accessed over RPC. + export type Provider = MaybeCallableProvider & Pick<{ + [K in keyof T]: MethodOrProperty; + }, Exclude>>; +} +declare namespace Cloudflare { + // Type of `env`. + // + // The specific project can extend `Env` by redeclaring it in project-specific files. Typescript + // will merge all declarations. + // + // You can use `wrangler types` to generate the `Env` type automatically. + interface Env { + } + // Project-specific parameters used to inform types. + // + // This interface is, again, intended to be declared in project-specific files, and then that + // declaration will be merged with this one. + // + // A project should have a declaration like this: + // + // interface GlobalProps { + // // Declares the main module's exports. Used to populate Cloudflare.Exports aka the type + // // of `ctx.exports`. + // mainModule: typeof import("my-main-module"); + // + // // Declares which of the main module's exports are configured with durable storage, and + // // thus should behave as Durable Object namsepace bindings. + // durableNamespaces: "MyDurableObject" | "AnotherDurableObject"; + // } + // + // You can use `wrangler types` to generate `GlobalProps` automatically. + interface GlobalProps { + } + // Evaluates to the type of a property in GlobalProps, defaulting to `Default` if it is not + // present. + type GlobalProp = K extends keyof GlobalProps ? GlobalProps[K] : Default; + // The type of the program's main module exports, if known. Requires `GlobalProps` to declare the + // `mainModule` property. + type MainModule = GlobalProp<"mainModule", {}>; + // The type of ctx.exports, which contains loopback bindings for all top-level exports. + type Exports = { + [K in keyof MainModule]: LoopbackForExport + // If the export is listed in `durableNamespaces`, then it is also a + // DurableObjectNamespace. + & (K extends GlobalProp<"durableNamespaces", never> ? MainModule[K] extends new (...args: any[]) => infer DoInstance ? DoInstance extends Rpc.DurableObjectBranded ? DurableObjectNamespace : DurableObjectNamespace : DurableObjectNamespace : {}); + }; +} +declare namespace CloudflareWorkersModule { + export type RpcStub = Rpc.Stub; + export const RpcStub: { + new (value: T): Rpc.Stub; + }; + export abstract class RpcTarget implements Rpc.RpcTargetBranded { + [Rpc.__RPC_TARGET_BRAND]: never; + } + // `protected` fields don't appear in `keyof`s, so can't be accessed over RPC + export abstract class WorkerEntrypoint implements Rpc.WorkerEntrypointBranded { + [Rpc.__WORKER_ENTRYPOINT_BRAND]: never; + protected ctx: ExecutionContext; + protected env: Env; + constructor(ctx: ExecutionContext, env: Env); + email?(message: ForwardableEmailMessage): void | Promise; + fetch?(request: Request): Response | Promise; + queue?(batch: MessageBatch): void | Promise; + scheduled?(controller: ScheduledController): void | Promise; + tail?(events: TraceItem[]): void | Promise; + tailStream?(event: TailStream.TailEvent): TailStream.TailEventHandlerType | Promise; + test?(controller: TestController): void | Promise; + trace?(traces: TraceItem[]): void | Promise; + } + export abstract class DurableObject implements Rpc.DurableObjectBranded { + [Rpc.__DURABLE_OBJECT_BRAND]: never; + protected ctx: DurableObjectState; + protected env: Env; + constructor(ctx: DurableObjectState, env: Env); + alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise; + fetch?(request: Request): Response | Promise; + webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise; + webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise; + webSocketError?(ws: WebSocket, error: unknown): void | Promise; + } + export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; + export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; + export type WorkflowDelayDuration = WorkflowSleepDuration; + export type WorkflowTimeoutDuration = WorkflowSleepDuration; + export type WorkflowRetentionDuration = WorkflowSleepDuration; + export type WorkflowBackoff = 'constant' | 'linear' | 'exponential'; + export type WorkflowStepConfig = { + retries?: { + limit: number; + delay: WorkflowDelayDuration | number; + backoff?: WorkflowBackoff; + }; + timeout?: WorkflowTimeoutDuration | number; + }; + export type WorkflowEvent = { + payload: Readonly; + timestamp: Date; + instanceId: string; + }; + export type WorkflowStepEvent = { + payload: Readonly; + timestamp: Date; + type: string; + }; + export abstract class WorkflowStep { + do>(name: string, callback: () => Promise): Promise; + do>(name: string, config: WorkflowStepConfig, callback: () => Promise): Promise; + sleep: (name: string, duration: WorkflowSleepDuration) => Promise; + sleepUntil: (name: string, timestamp: Date | number) => Promise; + waitForEvent>(name: string, options: { + type: string; + timeout?: WorkflowTimeoutDuration | number; + }): Promise>; + } + export abstract class WorkflowEntrypoint | unknown = unknown> implements Rpc.WorkflowEntrypointBranded { + [Rpc.__WORKFLOW_ENTRYPOINT_BRAND]: never; + protected ctx: ExecutionContext; + protected env: Env; + constructor(ctx: ExecutionContext, env: Env); + run(event: Readonly>, step: WorkflowStep): Promise; + } + export function waitUntil(promise: Promise): void; + export function withEnv(newEnv: unknown, fn: () => unknown): unknown; + export function withExports(newExports: unknown, fn: () => unknown): unknown; + export function withEnvAndExports(newEnv: unknown, newExports: unknown, fn: () => unknown): unknown; + export const env: Cloudflare.Env; + export const exports: Cloudflare.Exports; +} +declare module 'cloudflare:workers' { + export = CloudflareWorkersModule; +} +interface SecretsStoreSecret { + /** + * Get a secret from the Secrets Store, returning a string of the secret value + * if it exists, or throws an error if it does not exist + */ + get(): Promise; +} +declare module "cloudflare:sockets" { + function _connect(address: string | SocketAddress, options?: SocketOptions): Socket; + export { _connect as connect }; +} +type MarkdownDocument = { + name: string; + blob: Blob; +}; +type ConversionResponse = { + name: string; + mimeType: string; + format: 'markdown'; + tokens: number; + data: string; +} | { + name: string; + mimeType: string; + format: 'error'; + error: string; +}; +type ImageConversionOptions = { + descriptionLanguage?: 'en' | 'es' | 'fr' | 'it' | 'pt' | 'de'; +}; +type EmbeddedImageConversionOptions = ImageConversionOptions & { + convert?: boolean; + maxConvertedImages?: number; +}; +type ConversionOptions = { + html?: { + images?: EmbeddedImageConversionOptions & { + convertOGImage?: boolean; + }; + }; + docx?: { + images?: EmbeddedImageConversionOptions; + }; + image?: ImageConversionOptions; + pdf?: { + images?: EmbeddedImageConversionOptions; + metadata?: boolean; + }; +}; +type ConversionRequestOptions = { + gateway?: GatewayOptions; + extraHeaders?: object; + conversionOptions?: ConversionOptions; +}; +type SupportedFileFormat = { + mimeType: string; + extension: string; +}; +declare abstract class ToMarkdownService { + transform(files: MarkdownDocument[], options?: ConversionRequestOptions): Promise; + transform(files: MarkdownDocument, options?: ConversionRequestOptions): Promise; + supported(): Promise; +} +declare namespace TailStream { + interface Header { + readonly name: string; + readonly value: string; + } + interface FetchEventInfo { + readonly type: "fetch"; + readonly method: string; + readonly url: string; + readonly cfJson?: object; + readonly headers: Header[]; + } + interface JsRpcEventInfo { + readonly type: "jsrpc"; + } + interface ScheduledEventInfo { + readonly type: "scheduled"; + readonly scheduledTime: Date; + readonly cron: string; + } + interface AlarmEventInfo { + readonly type: "alarm"; + readonly scheduledTime: Date; + } + interface QueueEventInfo { + readonly type: "queue"; + readonly queueName: string; + readonly batchSize: number; + } + interface EmailEventInfo { + readonly type: "email"; + readonly mailFrom: string; + readonly rcptTo: string; + readonly rawSize: number; + } + interface TraceEventInfo { + readonly type: "trace"; + readonly traces: (string | null)[]; + } + interface HibernatableWebSocketEventInfoMessage { + readonly type: "message"; + } + interface HibernatableWebSocketEventInfoError { + readonly type: "error"; + } + interface HibernatableWebSocketEventInfoClose { + readonly type: "close"; + readonly code: number; + readonly wasClean: boolean; + } + interface HibernatableWebSocketEventInfo { + readonly type: "hibernatableWebSocket"; + readonly info: HibernatableWebSocketEventInfoClose | HibernatableWebSocketEventInfoError | HibernatableWebSocketEventInfoMessage; + } + interface CustomEventInfo { + readonly type: "custom"; + } + interface FetchResponseInfo { + readonly type: "fetch"; + readonly statusCode: number; + } + type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound"; + interface ScriptVersion { + readonly id: string; + readonly tag?: string; + readonly message?: string; + } + interface Onset { + readonly type: "onset"; + readonly attributes: Attribute[]; + // id for the span being opened by this Onset event. + readonly spanId: string; + readonly dispatchNamespace?: string; + readonly entrypoint?: string; + readonly executionModel: string; + readonly scriptName?: string; + readonly scriptTags?: string[]; + readonly scriptVersion?: ScriptVersion; + readonly info: FetchEventInfo | JsRpcEventInfo | ScheduledEventInfo | AlarmEventInfo | QueueEventInfo | EmailEventInfo | TraceEventInfo | HibernatableWebSocketEventInfo | CustomEventInfo; + } + interface Outcome { + readonly type: "outcome"; + readonly outcome: EventOutcome; + readonly cpuTime: number; + readonly wallTime: number; + } + interface SpanOpen { + readonly type: "spanOpen"; + readonly name: string; + // id for the span being opened by this SpanOpen event. + readonly spanId: string; + readonly info?: FetchEventInfo | JsRpcEventInfo | Attributes; + } + interface SpanClose { + readonly type: "spanClose"; + readonly outcome: EventOutcome; + } + interface DiagnosticChannelEvent { + readonly type: "diagnosticChannel"; + readonly channel: string; + readonly message: any; + } + interface Exception { + readonly type: "exception"; + readonly name: string; + readonly message: string; + readonly stack?: string; + } + interface Log { + readonly type: "log"; + readonly level: "debug" | "error" | "info" | "log" | "warn"; + readonly message: object; + } + // This marks the worker handler return information. + // This is separate from Outcome because the worker invocation can live for a long time after + // returning. For example - Websockets that return an http upgrade response but then continue + // streaming information or SSE http connections. + interface Return { + readonly type: "return"; + readonly info?: FetchResponseInfo; + } + interface Attribute { + readonly name: string; + readonly value: string | string[] | boolean | boolean[] | number | number[] | bigint | bigint[]; + } + interface Attributes { + readonly type: "attributes"; + readonly info: Attribute[]; + } + type EventType = Onset | Outcome | SpanOpen | SpanClose | DiagnosticChannelEvent | Exception | Log | Return | Attributes; + // Context in which this trace event lives. + interface SpanContext { + // Single id for the entire top-level invocation + // This should be a new traceId for the first worker stage invoked in the eyeball request and then + // same-account service-bindings should reuse the same traceId but cross-account service-bindings + // should use a new traceId. + readonly traceId: string; + // spanId in which this event is handled + // for Onset and SpanOpen events this would be the parent span id + // for Outcome and SpanClose these this would be the span id of the opening Onset and SpanOpen events + // For Hibernate and Mark this would be the span under which they were emitted. + // spanId is not set ONLY if: + // 1. This is an Onset event + // 2. We are not inherting any SpanContext. (e.g. this is a cross-account service binding or a new top-level invocation) + readonly spanId?: string; + } + interface TailEvent { + // invocation id of the currently invoked worker stage. + // invocation id will always be unique to every Onset event and will be the same until the Outcome event. + readonly invocationId: string; + // Inherited spanContext for this event. + readonly spanContext: SpanContext; + readonly timestamp: Date; + readonly sequence: number; + readonly event: Event; + } + type TailEventHandler = (event: TailEvent) => void | Promise; + type TailEventHandlerObject = { + outcome?: TailEventHandler; + spanOpen?: TailEventHandler; + spanClose?: TailEventHandler; + diagnosticChannel?: TailEventHandler; + exception?: TailEventHandler; + log?: TailEventHandler; + return?: TailEventHandler; + attributes?: TailEventHandler; + }; + type TailEventHandlerType = TailEventHandler | TailEventHandlerObject; +} +// Copyright (c) 2022-2023 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +/** + * Data types supported for holding vector metadata. + */ +type VectorizeVectorMetadataValue = string | number | boolean | string[]; +/** + * Additional information to associate with a vector. + */ +type VectorizeVectorMetadata = VectorizeVectorMetadataValue | Record; +type VectorFloatArray = Float32Array | Float64Array; +interface VectorizeError { + code?: number; + error: string; +} +/** + * Comparison logic/operation to use for metadata filtering. + * + * This list is expected to grow as support for more operations are released. + */ +type VectorizeVectorMetadataFilterOp = '$eq' | '$ne' | '$lt' | '$lte' | '$gt' | '$gte'; +type VectorizeVectorMetadataFilterCollectionOp = '$in' | '$nin'; +/** + * Filter criteria for vector metadata used to limit the retrieved query result set. + */ +type VectorizeVectorMetadataFilter = { + [field: string]: Exclude | null | { + [Op in VectorizeVectorMetadataFilterOp]?: Exclude | null; + } | { + [Op in VectorizeVectorMetadataFilterCollectionOp]?: Exclude[]; + }; +}; +/** + * Supported distance metrics for an index. + * Distance metrics determine how other "similar" vectors are determined. + */ +type VectorizeDistanceMetric = "euclidean" | "cosine" | "dot-product"; +/** + * Metadata return levels for a Vectorize query. + * + * Default to "none". + * + * @property all Full metadata for the vector return set, including all fields (including those un-indexed) without truncation. This is a more expensive retrieval, as it requires additional fetching & reading of un-indexed data. + * @property indexed Return all metadata fields configured for indexing in the vector return set. This level of retrieval is "free" in that no additional overhead is incurred returning this data. However, note that indexed metadata is subject to truncation (especially for larger strings). + * @property none No indexed metadata will be returned. + */ +type VectorizeMetadataRetrievalLevel = "all" | "indexed" | "none"; +interface VectorizeQueryOptions { + topK?: number; + namespace?: string; + returnValues?: boolean; + returnMetadata?: boolean | VectorizeMetadataRetrievalLevel; + filter?: VectorizeVectorMetadataFilter; +} +/** + * Information about the configuration of an index. + */ +type VectorizeIndexConfig = { + dimensions: number; + metric: VectorizeDistanceMetric; +} | { + preset: string; // keep this generic, as we'll be adding more presets in the future and this is only in a read capacity +}; +/** + * Metadata about an existing index. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link VectorizeIndexInfo} for its post-beta equivalent. + */ +interface VectorizeIndexDetails { + /** The unique ID of the index */ + readonly id: string; + /** The name of the index. */ + name: string; + /** (optional) A human readable description for the index. */ + description?: string; + /** The index configuration, including the dimension size and distance metric. */ + config: VectorizeIndexConfig; + /** The number of records containing vectors within the index. */ + vectorsCount: number; +} +/** + * Metadata about an existing index. + */ +interface VectorizeIndexInfo { + /** The number of records containing vectors within the index. */ + vectorCount: number; + /** Number of dimensions the index has been configured for. */ + dimensions: number; + /** ISO 8601 datetime of the last processed mutation on in the index. All changes before this mutation will be reflected in the index state. */ + processedUpToDatetime: number; + /** UUIDv4 of the last mutation processed by the index. All changes before this mutation will be reflected in the index state. */ + processedUpToMutation: number; +} +/** + * Represents a single vector value set along with its associated metadata. + */ +interface VectorizeVector { + /** The ID for the vector. This can be user-defined, and must be unique. It should uniquely identify the object, and is best set based on the ID of what the vector represents. */ + id: string; + /** The vector values */ + values: VectorFloatArray | number[]; + /** The namespace this vector belongs to. */ + namespace?: string; + /** Metadata associated with the vector. Includes the values of other fields and potentially additional details. */ + metadata?: Record; +} +/** + * Represents a matched vector for a query along with its score and (if specified) the matching vector information. + */ +type VectorizeMatch = Pick, "values"> & Omit & { + /** The score or rank for similarity, when returned as a result */ + score: number; +}; +/** + * A set of matching {@link VectorizeMatch} for a particular query. + */ +interface VectorizeMatches { + matches: VectorizeMatch[]; + count: number; +} +/** + * Results of an operation that performed a mutation on a set of vectors. + * Here, `ids` is a list of vectors that were successfully processed. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link VectorizeAsyncMutation} for its post-beta equivalent. + */ +interface VectorizeVectorMutation { + /* List of ids of vectors that were successfully processed. */ + ids: string[]; + /* Total count of the number of processed vectors. */ + count: number; +} +/** + * Result type indicating a mutation on the Vectorize Index. + * Actual mutations are processed async where the `mutationId` is the unique identifier for the operation. + */ +interface VectorizeAsyncMutation { + /** The unique identifier for the async mutation operation containing the changeset. */ + mutationId: string; +} +/** + * A Vectorize Vector Search Index for querying vectors/embeddings. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link Vectorize} for its new implementation. + */ +declare abstract class VectorizeIndex { + /** + * Get information about the currently bound index. + * @returns A promise that resolves with information about the current index. + */ + public describe(): Promise; + /** + * Use the provided vector to perform a similarity search across the index. + * @param vector Input vector that will be used to drive the similarity search. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public query(vector: VectorFloatArray | number[], options?: VectorizeQueryOptions): Promise; + /** + * Insert a list of vectors into the index dataset. If a provided id exists, an error will be thrown. + * @param vectors List of vectors that will be inserted. + * @returns A promise that resolves with the ids & count of records that were successfully processed. + */ + public insert(vectors: VectorizeVector[]): Promise; + /** + * Upsert a list of vectors into the index dataset. If a provided id exists, it will be replaced with the new values. + * @param vectors List of vectors that will be upserted. + * @returns A promise that resolves with the ids & count of records that were successfully processed. + */ + public upsert(vectors: VectorizeVector[]): Promise; + /** + * Delete a list of vectors with a matching id. + * @param ids List of vector ids that should be deleted. + * @returns A promise that resolves with the ids & count of records that were successfully processed (and thus deleted). + */ + public deleteByIds(ids: string[]): Promise; + /** + * Get a list of vectors with a matching id. + * @param ids List of vector ids that should be returned. + * @returns A promise that resolves with the raw unscored vectors matching the id set. + */ + public getByIds(ids: string[]): Promise; +} +/** + * A Vectorize Vector Search Index for querying vectors/embeddings. + * + * Mutations in this version are async, returning a mutation id. + */ +declare abstract class Vectorize { + /** + * Get information about the currently bound index. + * @returns A promise that resolves with information about the current index. + */ + public describe(): Promise; + /** + * Use the provided vector to perform a similarity search across the index. + * @param vector Input vector that will be used to drive the similarity search. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public query(vector: VectorFloatArray | number[], options?: VectorizeQueryOptions): Promise; + /** + * Use the provided vector-id to perform a similarity search across the index. + * @param vectorId Id for a vector in the index against which the index should be queried. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public queryById(vectorId: string, options?: VectorizeQueryOptions): Promise; + /** + * Insert a list of vectors into the index dataset. If a provided id exists, an error will be thrown. + * @param vectors List of vectors that will be inserted. + * @returns A promise that resolves with a unique identifier of a mutation containing the insert changeset. + */ + public insert(vectors: VectorizeVector[]): Promise; + /** + * Upsert a list of vectors into the index dataset. If a provided id exists, it will be replaced with the new values. + * @param vectors List of vectors that will be upserted. + * @returns A promise that resolves with a unique identifier of a mutation containing the upsert changeset. + */ + public upsert(vectors: VectorizeVector[]): Promise; + /** + * Delete a list of vectors with a matching id. + * @param ids List of vector ids that should be deleted. + * @returns A promise that resolves with a unique identifier of a mutation containing the delete changeset. + */ + public deleteByIds(ids: string[]): Promise; + /** + * Get a list of vectors with a matching id. + * @param ids List of vector ids that should be returned. + * @returns A promise that resolves with the raw unscored vectors matching the id set. + */ + public getByIds(ids: string[]): Promise; +} +/** + * The interface for "version_metadata" binding + * providing metadata about the Worker Version using this binding. + */ +type WorkerVersionMetadata = { + /** The ID of the Worker Version using this binding */ + id: string; + /** The tag of the Worker Version using this binding */ + tag: string; + /** The timestamp of when the Worker Version was uploaded */ + timestamp: string; +}; +interface DynamicDispatchLimits { + /** + * Limit CPU time in milliseconds. + */ + cpuMs?: number; + /** + * Limit number of subrequests. + */ + subRequests?: number; +} +interface DynamicDispatchOptions { + /** + * Limit resources of invoked Worker script. + */ + limits?: DynamicDispatchLimits; + /** + * Arguments for outbound Worker script, if configured. + */ + outbound?: { + [key: string]: any; + }; +} +interface DispatchNamespace { + /** + * @param name Name of the Worker script. + * @param args Arguments to Worker script. + * @param options Options for Dynamic Dispatch invocation. + * @returns A Fetcher object that allows you to send requests to the Worker script. + * @throws If the Worker script does not exist in this dispatch namespace, an error will be thrown. + */ + get(name: string, args?: { + [key: string]: any; + }, options?: DynamicDispatchOptions): Fetcher; +} +declare module 'cloudflare:workflows' { + /** + * NonRetryableError allows for a user to throw a fatal error + * that makes a Workflow instance fail immediately without triggering a retry + */ + export class NonRetryableError extends Error { + public constructor(message: string, name?: string); + } +} +declare abstract class Workflow { + /** + * Get a handle to an existing instance of the Workflow. + * @param id Id for the instance of this Workflow + * @returns A promise that resolves with a handle for the Instance + */ + public get(id: string): Promise; + /** + * Create a new instance and return a handle to it. If a provided id exists, an error will be thrown. + * @param options Options when creating an instance including id and params + * @returns A promise that resolves with a handle for the Instance + */ + public create(options?: WorkflowInstanceCreateOptions): Promise; + /** + * Create a batch of instances and return handle for all of them. If a provided id exists, an error will be thrown. + * `createBatch` is limited at 100 instances at a time or when the RPC limit for the batch (1MiB) is reached. + * @param batch List of Options when creating an instance including name and params + * @returns A promise that resolves with a list of handles for the created instances. + */ + public createBatch(batch: WorkflowInstanceCreateOptions[]): Promise; +} +type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; +type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; +type WorkflowRetentionDuration = WorkflowSleepDuration; +interface WorkflowInstanceCreateOptions { + /** + * An id for your Workflow instance. Must be unique within the Workflow. + */ + id?: string; + /** + * The event payload the Workflow instance is triggered with + */ + params?: PARAMS; + /** + * The retention policy for Workflow instance. + * Defaults to the maximum retention period available for the owner's account. + */ + retention?: { + successRetention?: WorkflowRetentionDuration; + errorRetention?: WorkflowRetentionDuration; + }; +} +type InstanceStatus = { + status: 'queued' // means that instance is waiting to be started (see concurrency limits) + | 'running' | 'paused' | 'errored' | 'terminated' // user terminated the instance while it was running + | 'complete' | 'waiting' // instance is hibernating and waiting for sleep or event to finish + | 'waitingForPause' // instance is finishing the current work to pause + | 'unknown'; + error?: { + name: string; + message: string; + }; + output?: unknown; +}; +interface WorkflowError { + code?: number; + message: string; +} +declare abstract class WorkflowInstance { + public id: string; + /** + * Pause the instance. + */ + public pause(): Promise; + /** + * Resume the instance. If it is already running, an error will be thrown. + */ + public resume(): Promise; + /** + * Terminate the instance. If it is errored, terminated or complete, an error will be thrown. + */ + public terminate(): Promise; + /** + * Restart the instance. + */ + public restart(): Promise; + /** + * Returns the current status of the instance. + */ + public status(): Promise; + /** + * Send an event to this instance. + */ + public sendEvent({ type, payload, }: { + type: string; + payload: unknown; + }): Promise; +} diff --git a/test/cloudflare-workers/features/fixtures/cloudflare-worker/wrangler.jsonc b/test/cloudflare-workers/features/fixtures/cloudflare-worker/wrangler.jsonc new file mode 100644 index 0000000000..cf4f84876b --- /dev/null +++ b/test/cloudflare-workers/features/fixtures/cloudflare-worker/wrangler.jsonc @@ -0,0 +1,18 @@ +/** + * For more details on how to configure Wrangler, refer to: + * https://developers.cloudflare.com/workers/wrangler/configuration/ + */ +{ + "$schema": "node_modules/wrangler/config-schema.json", + "name": "cloudflare-worker", + "main": "src/index.ts", + "compatibility_date": "2025-12-16", + "compatibility_flags": [ + "nodejs_compat" + ], + "vars": { + "BUGSNAG_API_KEY": "placeholder-api-key", + "BUGSNAG_NOTIFY_ENDPOINT": "placeholder-notify-endpoint", + "BUGSNAG_SESSIONS_ENDPOINT": "placeholder-sessions-endpoint" + } +} \ No newline at end of file diff --git a/test/cloudflare-workers/features/scripts/build-fixtures.rb b/test/cloudflare-workers/features/scripts/build-fixtures.rb new file mode 100755 index 0000000000..d493f3f496 --- /dev/null +++ b/test/cloudflare-workers/features/scripts/build-fixtures.rb @@ -0,0 +1,117 @@ +#!/usr/bin/env ruby + +require "fileutils" + +# Allow specifying a specific fixture to build by passing it's name as an argument +# e.g. ./build-fixtures simple-app +SPECIFIC_FIXTURE = ARGV.first + +# Allow debugging by logging more verbosely and not tidying up packed packages +DEBUG = ["1", "true", true].include?(ENV.fetch("DEBUG", false)) + +# The root of bugsnag-js +ROOT = File.realpath("#{__dir__}/../../../../") + +# Bugsnag packages that we need to pack & install into the fixtures +BUGSNAG_PACKAGES = [ + "core", + "delivery-node", + "in-flight", + "js", + "node", + "plugin-app-duration", + "plugin-cloudflare-workers", + "plugin-contextualize", + "plugin-express", + "plugin-hono", + "plugin-intercept", + "plugin-node-device", + "plugin-node-in-project", + "plugin-node-surrounding-code", + "plugin-node-uncaught-exception", + "plugin-node-unhandled-rejection", + "plugin-server-session", + "plugin-strip-project-root", +] + +def heading(message) + <<~HEADING + ====#{"=" * message.length}==== + = #{message} = + ====#{"=" * message.length}==== + HEADING +end + +# Build Bugsnag packages so they're ready to install +def build + Dir.chdir(ROOT) do + system("npm ci") + system("npm run build") + end +end + +# Run "npm pack" on the required packages and strip the version suffix so they +# can be depended on in a package.json file +def pack + puts heading("Packing Bugsnag packages") + + BUGSNAG_PACKAGES.each do |package| + path = "#{ROOT}/packages/#{package}" + flags = DEBUG ? "--verbose" : "--quiet" + + success = system("npm pack #{flags} #{path}/") + + raise "Failed to pack #{package}" unless success + end + + # Strip the version suffix from the packages + Dir["#{FileUtils.pwd}/bugsnag-*.tgz"].each do |package| + package_with_no_version = package.gsub(/-\d+\.\d+\.\d+.*(?=\.tgz)/, '') + File.rename(package, package_with_no_version) + end +end + +# Install the packed packages in each fixture and build the fixture +def install_and_build + Dir["#{__dir__}/../fixtures/*"].each do |fixture| + fixture = File.realpath(fixture) + fixture_name = File.basename(fixture) + + if SPECIFIC_FIXTURE && SPECIFIC_FIXTURE != fixture_name + puts heading("Not building #{fixture_name} because it's not '#{SPECIFIC_FIXTURE}'") + next + end + + puts heading("Installing Bugsnag packages in #{fixture_name}") + + FileUtils.copy(Dir["#{FileUtils.pwd}/bugsnag-*.tgz"], fixture) + system("npm install --prefix #{fixture} #{fixture}/bugsnag-*.tgz") + + unless DEBUG + # Remove the packages from the fixture directories as they aren't + # needed anymore. A built lambda has them in its node_modules directory + FileUtils.remove(Dir["#{fixture}/bugsnag-*.tgz"]) + + end + + end +end + +# Tidy up PWD by removing all the packed packages created by "pack" +def tidy_up + return if DEBUG + + puts heading("Tidying up PWD") + + FileUtils.remove(Dir["#{FileUtils.pwd}/bugsnag-*.tgz"]) +end + +begin + build + pack + install_and_build +ensure + tidy_up + + puts "Done!" +end diff --git a/test/cloudflare-workers/features/scripts/start-fixture.rb b/test/cloudflare-workers/features/scripts/start-fixture.rb new file mode 100644 index 0000000000..b06c4948d1 --- /dev/null +++ b/test/cloudflare-workers/features/scripts/start-fixture.rb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require "fileutils" + +FIXTURE_NAME = ARGV.first + +FIXTURE_DIR = File.realpath("#{__dir__}/../fixtures/#{FIXTURE_NAME}") + +Dir.chdir(FIXTURE_DIR) do + system("npm run start") +end \ No newline at end of file diff --git a/test/cloudflare-workers/features/steps/cloudflare-steps.rb b/test/cloudflare-workers/features/steps/cloudflare-steps.rb new file mode 100644 index 0000000000..0b84e1f1a8 --- /dev/null +++ b/test/cloudflare-workers/features/steps/cloudflare-steps.rb @@ -0,0 +1,57 @@ +require 'net/http' + +When('I start the worker {string}') do |fixture| + steps %Q{ + Given I store the api key in the environment variable "BUGSNAG_API_KEY" + And I set environment variable "BUGSNAG_NOTIFY_ENDPOINT" to "http://localhost:#{Maze.config.port}/notify" + And I set environment variable "BUGSNAG_SESSIONS_ENDPOINT" to "http://localhost:#{Maze.config.port}/sessions" + } + + command = "ruby #{File.realpath("#{__dir__}/../scripts/start-fixture.rb")} #{fixture}" + Maze::Runner.run_command(command, blocking: false) +end + +Then('I open the URL {string} and get a {int} response') do |url, expected_response_code| + begin + response = Net::HTTP.get_response(URI(url)) + rescue + $logger.debug $!.inspect + end + + Maze.check.equal( + expected_response_code, + response.code.to_i, + <<~TEXT + Unexpected response code "#{response.code}" received. Response body: + + #{response.body} + TEXT + ) +end + +When('I open the URL {string} and get a {int} response with body {string}') do |url, expected_response_code, expected_response_body| + begin + response = Net::HTTP.get_response(URI(url)) + rescue + $logger.debug $!.inspect + end + + Maze.check.equal( + expected_response_code, + response.code.to_i, + <<~TEXT + Unexpected response code "#{response.code}" received. Response body: + + #{response.body} + TEXT + ) + Maze.check.equal( + expected_response_body, + response.body, + <<~TEXT + Unexpected response body received. Response body: + + #{response.body} + TEXT + ) +end \ No newline at end of file diff --git a/test/cloudflare-workers/features/support/env.rb b/test/cloudflare-workers/features/support/env.rb new file mode 100644 index 0000000000..332bb09db9 --- /dev/null +++ b/test/cloudflare-workers/features/support/env.rb @@ -0,0 +1,16 @@ +BeforeAll do + success = system(File.realpath("#{__dir__}/../scripts/build-fixtures.rb")) + + unless success + puts "Unable to build fixtures!" + exit 1 + end + + Maze.config.enforce_bugsnag_integrity = false + Maze.config.receive_no_requests_wait = 10 + Maze.config.receive_requests_wait = 10 +end + +After do + Maze::Runner.kill_running_scripts +end \ No newline at end of file From cd8fcba5a0bfcb98685b9e54e33080348fad73b6 Mon Sep 17 00:00:00 2001 From: Yousif Ahmed <74918474+yousif-bugsnag@users.noreply.github.com> Date: Tue, 6 Jan 2026 09:20:34 +0000 Subject: [PATCH 40/43] test(react-native): fix react-navigation tests and dependencies (#2650) --- .../react-native-android-full-pipeline.yml | 54 ++++++---- .../basic/react-native-android-pipeline.yml | 2 + .../basic/react-native-ios-full-pipeline.yml | 54 ++++++---- .../basic/react-native-ios-pipeline.yml | 2 + docker-compose.yml | 1 + scripts/generate-react-native-fixture.js | 99 ++++++++++++++----- .../scenario-launcher/{src => }/index.js | 0 .../{src => }/lib/CommandRunner.js | 0 .../{src => }/lib/ConfigFileReader.js | 0 .../NativeBugsnagTestInterface.ts | 0 .../{src => }/lib/ScenarioLauncher.js | 0 .../scenario-launcher/{src => }/lib/native.js | 0 .../fixtures/scenario-launcher/package.json | 27 +++-- .../core}/AppConfigAppTypeScenario.js | 0 ...onfigEnabledReleaseStagesNoSendScenario.js | 0 .../AppConfigEnabledReleaseStagesScenario.js | 0 .../core}/AppConfigReleaseStageScenario.js | 0 .../core}/AppJsHandledScenario.js | 0 .../core}/AppJsUnhandledScenario.js | 0 .../core}/AppNativeHandledScenario.js | 2 +- .../core}/AppNativeUnhandledScenario.js | 2 +- .../BreadcrumbsAutomaticErrorScenario.js | 0 .../BreadcrumbsAutomaticLoadedScenario.js | 0 .../core}/BreadcrumbsJsManualScenario.js | 0 .../core}/BreadcrumbsNativeManualScenario.js | 2 +- ...rumbsNullEnabledBreadcrumbTypesScenario.js | 0 .../core}/ContextJsCustomScenario.js | 0 .../core}/ContextJsDefaultScenario.js | 0 .../core}/ContextNativeCustomScenario.js | 2 +- .../core}/DeviceJsHandledScenario.js | 0 .../core}/DeviceJsUnhandledScenario.js | 0 .../core}/DeviceNativeHandledScenario.js | 2 +- .../core}/DeviceNativeUnhandledScenario.js | 2 +- .../core}/EventApiKeyOverrideScenario.js | 0 .../core}/FeatureFlagsNativeCrashScenario.js | 2 +- .../core}/FeatureFlagsScenario.js | 0 .../GroupingDiscriminatorNativeScenario.js | 2 +- .../core}/GroupingDiscriminatorScenario.js | 0 .../core}/HandledJsErrorScenario.js | 0 .../core}/HandledNativeErrorScenario.js | 2 +- .../core}/HandledOverrideJsErrorScenario.js | 0 .../core}/MetadataJsScenario.js | 0 .../core}/MetadataNativeScenario.js | 2 +- .../core}/MetadataNativeUnhandledScenario.js | 2 +- .../core}/NativeFeatureFlagsScenario.js | 2 +- .../NativePromiseRejectionHandledScenario.js | 2 +- ...NativePromiseRejectionUnhandledScenario.js | 2 +- .../core}/RCTFatalScenario.js | 2 +- .../core}/ReactNativeErrorBoundaryScenario.js | 0 .../scenarios => scenarios/core}/Scenario.js | 0 .../core}/SessionAutoDisabledScenario.js | 0 .../core}/SessionAutoEnabledScenario.js | 0 .../SessionJsControlledManualJsScenario.js | 0 ...SessionJsControlledManualNativeScenario.js | 2 +- ...SessionNativeControlledManualJsScenario.js | 2 +- .../core}/UnhandledJsErrorScenario.js | 0 .../core}/UnhandledJsErrorSeverityScenario.js | 0 ...dledJsPromiseRejectionAsHandledScenario.js | 0 .../UnhandledJsPromiseRejectionScenario.js | 0 .../core}/UnhandledNativeErrorScenario.js | 2 +- .../core}/UnhandledNativeErrorSyncScenario.js | 2 +- .../core}/UnhandledOverrideJsErrorScenario.js | 0 .../core}/UserJsClientScenario.js | 0 .../core}/UserJsConfigScenario.js | 0 .../core}/UserJsEventScenario.js | 0 .../core}/UserJsNativeScenario.js | 2 +- .../core}/UserNativeClientScenario.js | 2 +- .../scenarios => scenarios/core}/index.js | 8 -- .../scenario-launcher/scenarios/index.js | 1 + ...veNavigationBreadcrumbsDisabledScenario.js | 2 +- ...iveNavigationBreadcrumbsEnabledScenario.js | 2 +- .../react-native-navigation/index.js | 3 + ...ctNavigationBreadcrumbsDisabledScenario.js | 2 +- ...actNavigationBreadcrumbsEnabledScenario.js | 2 +- .../scenarios/react-navigation/index.js | 3 + .../scenario-launcher/scripts/cleanup.js | 19 ++++ .../scripts/prepare-package.js | 34 +++++++ .../features/react-navigation.feature | 2 +- test/react-native/features/support/env.rb | 4 + 79 files changed, 252 insertions(+), 111 deletions(-) rename test/react-native/features/fixtures/scenario-launcher/{src => }/index.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src => }/lib/CommandRunner.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src => }/lib/ConfigFileReader.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src => lib}/NativeBugsnagTestInterface.ts (100%) rename test/react-native/features/fixtures/scenario-launcher/{src => }/lib/ScenarioLauncher.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src => }/lib/native.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppConfigAppTypeScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppConfigEnabledReleaseStagesNoSendScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppConfigEnabledReleaseStagesScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppConfigReleaseStageScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppJsHandledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppJsUnhandledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppNativeHandledScenario.js (85%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/AppNativeUnhandledScenario.js (86%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/BreadcrumbsAutomaticErrorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/BreadcrumbsAutomaticLoadedScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/BreadcrumbsJsManualScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/BreadcrumbsNativeManualScenario.js (78%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/BreadcrumbsNullEnabledBreadcrumbTypesScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/ContextJsCustomScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/ContextJsDefaultScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/ContextNativeCustomScenario.js (85%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/DeviceJsHandledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/DeviceJsUnhandledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/DeviceNativeHandledScenario.js (77%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/DeviceNativeUnhandledScenario.js (77%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/EventApiKeyOverrideScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/FeatureFlagsNativeCrashScenario.js (91%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/FeatureFlagsScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/GroupingDiscriminatorNativeScenario.js (92%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/GroupingDiscriminatorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/HandledJsErrorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/HandledNativeErrorScenario.js (77%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/HandledOverrideJsErrorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/MetadataJsScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/MetadataNativeScenario.js (90%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/MetadataNativeUnhandledScenario.js (90%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/NativeFeatureFlagsScenario.js (92%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/NativePromiseRejectionHandledScenario.js (85%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/NativePromiseRejectionUnhandledScenario.js (80%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/RCTFatalScenario.js (75%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/ReactNativeErrorBoundaryScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/Scenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/SessionAutoDisabledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/SessionAutoEnabledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/SessionJsControlledManualJsScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/SessionJsControlledManualNativeScenario.js (94%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/SessionNativeControlledManualJsScenario.js (96%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledJsErrorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledJsErrorSeverityScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledJsPromiseRejectionAsHandledScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledJsPromiseRejectionScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledNativeErrorScenario.js (77%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledNativeErrorSyncScenario.js (78%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UnhandledOverrideJsErrorScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UserJsClientScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UserJsConfigScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UserJsEventScenario.js (100%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UserJsNativeScenario.js (85%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/UserNativeClientScenario.js (76%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/core}/index.js (89%) create mode 100644 test/react-native/features/fixtures/scenario-launcher/scenarios/index.js rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/react-native-navigation}/ReactNativeNavigationBreadcrumbsDisabledScenario.js (97%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/react-native-navigation}/ReactNativeNavigationBreadcrumbsEnabledScenario.js (97%) create mode 100644 test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/index.js rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/react-navigation}/ReactNavigationBreadcrumbsDisabledScenario.js (98%) rename test/react-native/features/fixtures/scenario-launcher/{src/scenarios => scenarios/react-navigation}/ReactNavigationBreadcrumbsEnabledScenario.js (97%) create mode 100644 test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/index.js create mode 100644 test/react-native/features/fixtures/scenario-launcher/scripts/cleanup.js create mode 100644 test/react-native/features/fixtures/scenario-launcher/scripts/prepare-package.js diff --git a/.buildkite/basic/react-native-android-full-pipeline.yml b/.buildkite/basic/react-native-android-full-pipeline.yml index 6a5ba2aa9d..7c0c1081fc 100644 --- a/.buildkite/basic/react-native-android-full-pipeline.yml +++ b/.buildkite/basic/react-native-android-full-pipeline.yml @@ -19,6 +19,7 @@ steps: RN_VERSION: "{{matrix.reactnative}}" RCT_NEW_ARCH_ENABLED: "0" BUILD_ANDROID: "true" + REACT_NAVIGATION: "true" artifact_paths: - "test/react-native/features/fixtures/generated/old-arch/**/reactnative.apk" commands: @@ -51,7 +52,7 @@ steps: - exit_status: "*" limit: 1 - - label: ':android: Build RN {{matrix}} test fixture APK (New Arch)' + - label: ':android: Build RN {{matrix.reactnative}} test fixture APK (New Arch)' key: "build-react-native-android-fixture-new-arch-full" timeout_in_minutes: 15 agents: @@ -59,9 +60,10 @@ steps: env: JAVA_VERSION: "17" NODE_VERSION: "22" - RN_VERSION: "{{matrix}}" + RN_VERSION: "{{matrix.reactnative}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_ANDROID: "true" + REACT_NAVIGATION: "{{matrix.reactnavigation}}" artifact_paths: - "test/react-native/features/fixtures/generated/new-arch/**/reactnative.apk" commands: @@ -72,12 +74,19 @@ steps: - exit_status: "*" limit: 1 matrix: - - "0.72" - - "0.74" - - "0.76" - - "0.78" - - "0.80" - - "0.81" + setup: + reactnative: + - "0.74" + - "0.76" + - "0.78" + - "0.80" + - "0.81" + reactnavigation: + - "true" + adjustments: + - with: + reactnative: "0.72" + reactnavigation: "false" - label: ':android: Build react-native-navigation {{matrix}} test fixture APK (Old Arch)' skip: true # Skipped pending PLAT-15027 @@ -165,6 +174,7 @@ steps: env: RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "0" + REACT_NAVIGATION: "true" concurrency: 25 concurrency_group: "bitbar" concurrency_method: eager @@ -181,19 +191,19 @@ steps: # current latest version (v7.40.1) of react-native-navigation's autolinking tool doesn't support RN 0.73+, # causing a build failure - see https://github.com/wix/react-native-navigation/issues/7821 # TODO: Investigate and try to re-enable when we add tests for more recent React Native versions - - label: ":bitbar: :android: RN {{matrix}} Android 12 (New Arch) end-to-end tests" + - label: ":bitbar: :android: RN {{matrix.reactnative}} Android 12 (New Arch) end-to-end tests" depends_on: "build-react-native-android-fixture-new-arch-full" timeout_in_minutes: 30 plugins: artifacts#v1.9.0: - download: "test/react-native/features/fixtures/generated/new-arch/{{matrix}}/reactnative.apk" + download: "test/react-native/features/fixtures/generated/new-arch/{{matrix.reactnative}}/reactnative.apk" upload: ./test/react-native/maze_output/**/* docker-compose#v4.12.0: pull: react-native-maze-runner run: react-native-maze-runner service-ports: true command: - - --app=/app/features/fixtures/generated/new-arch/{{matrix}}/reactnative.apk + - --app=/app/features/fixtures/generated/new-arch/{{matrix.reactnative}}/reactnative.apk - --farm=bb - --device=ANDROID_12 - --appium-version=1.22 @@ -213,17 +223,25 @@ steps: limit: 2 env: RCT_NEW_ARCH_ENABLED: "1" - RN_VERSION: "{{matrix}}" + RN_VERSION: "{{matrix.reactnative}}" + REACT_NAVIGATION: "{{matrix.reactnavigation}}" concurrency: 25 concurrency_group: "bitbar" concurrency_method: eager matrix: - - "0.72" - - "0.74" - - "0.76" - - "0.78" - - "0.80" - - "0.81" + setup: + reactnative: + - "0.74" + - "0.76" + - "0.78" + - "0.80" + - "0.81" + reactnavigation: + - "true" + adjustments: + - with: + reactnative: "0.72" + reactnavigation: "false" - label: ":bitbar: :android: react-native-navigation {{matrix}} Android 12 (Old Arch) end-to-end tests" skip: true # Skipped pending PLAT-15027 diff --git a/.buildkite/basic/react-native-android-pipeline.yml b/.buildkite/basic/react-native-android-pipeline.yml index e576843085..66acad308f 100644 --- a/.buildkite/basic/react-native-android-pipeline.yml +++ b/.buildkite/basic/react-native-android-pipeline.yml @@ -15,6 +15,7 @@ steps: RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_ANDROID: "true" + REACT_NAVIGATION: "true" artifact_paths: - "test/react-native/features/fixtures/generated/new-arch/**/reactnative.apk" commands: @@ -63,6 +64,7 @@ steps: env: RCT_NEW_ARCH_ENABLED: "1" RN_VERSION: "{{matrix}}" + REACT_NAVIGATION: "true" concurrency: 25 concurrency_group: "bitbar" concurrency_method: eager diff --git a/.buildkite/basic/react-native-ios-full-pipeline.yml b/.buildkite/basic/react-native-ios-full-pipeline.yml index 6dcd2f855a..5f972666c9 100644 --- a/.buildkite/basic/react-native-ios-full-pipeline.yml +++ b/.buildkite/basic/react-native-ios-full-pipeline.yml @@ -20,6 +20,7 @@ steps: RCT_NEW_ARCH_ENABLED: "0" BUILD_IOS: "true" XCODE_VERSION: "16.2.0" + REACT_NAVIGATION: "true" artifact_paths: - "test/react-native/features/fixtures/generated/old-arch/**/output/reactnative.ipa" commands: @@ -48,29 +49,37 @@ steps: - exit_status: "*" limit: 1 - - label: ':mac: Build RN {{matrix}} test fixture ipa (New Arch)' + - label: ':mac: Build RN {{matrix.reactnative}} test fixture ipa (New Arch)' key: "build-react-native-ios-fixture-new-arch-full" timeout_in_minutes: 30 agents: queue: "macos-15" env: NODE_VERSION: "22" - RN_VERSION: "{{matrix}}" + RN_VERSION: "{{matrix.reactnative}}" RCT_NEW_ARCH_ENABLED: "1" BUILD_IOS: "true" XCODE_VERSION: "16.2.0" + REACT_NAVIGATION: "{{matrix.reactnavigation}}" artifact_paths: - "test/react-native/features/fixtures/generated/new-arch/**/output/reactnative.ipa" commands: - "bundle install" - "node scripts/generate-react-native-fixture.js" matrix: - - "0.72" - - "0.74" - - "0.76" - - "0.78" - - "0.80" - - "0.81" + setup: + reactnative: + - "0.74" + - "0.76" + - "0.78" + - "0.80" + - "0.81" + reactnavigation: + - "true" + adjustments: + - with: + reactnative: "0.72" + reactnavigation: "false" retry: automatic: - exit_status: "*" @@ -162,6 +171,7 @@ steps: env: RN_VERSION: "{{matrix}}" RCT_NEW_ARCH_ENABLED: "0" + REACT_NAVIGATION: "true" concurrency: 25 concurrency_group: "bitbar" concurrency_method: eager @@ -175,19 +185,19 @@ steps: - "0.80" - "0.81" - - label: ":bitbar: :mac: RN {{matrix}} iOS (New Arch) end-to-end tests" + - label: ":bitbar: :mac: RN {{matrix.reactnative}} iOS (New Arch) end-to-end tests" depends_on: "build-react-native-ios-fixture-new-arch-full" timeout_in_minutes: 60 plugins: artifacts#v1.9.0: - download: "test/react-native/features/fixtures/generated/new-arch/{{matrix}}/output/reactnative.ipa" + download: "test/react-native/features/fixtures/generated/new-arch/{{matrix.reactnative}}/output/reactnative.ipa" upload: ./test/react-native/maze_output/**/* docker-compose#v4.12.0: pull: react-native-maze-runner run: react-native-maze-runner service-ports: true command: - - --app=/app/features/fixtures/generated/new-arch/{{matrix}}/output/reactnative.ipa + - --app=/app/features/fixtures/generated/new-arch/{{matrix.reactnative}}/output/reactnative.ipa - --farm=bb - --device=IOS_15 - --fail-fast @@ -200,7 +210,8 @@ steps: api-token-env-name: "REACT_NATIVE_BUILDKITE_ANALYTICS_TOKEN" env: RCT_NEW_ARCH_ENABLED: "1" - RN_VERSION: "{{matrix}}" + RN_VERSION: "{{matrix.reactnative}}" + REACT_NAVIGATION: "{{matrix.reactnavigation}}" retry: manual: permit_on_passed: true @@ -211,12 +222,19 @@ steps: concurrency_group: "bitbar" concurrency_method: eager matrix: - - "0.72" - - "0.74" - - "0.76" - - "0.78" - - "0.80" - - "0.81" + setup: + reactnative: + - "0.74" + - "0.76" + - "0.78" + - "0.80" + - "0.81" + reactnavigation: + - "true" + adjustments: + - with: + reactnative: "0.72" + reactnavigation: "false" # current latest version (v7.40.1) of react-native-navigation's autolinking tool doesn't currently support RN 0.73+, # causing a build failure - see https://github.com/wix/react-native-navigation/issues/7821 diff --git a/.buildkite/basic/react-native-ios-pipeline.yml b/.buildkite/basic/react-native-ios-pipeline.yml index b070b5e4cd..fcca0f56dc 100644 --- a/.buildkite/basic/react-native-ios-pipeline.yml +++ b/.buildkite/basic/react-native-ios-pipeline.yml @@ -19,6 +19,7 @@ steps: RCT_NEW_ARCH_ENABLED: "1" BUILD_IOS: "true" XCODE_VERSION: "16.2.0" + REACT_NAVIGATION: "true" artifact_paths: - "test/react-native/features/fixtures/generated/new-arch/**/output/reactnative.ipa" commands: @@ -59,6 +60,7 @@ steps: env: RCT_NEW_ARCH_ENABLED: "1" RN_VERSION: "{{matrix}}" + REACT_NAVIGATION: "true" retry: manual: permit_on_passed: true diff --git a/docker-compose.yml b/docker-compose.yml index c18d714281..fbd9a2a5df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -121,6 +121,7 @@ services: BITBAR_ACCESS_KEY: HERMES: RN_VERSION: + REACT_NAVIGATION: REACT_NATIVE_NAVIGATION: MAZE_REPEATER_API_KEY: "${MAZE_REPEATER_API_KEY_RN:-}" MAZE_HUB_REPEATER_API_KEY: "${MAZE_HUB_REPEATER_API_KEY_RN:-}" diff --git a/scripts/generate-react-native-fixture.js b/scripts/generate-react-native-fixture.js index 8589c25cae..43169ccc5e 100644 --- a/scripts/generate-react-native-fixture.js +++ b/scripts/generate-react-native-fixture.js @@ -39,9 +39,7 @@ const fixtureDir = resolve(ROOT_DIR, fixturePath, reactNativeVersion) const replacementFilesDir = resolve(ROOT_DIR, 'test/react-native/features/fixtures/replacements/') const INTERNAL_DEPENDENCIES = [ - '@bugsnag/react-native', - '@bugsnag/plugin-react-navigation', - '@bugsnag/plugin-react-native-navigation' + '@bugsnag/react-native' ] // make sure we install a compatible versions of peer dependencies @@ -50,20 +48,69 @@ const PEER_DEPENDENCIES = [ `react-native-file-access@${reactNativeFileAccessVersion}` ] -let reactNavigationVersion = '6.1.18' -let reactNavigationNativeStackVersion = '6.11.0' -let reactNativeScreensVersion = '3.35.0' -let reactNativeSafeAreaContextVersion = '4.14.0' - -// RN 0.77 requires react-native-screens 4.6.0, which in turn requires react navigation v7 -if (parseFloat(reactNativeVersion) >= 0.77) { - reactNavigationVersion = '7.1.18' - reactNavigationNativeStackVersion = '7.3.28' - reactNativeScreensVersion = '4.17.1' - reactNativeSafeAreaContextVersion = '5.6.1' -} else if (parseFloat(reactNativeVersion) <= 0.69) { - reactNativeScreensVersion = '3.14.0' - reactNativeSafeAreaContextVersion = '4.3.4' +// react-native-screens new-arch support: +// library version react-native version +// 4.19.0+ 0.81.0+ +// 4.14.0+ 0.79.0+ +// 4.5.0+ 0.77.0+ +// 4.0.0+ 0.76.0+ +// 3.33.0+ 0.75.0+ +// 3.32.0+ 0.74.0+ +// 3.28.0+ 0.73.0+ +// 3.21.0+ 0.72.0+ +// 3.19.0+ 0.71.0+ +// 3.18.0+ 0.70.0+ +// 3.14.0+ 0.69.0+ + +// default to the latest versions - update here when new versions are released or new RN versions come out +let reactNavigationVersion = '^7.0.0' +let reactNavigationNativeStackVersion = '^7.0.0' +let reactNativeSafeAreaContextVersion = '^5.0.0' +let reactNativeScreensVersion = '~4.19.0' + +// Adjust versions based on React Native version +const rnVersion = parseFloat(reactNativeVersion) +switch (true) { + case rnVersion >= 0.81: + reactNativeScreensVersion = '~4.19.0' + break + case rnVersion >= 0.79: + reactNativeScreensVersion = '~4.14.0' + break + case rnVersion >= 0.78: + reactNativeScreensVersion = '~4.11.0' + break + case rnVersion >= 0.76: + reactNativeScreensVersion = '~4.0.0' + break + case rnVersion >= 0.75: + reactNavigationVersion = '^6.0.0' + reactNavigationNativeStackVersion = '^6.0.0' + reactNativeScreensVersion = '~3.33.0' + break + case rnVersion >= 0.74: + reactNavigationVersion = '^6.0.0' + reactNavigationNativeStackVersion = '^6.0.0' + reactNativeScreensVersion = '~3.32.0' + break + case rnVersion >= 0.73: + reactNavigationVersion = '^6.0.0' + reactNavigationNativeStackVersion = '^6.0.0' + reactNativeSafeAreaContextVersion = '4.14.0' + reactNativeScreensVersion = '~3.28.0' + break + case rnVersion >= 0.72: + reactNavigationVersion = '^6.0.0' + reactNavigationNativeStackVersion = '^6.0.0' + reactNativeSafeAreaContextVersion = '4.14.0' + reactNativeScreensVersion = '~3.21.0' + break + case rnVersion <= 0.69: + reactNavigationVersion = '^6.0.0' + reactNavigationNativeStackVersion = '^6.0.0' + reactNativeSafeAreaContextVersion = '4.3.4' + reactNativeScreensVersion = '~3.14.0' + break } const REACT_NAVIGATION_PEER_DEPENDENCIES = [ @@ -77,6 +124,16 @@ const REACT_NATIVE_NAVIGATION_PEER_DEPENDENCIES = [ 'react-native-navigation@7.41.0' // Issue with 7.42.0 ] +// add packages and dependencies for react-native-navigation (wix) +if (process.env.REACT_NATIVE_NAVIGATION === 'true' || process.env.REACT_NATIVE_NAVIGATION === '1') { + INTERNAL_DEPENDENCIES.push('@bugsnag/plugin-react-native-navigation') + PEER_DEPENDENCIES.push(...REACT_NATIVE_NAVIGATION_PEER_DEPENDENCIES) +} else if (process.env.REACT_NAVIGATION === 'true' || process.env.REACT_NAVIGATION === '1') { + // add packages and dependencies for @react-navigation + INTERNAL_DEPENDENCIES.push('@bugsnag/plugin-react-navigation') + PEER_DEPENDENCIES.push(...REACT_NAVIGATION_PEER_DEPENDENCIES) +} + // install and build the packages if (!process.env.SKIP_BUILD_PACKAGES) { execFileSync('npm', ['ci'], { cwd: ROOT_DIR, stdio: 'inherit', env: { ...process.env, PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } }) @@ -137,14 +194,6 @@ function installFixtureDependencies () { // pack the scenario launcher execFileSync('npm', ['pack', resolve(ROOT_DIR, 'test/react-native/features/fixtures/scenario-launcher'), '--pack-destination', fixtureDir], { cwd: ROOT_DIR, stdio: 'inherit' }) - // add dependencies for react-native-navigation (wix) - if (process.env.REACT_NATIVE_NAVIGATION === 'true' || process.env.REACT_NATIVE_NAVIGATION === '1') { - PEER_DEPENDENCIES.push(...REACT_NATIVE_NAVIGATION_PEER_DEPENDENCIES) - } else if (!isNewArchEnabled) { - // add dependencies for @react-navigation - PEER_DEPENDENCIES.push(...REACT_NAVIGATION_PEER_DEPENDENCIES) - } - const fixtureDependencyArgs = PEER_DEPENDENCIES.join(' ') // install dependencies diff --git a/test/react-native/features/fixtures/scenario-launcher/src/index.js b/test/react-native/features/fixtures/scenario-launcher/index.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/index.js rename to test/react-native/features/fixtures/scenario-launcher/index.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/lib/CommandRunner.js b/test/react-native/features/fixtures/scenario-launcher/lib/CommandRunner.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/lib/CommandRunner.js rename to test/react-native/features/fixtures/scenario-launcher/lib/CommandRunner.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/lib/ConfigFileReader.js b/test/react-native/features/fixtures/scenario-launcher/lib/ConfigFileReader.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/lib/ConfigFileReader.js rename to test/react-native/features/fixtures/scenario-launcher/lib/ConfigFileReader.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/NativeBugsnagTestInterface.ts b/test/react-native/features/fixtures/scenario-launcher/lib/NativeBugsnagTestInterface.ts similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/NativeBugsnagTestInterface.ts rename to test/react-native/features/fixtures/scenario-launcher/lib/NativeBugsnagTestInterface.ts diff --git a/test/react-native/features/fixtures/scenario-launcher/src/lib/ScenarioLauncher.js b/test/react-native/features/fixtures/scenario-launcher/lib/ScenarioLauncher.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/lib/ScenarioLauncher.js rename to test/react-native/features/fixtures/scenario-launcher/lib/ScenarioLauncher.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/lib/native.js b/test/react-native/features/fixtures/scenario-launcher/lib/native.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/lib/native.js rename to test/react-native/features/fixtures/scenario-launcher/lib/native.js diff --git a/test/react-native/features/fixtures/scenario-launcher/package.json b/test/react-native/features/fixtures/scenario-launcher/package.json index 0e41deb910..6705393451 100644 --- a/test/react-native/features/fixtures/scenario-launcher/package.json +++ b/test/react-native/features/fixtures/scenario-launcher/package.json @@ -2,28 +2,23 @@ "name": "@bugsnag/react-native-scenarios", "version": "1.0.0", "description": "Test scenarios for the Bugsnag React Native library", - "main": "src/index.js", + "main": "index.js", "files": [ - "src", - "android", - "ios", - "BugsnagTestInterface.podspec", - "!android/build", - "!ios/build" + "/android", + "/ios", + "/lib", + "/scenarios/core", + "/scenarios/index.js", + "/BugsnagTestInterface.podspec" ], "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "prepack": "node ./scripts/prepare-package.js", + "postpack": "node ./scripts/cleanup.js" }, "author": "BugSnag", "license": "MIT", - "optionalDependencies": { - "react-native-navigation": "*" - }, "peerDependencies": { - "@bugsnag/plugin-react-navigation": "*", - "@bugsnag/plugin-react-native-navigation": "*", - "@react-navigation/native": "*", - "@react-navigation/native-stack": "*", "react": "*", "react-native": "*", "react-native-file-access": "*" @@ -31,7 +26,7 @@ "codegenConfig": { "name": "BugsnagTestInterfaceSpec", "type": "modules", - "jsSrcsDir": "src", + "jsSrcsDir": "lib", "android": { "javaPackageName": "com.reactnative.scenarios" } diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigAppTypeScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigAppTypeScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigAppTypeScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigAppTypeScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigEnabledReleaseStagesNoSendScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigEnabledReleaseStagesNoSendScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigEnabledReleaseStagesNoSendScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigEnabledReleaseStagesNoSendScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigEnabledReleaseStagesScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigEnabledReleaseStagesScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigEnabledReleaseStagesScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigEnabledReleaseStagesScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigReleaseStageScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigReleaseStageScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppConfigReleaseStageScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppConfigReleaseStageScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppJsHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppJsHandledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppJsHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppJsHandledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppJsUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppJsUnhandledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppJsUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppJsUnhandledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeHandledScenario.js similarity index 85% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeHandledScenario.js index 9bdd24f57e..dff07788a5 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeHandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeHandledScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class AppNativeHandledScenario extends Scenario { constructor (configuration, jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeUnhandledScenario.js similarity index 86% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeUnhandledScenario.js index 727e830c7a..fe5700335b 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/AppNativeUnhandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/AppNativeUnhandledScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class AppNativeUnhandledScenario extends Scenario { constructor (configuration, jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsAutomaticErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsAutomaticErrorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsAutomaticErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsAutomaticErrorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsAutomaticLoadedScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsAutomaticLoadedScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsAutomaticLoadedScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsAutomaticLoadedScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsJsManualScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsJsManualScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsJsManualScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsJsManualScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsNativeManualScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsNativeManualScenario.js similarity index 78% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsNativeManualScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsNativeManualScenario.js index 825855a943..356b4abc01 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsNativeManualScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsNativeManualScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class BreadcrumbsNativeManualScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsNullEnabledBreadcrumbTypesScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsNullEnabledBreadcrumbTypesScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/BreadcrumbsNullEnabledBreadcrumbTypesScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/BreadcrumbsNullEnabledBreadcrumbTypesScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextJsCustomScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextJsCustomScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextJsCustomScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextJsCustomScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextJsDefaultScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextJsDefaultScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextJsDefaultScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextJsDefaultScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextNativeCustomScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextNativeCustomScenario.js similarity index 85% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextNativeCustomScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextNativeCustomScenario.js index 781cb222bb..73fcad69f5 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ContextNativeCustomScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/ContextNativeCustomScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class ContextNativeCustomScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceJsHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceJsHandledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceJsHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceJsHandledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceJsUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceJsUnhandledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceJsUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceJsUnhandledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeHandledScenario.js similarity index 77% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeHandledScenario.js index 945ae32320..e57a35e087 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeHandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeHandledScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class DeviceNativeHandledScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeUnhandledScenario.js similarity index 77% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeUnhandledScenario.js index 572609455d..3688a56d01 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/DeviceNativeUnhandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/DeviceNativeUnhandledScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class DeviceNativeUnhandledScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/EventApiKeyOverrideScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/EventApiKeyOverrideScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/EventApiKeyOverrideScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/EventApiKeyOverrideScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/FeatureFlagsNativeCrashScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/FeatureFlagsNativeCrashScenario.js similarity index 91% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/FeatureFlagsNativeCrashScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/FeatureFlagsNativeCrashScenario.js index 37816c802c..290045d132 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/FeatureFlagsNativeCrashScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/FeatureFlagsNativeCrashScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class FeatureFlagsNativeCrashScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/FeatureFlagsScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/FeatureFlagsScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/FeatureFlagsScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/FeatureFlagsScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/GroupingDiscriminatorNativeScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/GroupingDiscriminatorNativeScenario.js similarity index 92% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/GroupingDiscriminatorNativeScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/GroupingDiscriminatorNativeScenario.js index c3792de4ff..a09628b0b5 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/GroupingDiscriminatorNativeScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/GroupingDiscriminatorNativeScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class GroupingDiscriminatorNativeScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/GroupingDiscriminatorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/GroupingDiscriminatorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/GroupingDiscriminatorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/GroupingDiscriminatorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledJsErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledJsErrorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledJsErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledJsErrorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledNativeErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledNativeErrorScenario.js similarity index 77% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledNativeErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledNativeErrorScenario.js index fec5f1783f..24b3d637ab 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledNativeErrorScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledNativeErrorScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class HandledNativeErrorScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledOverrideJsErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledOverrideJsErrorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/HandledOverrideJsErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/HandledOverrideJsErrorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataJsScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataJsScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataJsScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataJsScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeScenario.js similarity index 90% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeScenario.js index 5863ed34bf..a19cf91a8f 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class MetadataNativeScenario extends Scenario { constructor (configuration, _jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeUnhandledScenario.js similarity index 90% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeUnhandledScenario.js index 6291f777a3..8aa6ef3916 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/MetadataNativeUnhandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/MetadataNativeUnhandledScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class MetadataNativeUnhandledScenario extends Scenario { constructor (configuration, _jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativeFeatureFlagsScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativeFeatureFlagsScenario.js similarity index 92% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativeFeatureFlagsScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativeFeatureFlagsScenario.js index 807ff5431f..4e9957d8b5 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativeFeatureFlagsScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativeFeatureFlagsScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class NativeFeatureFlagsScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionHandledScenario.js similarity index 85% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionHandledScenario.js index 1760f07cd9..84c485eb9b 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionHandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionHandledScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class NativePromiseRejectionHandledScenario extends Scenario { async run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionUnhandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionUnhandledScenario.js similarity index 80% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionUnhandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionUnhandledScenario.js index 2445120855..251b260a0a 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/NativePromiseRejectionUnhandledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/NativePromiseRejectionUnhandledScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class NativePromiseRejectionUnhandledScenario extends Scenario { async run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/RCTFatalScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/RCTFatalScenario.js similarity index 75% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/RCTFatalScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/RCTFatalScenario.js index c2dbef562d..bd5db2bbae 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/RCTFatalScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/RCTFatalScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class RCTFatalScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/ReactNativeErrorBoundaryScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeErrorBoundaryScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/ReactNativeErrorBoundaryScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/Scenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/Scenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/Scenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/Scenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionAutoDisabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionAutoDisabledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionAutoDisabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionAutoDisabledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionAutoEnabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionAutoEnabledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionAutoEnabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionAutoEnabledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionJsControlledManualJsScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionJsControlledManualJsScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionJsControlledManualJsScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionJsControlledManualJsScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionJsControlledManualNativeScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionJsControlledManualNativeScenario.js similarity index 94% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionJsControlledManualNativeScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionJsControlledManualNativeScenario.js index 3ca1d8ae00..77ca20a29c 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionJsControlledManualNativeScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionJsControlledManualNativeScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class SessionJsControlledManualNativeScenario extends Scenario { constructor (configuration, jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionNativeControlledManualJsScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionNativeControlledManualJsScenario.js similarity index 96% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionNativeControlledManualJsScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionNativeControlledManualJsScenario.js index 7438a5fbe2..d290f06b24 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/SessionNativeControlledManualJsScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/SessionNativeControlledManualJsScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class SessionNativeControlledManualJsScenario extends Scenario { constructor (configuration, jsConfig) { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsErrorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsErrorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsErrorSeverityScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsErrorSeverityScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsErrorSeverityScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsErrorSeverityScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsPromiseRejectionAsHandledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsPromiseRejectionAsHandledScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsPromiseRejectionAsHandledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsPromiseRejectionAsHandledScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsPromiseRejectionScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsPromiseRejectionScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledJsPromiseRejectionScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledJsPromiseRejectionScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorScenario.js similarity index 77% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorScenario.js index b47b4ec22a..c5192eb482 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class UnhandledNativeErrorScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorSyncScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorSyncScenario.js similarity index 78% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorSyncScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorSyncScenario.js index 6095685d9e..db97feb49b 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledNativeErrorSyncScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledNativeErrorSyncScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class UnhandledNativeErrorSyncScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledOverrideJsErrorScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledOverrideJsErrorScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UnhandledOverrideJsErrorScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UnhandledOverrideJsErrorScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsClientScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsClientScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsClientScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsClientScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsConfigScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsConfigScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsConfigScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsConfigScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsEventScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsEventScenario.js similarity index 100% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsEventScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsEventScenario.js diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsNativeScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsNativeScenario.js similarity index 85% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsNativeScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsNativeScenario.js index 8f08fd1d2b..e3b84576fa 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserJsNativeScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserJsNativeScenario.js @@ -1,6 +1,6 @@ import Scenario from './Scenario' import Bugsnag from '@bugsnag/react-native' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class UserJsNativeScenario extends Scenario { async run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserNativeClientScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserNativeClientScenario.js similarity index 76% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserNativeClientScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserNativeClientScenario.js index 507435251c..b2bb56fcca 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/UserNativeClientScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/UserNativeClientScenario.js @@ -1,5 +1,5 @@ import Scenario from './Scenario' -import { NativeInterface } from '../lib/native' +import { NativeInterface } from '../../lib/native' export class UserNativeClientScenario extends Scenario { run () { diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/index.js similarity index 89% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/core/index.js index 9c08ba1c88..988e1529a8 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/index.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/core/index.js @@ -74,17 +74,9 @@ export { FeatureFlagsScenario } from './FeatureFlagsScenario' export { FeatureFlagsNativeCrashScenario } from './FeatureFlagsNativeCrashScenario' export { NativeFeatureFlagsScenario } from './NativeFeatureFlagsScenario' -// react-navigation.feature -export { ReactNavigationBreadcrumbsEnabledScenario } from './ReactNavigationBreadcrumbsEnabledScenario' -export { ReactNavigationBreadcrumbsDisabledScenario } from './ReactNavigationBreadcrumbsDisabledScenario' - // react-native-error-boundary.feature export { ReactNativeErrorBoundaryScenario } from './ReactNativeErrorBoundaryScenario' -// react-native-navigation.feature -export { ReactNativeNavigationBreadcrumbsEnabledScenario } from './ReactNativeNavigationBreadcrumbsEnabledScenario' -export { ReactNativeNavigationBreadcrumbsDisabledScenario } from './ReactNativeNavigationBreadcrumbsDisabledScenario' - // grouping-discriminator.feature export { GroupingDiscriminatorScenario } from './GroupingDiscriminatorScenario' export { GroupingDiscriminatorNativeScenario } from './GroupingDiscriminatorNativeScenario' diff --git a/test/react-native/features/fixtures/scenario-launcher/scenarios/index.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/index.js new file mode 100644 index 0000000000..46d458ad7f --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/index.js @@ -0,0 +1 @@ +export * from './core' diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsDisabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsDisabledScenario.js similarity index 97% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsDisabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsDisabledScenario.js index 964815d420..3a8a8a852f 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsDisabledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsDisabledScenario.js @@ -1,4 +1,4 @@ -import Scenario from './Scenario' +import Scenario from '../core/Scenario' import Bugsnag from '@bugsnag/react-native' import BugsnagReactNativeNavigation from '@bugsnag/plugin-react-native-navigation' import React, { useEffect } from 'react' diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsEnabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsEnabledScenario.js similarity index 97% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsEnabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsEnabledScenario.js index 249f84c3aa..79eac5b1af 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNativeNavigationBreadcrumbsEnabledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/ReactNativeNavigationBreadcrumbsEnabledScenario.js @@ -1,4 +1,4 @@ -import Scenario from './Scenario' +import Scenario from '../core/Scenario' import Bugsnag from '@bugsnag/react-native' import BugsnagReactNativeNavigation from '@bugsnag/plugin-react-native-navigation' import React, { useEffect } from 'react' diff --git a/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/index.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/index.js new file mode 100644 index 0000000000..81df59406f --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-native-navigation/index.js @@ -0,0 +1,3 @@ +// react-native-navigation.feature +export { ReactNativeNavigationBreadcrumbsEnabledScenario } from './ReactNativeNavigationBreadcrumbsEnabledScenario' +export { ReactNativeNavigationBreadcrumbsDisabledScenario } from './ReactNativeNavigationBreadcrumbsDisabledScenario' diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsDisabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsDisabledScenario.js similarity index 98% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsDisabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsDisabledScenario.js index 8c6c373626..a5f912243a 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsDisabledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsDisabledScenario.js @@ -1,4 +1,4 @@ -import Scenario from './Scenario' +import Scenario from '../core/Scenario' import Bugsnag from '@bugsnag/react-native' import BugsnagPluginReactNavigation from '@bugsnag/plugin-react-navigation' import * as React from 'react' diff --git a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsEnabledScenario.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsEnabledScenario.js similarity index 97% rename from test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsEnabledScenario.js rename to test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsEnabledScenario.js index 6d3fdedd1b..fbaab71ccf 100644 --- a/test/react-native/features/fixtures/scenario-launcher/src/scenarios/ReactNavigationBreadcrumbsEnabledScenario.js +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/ReactNavigationBreadcrumbsEnabledScenario.js @@ -1,4 +1,4 @@ -import Scenario from './Scenario' +import Scenario from '../core/Scenario' import Bugsnag from '@bugsnag/react-native' import BugsnagPluginReactNavigation from '@bugsnag/plugin-react-navigation' import * as React from 'react' diff --git a/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/index.js b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/index.js new file mode 100644 index 0000000000..80ee936228 --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/scenarios/react-navigation/index.js @@ -0,0 +1,3 @@ +// react-navigation.feature +export { ReactNavigationBreadcrumbsEnabledScenario } from './ReactNavigationBreadcrumbsEnabledScenario' +export { ReactNavigationBreadcrumbsDisabledScenario } from './ReactNavigationBreadcrumbsDisabledScenario' diff --git a/test/react-native/features/fixtures/scenario-launcher/scripts/cleanup.js b/test/react-native/features/fixtures/scenario-launcher/scripts/cleanup.js new file mode 100644 index 0000000000..d8d770b9d9 --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/scripts/cleanup.js @@ -0,0 +1,19 @@ +const fs = require('fs') +const path = require('path') + +const packagePath = path.join(__dirname, '..', 'package.json') +const backupPath = `${packagePath}.backup` + +// Restore original package.json if backup exists +if (fs.existsSync(backupPath)) { + fs.copyFileSync(backupPath, packagePath) + fs.unlinkSync(backupPath) +} + +// Restore original scenarios index file if backup exists +const scenarioIndexPath = path.join(__dirname, '..', 'scenarios', 'index.js') +const scenarioBackupPath = `${scenarioIndexPath}.backup` +if (fs.existsSync(scenarioBackupPath)) { + fs.copyFileSync(scenarioBackupPath, scenarioIndexPath) + fs.unlinkSync(scenarioBackupPath) +} diff --git a/test/react-native/features/fixtures/scenario-launcher/scripts/prepare-package.js b/test/react-native/features/fixtures/scenario-launcher/scripts/prepare-package.js new file mode 100644 index 0000000000..92c04a8f51 --- /dev/null +++ b/test/react-native/features/fixtures/scenario-launcher/scripts/prepare-package.js @@ -0,0 +1,34 @@ +const fs = require('fs') +const path = require('path') + +// Read package.json and scenarios index files +const packageJsonPath = path.join(__dirname, '..', 'package.json') +const pkg = require(packageJsonPath) + +const scenarioIndexPath = path.join(__dirname, '..', 'scenarios', 'index.js') +let scenarioExports = fs.readFileSync(scenarioIndexPath, 'utf8') + +// Make backups of files to modify so we can restore them later +fs.copyFileSync(packageJsonPath, `${packageJsonPath}.backup`) +fs.copyFileSync(scenarioIndexPath, `${scenarioIndexPath}.backup`) + +if (process.env.REACT_NATIVE_NAVIGATION) { + pkg.files.push('/scenarios/react-native-navigation') + scenarioExports += "\nexport * from './react-native-navigation'" +} + +if (process.env.REACT_NAVIGATION === 'true' || process.env.REACT_NAVIGATION === '1') { + pkg.files.push('/scenarios/react-navigation') + scenarioExports += "\nexport * from './react-navigation'" +} + +if (process.env.NATIVE_INTEGRATION) { + pkg.files.push('/scenarios/native-integration') + scenarioExports += "\nexport * from './native-integration'" +} + +// Update package.json +fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2)) + +// Update scenarios index file +fs.writeFileSync(scenarioIndexPath, scenarioExports) diff --git a/test/react-native/features/react-navigation.feature b/test/react-native/features/react-navigation.feature index 335427dfd8..61d45cdcc0 100644 --- a/test/react-native/features/react-navigation.feature +++ b/test/react-native/features/react-navigation.feature @@ -1,4 +1,4 @@ -@navigation @skip_new_arch +@navigation @react_navigation Feature: Navigation plugin features Scenario: Navigating screens causes breadcrumbs and context to be updated diff --git a/test/react-native/features/support/env.rb b/test/react-native/features/support/env.rb index b71678a7c6..e5b3f67abb 100644 --- a/test/react-native/features/support/env.rb +++ b/test/react-native/features/support/env.rb @@ -25,6 +25,10 @@ skip_this_scenario("Skipping scenario") if ENV['SKIP_NAVIGATION_SCENARIOS'].eql?('true') end +Before('@react_navigation') do |scenario| + skip_this_scenario("Skipping scenario: Not running react-navigation fixture") unless ENV["REACT_NAVIGATION"] == 'true' +end + Before('@react-native-navigation') do |scenario| skip_this_scenario("Skipping scenario") unless ENV['REACT_NATIVE_NAVIGATION'].eql?('true') end From e521d74cc1bb28e3607cfc375b886e2e093cff0b Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Thu, 15 Jan 2026 10:14:09 +0000 Subject: [PATCH 41/43] feat: :sparkles: return callback value from contextualize plugin --- CHANGELOG.md | 1 + .../plugin-contextualize/contextualize.js | 2 +- .../test/contextualize.test.js | 155 ++++++++++++++++++ 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 packages/plugin-contextualize/test/contextualize.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index af787fa616..233169ee52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added (plugin-cloudflare-workers): Add initial support for Cloudflare Workers [#2643](https://github.com/bugsnag/bugsnag-js/pull/2643) [#2644](https://github.com/bugsnag/bugsnag-js/pull/2644) +(plugin-contextualize) Return callback value from contextualize plugin [#2654](https://github.com/bugsnag/bugsnag-js/pull/2654) ### Fixed diff --git a/packages/plugin-contextualize/contextualize.js b/packages/plugin-contextualize/contextualize.js index 5a3671ef76..cabb970e8d 100644 --- a/packages/plugin-contextualize/contextualize.js +++ b/packages/plugin-contextualize/contextualize.js @@ -17,7 +17,7 @@ module.exports = { clonedClient.addOnError(onError) - client._clientContext.run(clonedClient, fn) + return client._clientContext.run(clonedClient, fn) } return contextualize diff --git a/packages/plugin-contextualize/test/contextualize.test.js b/packages/plugin-contextualize/test/contextualize.test.js new file mode 100644 index 0000000000..c6ef04f744 --- /dev/null +++ b/packages/plugin-contextualize/test/contextualize.test.js @@ -0,0 +1,155 @@ +const Client = require('@bugsnag/core/client') +const plugin = require('../contextualize') +const { AsyncLocalStorage } = require('async_hooks') + +describe('plugin: contextualize', () => { + describe('client cloning', () => { + it('creates a cloned client for the contextualized scope', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + let capturedClient = null + contextualize(() => { + capturedClient = c._clientContext.getStore() + }, (event) => {}) + + expect(capturedClient).not.toBe(c) + expect(capturedClient).toBeTruthy() + }) + + it('sets fallbackStack on the cloned client', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + let capturedClient = null + contextualize(() => { + capturedClient = c._clientContext.getStore() + }, (event) => {}) + + expect(capturedClient.fallbackStack).toBeDefined() + expect(typeof capturedClient.fallbackStack).toBe('string') + }) + }) + + describe('onError callback', () => { + it('adds the onError callback to the cloned client', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const onError = jest.fn() + let capturedClient = null + + contextualize(() => { + capturedClient = c._clientContext.getStore() + }, onError) + + expect(capturedClient._cbs.e.length).toBeGreaterThan(0) + }) + + it('does not add onError to the parent client', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const initialCallbackCount = c._cbs.e.length + + contextualize(() => {}, (event) => { + event.addMetadata('test', { key: 'value' }) + }) + + expect(c._cbs.e.length).toBe(initialCallbackCount) + }) + }) + + describe('context isolation', () => { + it('isolates metadata changes within the contextualized scope', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + let clonedClient = null + contextualize(() => { + clonedClient = c._clientContext.getStore() + clonedClient.addMetadata('custom', { foo: 'bar' }) + }, (event) => {}) + + expect(c.getMetadata('custom')).toBeUndefined() + expect(clonedClient.getMetadata('custom')).toEqual({ foo: 'bar' }) + }) + }) + + describe('async execution', () => { + it('maintains context in async operations', async () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + let capturedClient = null + await contextualize(async () => { + await new Promise(resolve => setTimeout(resolve, 10)) + capturedClient = c._clientContext.getStore() + }, (event) => {}) + + expect(capturedClient).toBeTruthy() + expect(capturedClient.fallbackStack).toBeDefined() + }) + + it('returns a promise when callback is async', async () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const result = contextualize(async () => { + return 'async value' + }, (event) => {}) + + expect(result).toBeInstanceOf(Promise) + await expect(result).resolves.toBe('async value') + }) + }) + + describe('callback execution', () => { + it('executes the callback function', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const callback = jest.fn(() => 'result') + contextualize(callback, (event) => {}) + + expect(callback).toHaveBeenCalledTimes(1) + }) + + it('passes through exceptions from the callback', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const error = new Error('test error') + expect(() => { + contextualize(() => { + throw error + }, (event) => {}) + }).toThrow(error) + }) + }) + + describe('return value', () => { + it('returns the value returned by the callback function', () => { + const c = new Client({ apiKey: 'api_key', plugins: [plugin] }) + c._clientContext = new AsyncLocalStorage() + const contextualize = c.getPlugin('contextualize') + + const result = contextualize(() => { + return 'test value' + }, (event) => { + event.addMetadata('test', { key: 'value' }) + }) + + expect(result).toBe('test value') + }) + }) +}) From 0522d07e6b0983b4559b229ed87d94805a377d9b Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Mon, 19 Jan 2026 11:09:56 +0000 Subject: [PATCH 42/43] Merge pull request #2647 from bugsnag/integration/http-errors [Integration] HTTP Errors --- .eslintignore | 1 + CHANGELOG.md | 3 + bin/local-test-util | 7 +- jest.config.js | 5 +- package-lock.json | 45 + packages/core/event.d.ts | 3 +- packages/core/event.js | 2 + packages/core/lib/json-payload.js | 3 +- packages/core/types/common.d.ts | 7 + packages/core/types/event.d.ts | 2 + .../network-breadcrumbs.js | 215 +- .../plugin-network-breadcrumbs/package.json | 3 + .../test/network-breadcrumbs.test.ts | 4 + .../LICENSE.txt | 19 + .../plugin-network-instrumentation/README.md | 36 + .../lib/extract-domain.js | 13 + .../lib/parse-query-params.js | 17 + .../lib/redact-query-parameters.js | 38 + .../lib/redact-values.js | 15 + .../lib/should-capture-status-code.js | 17 + .../lib/truncate.js | 10 + .../network-instrumentation.js | 169 + .../package.json | 28 + .../test/network-instrumentation-xhr.test.ts | 242 + .../test/network-instrumentation.test.ts | 685 ++ .../test/redact-query-parameters.test.ts | 24 + ...ugsnag-plugin-network-instrumentation.d.ts | 47 + packages/request-tracker/index.js | 42 + packages/request-tracker/lib/fetch-tracker.js | 103 + .../request-tracker/lib/headers-to-object.js | 24 + .../request-tracker/lib/request-tracker.js | 66 + packages/request-tracker/lib/url-helpers.js | 46 + .../lib/xhr-header-string-to-object.js | 18 + packages/request-tracker/lib/xhr-tracker.js | 117 + packages/request-tracker/package.json | 24 + .../test/request-tracker.test.js | 456 + scripts/generate-react-native-fixture.js | 3 +- .../handled/webpack3/webpack.config.js | 4 +- .../handled/webpack4/webpack.config.js | 2 +- .../features/fixtures/http_errors/.babelrc | 7 + .../features/fixtures/http_errors/index.html | 11 + .../fixtures/http_errors/package-lock.json | 7493 +++++++++++++++++ .../fixtures/http_errors/package.json | 20 + .../features/fixtures/http_errors/src/app.tsx | 69 + .../fixtures/http_errors/src/lib/config.ts | 19 + .../fixtures/http_errors/tsconfig.json | 15 + .../fixtures/http_errors/webpack.config.js | 37 + .../plugin_react/webpack4/webpack.config.js | 2 +- .../plugin_vue/webpack4/webpack.config.js | 2 +- test/browser/features/http_errors.feature | 127 + test/browser/features/steps/browser_steps.rb | 12 + test/browser/features/support/env.rb | 6 +- tsconfig.json | 4 +- 53 files changed, 10204 insertions(+), 185 deletions(-) create mode 100644 packages/plugin-network-instrumentation/LICENSE.txt create mode 100644 packages/plugin-network-instrumentation/README.md create mode 100644 packages/plugin-network-instrumentation/lib/extract-domain.js create mode 100644 packages/plugin-network-instrumentation/lib/parse-query-params.js create mode 100644 packages/plugin-network-instrumentation/lib/redact-query-parameters.js create mode 100644 packages/plugin-network-instrumentation/lib/redact-values.js create mode 100644 packages/plugin-network-instrumentation/lib/should-capture-status-code.js create mode 100644 packages/plugin-network-instrumentation/lib/truncate.js create mode 100644 packages/plugin-network-instrumentation/network-instrumentation.js create mode 100644 packages/plugin-network-instrumentation/package.json create mode 100644 packages/plugin-network-instrumentation/test/network-instrumentation-xhr.test.ts create mode 100644 packages/plugin-network-instrumentation/test/network-instrumentation.test.ts create mode 100644 packages/plugin-network-instrumentation/test/redact-query-parameters.test.ts create mode 100644 packages/plugin-network-instrumentation/types/bugsnag-plugin-network-instrumentation.d.ts create mode 100644 packages/request-tracker/index.js create mode 100644 packages/request-tracker/lib/fetch-tracker.js create mode 100644 packages/request-tracker/lib/headers-to-object.js create mode 100644 packages/request-tracker/lib/request-tracker.js create mode 100644 packages/request-tracker/lib/url-helpers.js create mode 100644 packages/request-tracker/lib/xhr-header-string-to-object.js create mode 100644 packages/request-tracker/lib/xhr-tracker.js create mode 100644 packages/request-tracker/package.json create mode 100644 packages/request-tracker/test/request-tracker.test.js create mode 100644 test/browser/features/fixtures/http_errors/.babelrc create mode 100644 test/browser/features/fixtures/http_errors/index.html create mode 100644 test/browser/features/fixtures/http_errors/package-lock.json create mode 100644 test/browser/features/fixtures/http_errors/package.json create mode 100644 test/browser/features/fixtures/http_errors/src/app.tsx create mode 100644 test/browser/features/fixtures/http_errors/src/lib/config.ts create mode 100644 test/browser/features/fixtures/http_errors/tsconfig.json create mode 100644 test/browser/features/fixtures/http_errors/webpack.config.js create mode 100644 test/browser/features/http_errors.feature diff --git a/.eslintignore b/.eslintignore index 99b541fc04..0aceac03bb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,4 +10,5 @@ packages/**/fixtures test/browser test/node test/react-native-cli/features/fixtures +test/react-native/features/fixtures test/cloudflare-workers diff --git a/CHANGELOG.md b/CHANGELOG.md index 233169ee52..a1d6c63a99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,11 @@ ## [Unreleased] +This release adds support for notitfying failed network requests using the new `plugin-network-instrumentation` package + ### Added +(plugin-network-instrumentation) Add new plugin to notify failed network requests [#2647](https://github.com/bugsnag/bugsnag-js/pull/2647) (plugin-cloudflare-workers): Add initial support for Cloudflare Workers [#2643](https://github.com/bugsnag/bugsnag-js/pull/2643) [#2644](https://github.com/bugsnag/bugsnag-js/pull/2644) (plugin-contextualize) Return callback value from contextualize plugin [#2654](https://github.com/bugsnag/bugsnag-js/pull/2654) diff --git a/bin/local-test-util b/bin/local-test-util index 9b2cfc91bc..acc8f5ccba 100755 --- a/bin/local-test-util +++ b/bin/local-test-util @@ -121,7 +121,7 @@ async function buildNotifiers (notifier) { async function packNotifiers (notifier) { const notifiers = notifier ? [ notifier ] - : [ 'js', 'browser', 'node', 'web-worker', 'plugin-angular', 'plugin-react', 'plugin-vue' ] + : [ 'js', 'browser', 'node', 'web-worker', 'plugin-angular', 'plugin-react', 'plugin-vue', 'plugin-network-instrumentation' ] for (const n of notifiers) { let packageLocation = `packages/${n}/` if (n === 'plugin-angular') packageLocation += 'dist/' @@ -131,7 +131,7 @@ async function packNotifiers (notifier) { async function installNotifiers (notifier) { trace('install notifiers') - if (notifier && ![ 'browser', 'plugin-vue', 'plugin-react', 'web-worker' ].includes(notifier)) return + if (notifier && ![ 'browser', 'plugin-vue', 'plugin-react', 'web-worker', 'plugin-network-instrumentation' ].includes(notifier)) return await ex(`npm`, [ `install`, `--no-package-lock`, @@ -144,7 +144,8 @@ async function installNotifiers (notifier) { `../../../../bugsnag-browser-${require('../packages/browser/package.json').version}.tgz`, `../../../../bugsnag-web-worker-${require('../packages/web-worker/package.json').version}.tgz`, `../../../../bugsnag-plugin-react-${require('../packages/plugin-react/package.json').version}.tgz`, - `../../../../bugsnag-plugin-vue-${require('../packages/plugin-vue/package.json').version}.tgz` + `../../../../bugsnag-plugin-vue-${require('../packages/plugin-vue/package.json').version}.tgz`, + `../../../../bugsnag-plugin-network-instrumentation-${require('../packages/plugin-network-instrumentation/package.json').version}.tgz` ] ), { cwd: `${__dirname}/../test/browser/features/fixtures` diff --git a/jest.config.js b/jest.config.js index dcb9bbd721..358588715a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,7 +29,7 @@ module.exports = { project('web workers', ['web-worker'], { testEnvironment: '/jest/FixJSDOMEnvironment.js' }), - project('shared plugins', ['plugin-app-duration', 'plugin-stackframe-path-normaliser']), + project('shared plugins', ['plugin-app-duration', 'plugin-stackframe-path-normaliser', 'request-tracker']), project('browser', [ 'browser', 'delivery-x-domain-request', @@ -50,7 +50,8 @@ module.exports = { 'plugin-inline-script-content', 'plugin-simple-throttle', 'plugin-console-breadcrumbs', - 'plugin-browser-session' + 'plugin-browser-session', + 'plugin-network-instrumentation' ], { testEnvironment: '/jest/FixJSDOMEnvironment.js' }), diff --git a/package-lock.json b/package-lock.json index 6328a177cc..185af1706c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2832,6 +2832,10 @@ "resolved": "packages/plugin-network-breadcrumbs", "link": true }, + "node_modules/@bugsnag/plugin-network-instrumentation": { + "resolved": "packages/plugin-network-instrumentation", + "link": true + }, "node_modules/@bugsnag/plugin-node-device": { "resolved": "packages/plugin-node-device", "link": true @@ -2936,6 +2940,10 @@ "resolved": "packages/react-native-cli", "link": true }, + "node_modules/@bugsnag/request-tracker": { + "resolved": "packages/request-tracker", + "link": true + }, "node_modules/@bugsnag/safe-json-stringify": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@bugsnag/safe-json-stringify/-/safe-json-stringify-6.0.0.tgz", @@ -53029,6 +53037,7 @@ "packages/plugin-electron-app": { "name": "@bugsnag/plugin-electron-app", "version": "8.7.0", + "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0" @@ -53070,6 +53079,7 @@ "packages/plugin-electron-client-state-persistence": { "name": "@bugsnag/plugin-electron-client-state-persistence", "version": "8.6.0", + "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0" @@ -53443,6 +53453,20 @@ "name": "@bugsnag/plugin-network-breadcrumbs", "version": "8.6.0", "license": "MIT", + "dependencies": { + "@bugsnag/request-tracker": "^8.0.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.6.0" + }, + "peerDependencies": { + "@bugsnag/core": "^8.0.0" + } + }, + "packages/plugin-network-instrumentation": { + "name": "@bugsnag/plugin-network-instrumentation", + "version": "8.6.0", + "license": "MIT", "devDependencies": { "@bugsnag/core": "^8.6.0" }, @@ -53846,6 +53870,14 @@ "node": ">=10.0.0" } }, + "packages/request-tracker": { + "name": "@bugsnag/request-tracker", + "version": "8.0.0", + "license": "MIT", + "dependencies": { + "@bugsnag/core": "^8.0.0" + } + }, "packages/web-worker": { "name": "@bugsnag/web-worker", "version": "8.6.0", @@ -60039,6 +60071,13 @@ }, "@bugsnag/plugin-network-breadcrumbs": { "version": "file:packages/plugin-network-breadcrumbs", + "requires": { + "@bugsnag/core": "^8.6.0", + "@bugsnag/request-tracker": "^8.0.0" + } + }, + "@bugsnag/plugin-network-instrumentation": { + "version": "file:packages/plugin-network-instrumentation", "requires": { "@bugsnag/core": "^8.6.0" } @@ -60265,6 +60304,12 @@ } } }, + "@bugsnag/request-tracker": { + "version": "file:packages/request-tracker", + "requires": { + "@bugsnag/core": "^8.0.0" + } + }, "@bugsnag/safe-json-stringify": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@bugsnag/safe-json-stringify/-/safe-json-stringify-6.0.0.tgz", diff --git a/packages/core/event.d.ts b/packages/core/event.d.ts index 9ace225a89..472cf2adc7 100644 --- a/packages/core/event.d.ts +++ b/packages/core/event.d.ts @@ -1,4 +1,4 @@ -import { App, Device, Event, Request, Breadcrumb, User, Session, FeatureFlag } from './types' +import { App, Device, Event, Request, Response, Breadcrumb, User, Session, FeatureFlag } from './types' import { Error } from './types/event' interface HandledState { @@ -40,6 +40,7 @@ export default class EventWithInternals extends Event { app: App device: Device request: Request + response: Response breadcrumbs: Breadcrumb[] context: string | undefined correlation: { spanId: string, traceId: string } | undefined diff --git a/packages/core/event.js b/packages/core/event.js index 9db8c8e743..65fa843da5 100644 --- a/packages/core/event.js +++ b/packages/core/event.js @@ -23,6 +23,7 @@ class Event { this.app = {} this.device = {} this.request = {} + this.response = {} this.breadcrumbs = [] this.threads = [] @@ -120,6 +121,7 @@ class Event { app: this.app, device: this.device, request: this.request, + response: this.response, breadcrumbs: this.breadcrumbs, context: this.context, groupingHash: this.groupingHash, diff --git a/packages/core/lib/json-payload.js b/packages/core/lib/json-payload.js index d543aed646..62fb286580 100644 --- a/packages/core/lib/json-payload.js +++ b/packages/core/lib/json-payload.js @@ -2,7 +2,8 @@ const jsonStringify = require('@bugsnag/safe-json-stringify') const EVENT_REDACTION_PATHS = [ 'events.[].metaData', 'events.[].breadcrumbs.[].metaData', - 'events.[].request' + 'events.[].request', + 'events.[].response' ] module.exports.event = (event, redactedKeys) => { diff --git a/packages/core/types/common.d.ts b/packages/core/types/common.d.ts index 4fd333d235..430b55c556 100644 --- a/packages/core/types/common.d.ts +++ b/packages/core/types/common.d.ts @@ -120,6 +120,13 @@ interface Request { [key: string]: any } +interface Response { + statusCode: number + headers: { [key: string]: unknown } + body?: string + bodyLength?: number +} + export interface User { id?: string email?: string diff --git a/packages/core/types/event.d.ts b/packages/core/types/event.d.ts index 114b0d2a4a..4c60fd5fe6 100644 --- a/packages/core/types/event.d.ts +++ b/packages/core/types/event.d.ts @@ -3,6 +3,7 @@ import { App, Device, Request, + Response, Logger, User, Thread, @@ -23,6 +24,7 @@ declare class Event { public app: App public device: Device public request: Request + public response: Response public errors: Error[]; public breadcrumbs: Breadcrumb[] diff --git a/packages/plugin-network-breadcrumbs/network-breadcrumbs.js b/packages/plugin-network-breadcrumbs/network-breadcrumbs.js index 86997b9caa..d7d74c57f9 100644 --- a/packages/plugin-network-breadcrumbs/network-breadcrumbs.js +++ b/packages/plugin-network-breadcrumbs/network-breadcrumbs.js @@ -1,7 +1,5 @@ const BREADCRUMB_TYPE = 'request' -const includes = require('@bugsnag/core/lib/es-utils/includes') - /* * Leaves breadcrumbs when network requests occur */ @@ -11,184 +9,63 @@ module.exports = (_ignoredUrls = [], win = window) => { load: client => { if (!client._isBreadcrumbTypeEnabled('request')) return - const ignoredUrls = [ - client._config.endpoints.notify, - client._config.endpoints.sessions - ].concat(_ignoredUrls) - - monkeyPatchXMLHttpRequest() - monkeyPatchFetch() - - // XMLHttpRequest monkey patch - function monkeyPatchXMLHttpRequest () { - if (!('addEventListener' in win.XMLHttpRequest.prototype) || !('WeakMap' in win)) return - - const trackedRequests = new WeakMap() - const requestHandlers = new WeakMap() - - const originalOpen = win.XMLHttpRequest.prototype.open - win.XMLHttpRequest.prototype.open = function open (method, url) { - // it's possible for `this` to be `undefined`, which is not a valid key for a WeakMap - if (this) { - trackedRequests.set(this, { method, url }) - } - originalOpen.apply(this, arguments) - } - - const originalSend = win.XMLHttpRequest.prototype.send - win.XMLHttpRequest.prototype.send = function send (body) { - const requestData = trackedRequests.get(this) - if (requestData) { - // if we have already setup listeners then this request instance is being reused, - // so we need to remove the listeners from the previous send - const listeners = requestHandlers.get(this) - if (listeners) { - this.removeEventListener('load', listeners.load) - this.removeEventListener('error', listeners.error) - } - - const requestStart = new Date() - const error = () => handleXHRError(requestData.method, requestData.url, getDuration(requestStart)) - const load = () => handleXHRLoad(requestData.method, requestData.url, this.status, getDuration(requestStart)) - - this.addEventListener('load', load) - this.addEventListener('error', error) - // it's possible for `this` to be `undefined`, which is not a valid key for a WeakMap - if (this) { - requestHandlers.set(this, { load, error }) - } - } - - originalSend.apply(this, arguments) - } - - if (process.env.NODE_ENV !== 'production') { - restoreFunctions.push(() => { - win.XMLHttpRequest.prototype.open = originalOpen - win.XMLHttpRequest.prototype.send = originalSend - }) + // Try to get existing request tracker + let requestTrackerPlugin = client.getPlugin('requestTracker') + + // Auto-load request tracker if not present + if (!requestTrackerPlugin) { + try { + const { createRequestTrackerPlugin } = require('@bugsnag/request-tracker') + const trackerPlugin = createRequestTrackerPlugin(_ignoredUrls, win) + client._loadPlugin(trackerPlugin) + requestTrackerPlugin = client.getPlugin('requestTracker') + } catch (error) { + client._logger.warn('Failed to auto-load request tracker, falling back to direct monkey-patching:', error.message) } } - function handleXHRLoad (method, url, status, duration) { - if (url === undefined) { - client._logger.warn('The request URL is no longer present on this XMLHttpRequest. A breadcrumb cannot be left for this request.') - return - } - - // an XMLHttpRequest's URL can be an object as long as its 'toString' - // returns a URL, e.g. a HTMLAnchorElement - if (typeof url === 'string' && includes(ignoredUrls, url.replace(/\?.*$/, ''))) { - // don't leave a network breadcrumb from bugsnag notify calls - return - } - const metadata = { - status, - method: String(method), - url: String(url), - duration: duration - } - if (status >= 400) { - // contacted server but got an error response - client.leaveBreadcrumb('XMLHttpRequest failed', metadata, BREADCRUMB_TYPE) - } else { - client.leaveBreadcrumb('XMLHttpRequest succeeded', metadata, BREADCRUMB_TYPE) - } + if (requestTrackerPlugin) { + return useSharedRequestTracker(requestTrackerPlugin) } - function handleXHRError (method, url, duration) { - if (url === undefined) { - client._logger.warn('The request URL is no longer present on this XMLHttpRequest. A breadcrumb cannot be left for this request.') - return - } - - if (typeof url === 'string' && includes(ignoredUrls, url.replace(/\?.*$/, ''))) { - // don't leave a network breadcrumb from bugsnag notify calls - return - } - - // failed to contact server - client.leaveBreadcrumb('XMLHttpRequest error', { - method: String(method), - url: String(url), - duration: duration - }, BREADCRUMB_TYPE) - } - - // window.fetch monkey patch - function monkeyPatchFetch () { - // only patch it if it exists and if it is not a polyfill (patching a polyfilled - // fetch() results in duplicate breadcrumbs for the same request because the - // implementation uses XMLHttpRequest which is also patched) - if (!('fetch' in win) || win.fetch.polyfill) return - - const oldFetch = win.fetch - win.fetch = function fetch () { - const urlOrRequest = arguments[0] - const options = arguments[1] - - let method - let url = null - - if (urlOrRequest && typeof urlOrRequest === 'object') { - url = urlOrRequest.url - if (options && 'method' in options) { - method = options.method - } else if (urlOrRequest && 'method' in urlOrRequest) { - method = urlOrRequest.method - } - } else { - url = urlOrRequest - if (options && 'method' in options) { - method = options.method + function useSharedRequestTracker (trackerPlugin) { + const { fetchTracker, xhrTracker, urlFilter, getDuration } = trackerPlugin + + const handleRequest = (startContext) => { + if (urlFilter(startContext.url)) return + + return { + onRequestEnd: (response) => { + const duration = getDuration(startContext.startTime) + const metadata = { + method: startContext.method, + status: response.status, + url: startContext.url, + duration + } + + const request = startContext.type === 'fetch' ? 'fetch()' : 'XMLHttpRequest' + + if (response.state === 'error') { + client.leaveBreadcrumb(`${request} error`, { method: startContext.method, url: startContext.url, duration }, BREADCRUMB_TYPE) + } else if (response.status >= 400) { + client.leaveBreadcrumb(`${request} failed`, metadata, BREADCRUMB_TYPE) + } else { + client.leaveBreadcrumb(`${request} succeeded`, metadata, BREADCRUMB_TYPE) + } } } - - if (method === undefined) { - method = 'GET' - } - - return new Promise((resolve, reject) => { - const requestStart = new Date() - - // pass through to native fetch - oldFetch(...arguments) - .then(response => { - handleFetchSuccess(response, method, url, getDuration(requestStart)) - resolve(response) - }) - .catch(error => { - handleFetchError(method, url, getDuration(requestStart)) - reject(error) - }) - }) - } - - if (process.env.NODE_ENV !== 'production') { - restoreFunctions.push(() => { - win.fetch = oldFetch - }) } - } - const handleFetchSuccess = (response, method, url, duration) => { - const metadata = { - method: String(method), - status: response.status, - url: String(url), - duration: duration + if (fetchTracker) { + fetchTracker.onStart(handleRequest) + restoreFunctions.push(fetchTracker._restore) } - if (response.status >= 400) { - // when the request comes back with a 4xx or 5xx status it does not reject the fetch promise, - client.leaveBreadcrumb('fetch() failed', metadata, BREADCRUMB_TYPE) - } else { - client.leaveBreadcrumb('fetch() succeeded', metadata, BREADCRUMB_TYPE) + if (xhrTracker) { + xhrTracker.onStart(handleRequest) + restoreFunctions.push(xhrTracker._restore) } } - - const handleFetchError = (method, url, duration) => { - client.leaveBreadcrumb('fetch() error', { method: String(method), url: String(url), duration: duration }, BREADCRUMB_TYPE) - } } } @@ -201,5 +78,3 @@ module.exports = (_ignoredUrls = [], win = window) => { return plugin } - -const getDuration = (startTime) => startTime && new Date() - startTime diff --git a/packages/plugin-network-breadcrumbs/package.json b/packages/plugin-network-breadcrumbs/package.json index 97254e152a..4dad920324 100644 --- a/packages/plugin-network-breadcrumbs/package.json +++ b/packages/plugin-network-breadcrumbs/package.json @@ -19,6 +19,9 @@ "devDependencies": { "@bugsnag/core": "^8.6.0" }, + "dependencies": { + "@bugsnag/request-tracker": "^8.0.0" + }, "peerDependencies": { "@bugsnag/core": "^8.0.0" } diff --git a/packages/plugin-network-breadcrumbs/test/network-breadcrumbs.test.ts b/packages/plugin-network-breadcrumbs/test/network-breadcrumbs.test.ts index 9cdda0fc87..48b3e3459a 100644 --- a/packages/plugin-network-breadcrumbs/test/network-breadcrumbs.test.ts +++ b/packages/plugin-network-breadcrumbs/test/network-breadcrumbs.test.ts @@ -29,6 +29,10 @@ class XMLHttpRequest { this?._listeners[evt].push(listener) } + getAllResponseHeaders () { + return '' + } + removeEventListener (evt: 'load'| 'error', listener: () => void) { for (let i = this?._listeners?.[evt]?.length ?? 0 - 1; i >= 0; i--) { if (listener.name === this?._listeners?.[evt]?.[i]?.name) delete this?._listeners[evt][i] diff --git a/packages/plugin-network-instrumentation/LICENSE.txt b/packages/plugin-network-instrumentation/LICENSE.txt new file mode 100644 index 0000000000..a2829a4909 --- /dev/null +++ b/packages/plugin-network-instrumentation/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2025 Bugsnag + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/plugin-network-instrumentation/README.md b/packages/plugin-network-instrumentation/README.md new file mode 100644 index 0000000000..7217e95216 --- /dev/null +++ b/packages/plugin-network-instrumentation/README.md @@ -0,0 +1,36 @@ +# @bugsnag/plugin-network-instrumentation + +A [@bugsnag/js](https://github.com/bugsnag/bugsnag-js) plugin for HTTP error handling. + +## Installation + +```sh +npm install --save @bugsnag/plugin-network-instrumentation +# or +yarn add @bugsnag/plugin-network-instrumentation +``` + +## Usage + +```js +import Bugsnag from '@bugsnag/js' +import BugsnagPluginNetworkRequests from '@bugsnag/plugin-network-instrumentation' + +Bugsnag.start({ + apiKey: 'YOUR_API_KEY_HERE', + plugins: [BugsnagPluginNetworkInstrumentation({ + httpErrorCodes = [400, 401, { min: 450: max 499 }], // Status codes to report as errors + maxRequestSize = 20_000, // Truncate the request and response body over this size (in kb) + onHttpError: ({ request, response }) => { + request.headers['x-custom-header'] = 'value' // Modify any request values before sending + response.body = 'custom body' // Modify any response values before sending + + return false // Don't report this request an as error + } + })] +}) +``` + +## License + +This package is free software released under the MIT License. See [LICENSE.txt](./LICENSE.txt) for details. diff --git a/packages/plugin-network-instrumentation/lib/extract-domain.js b/packages/plugin-network-instrumentation/lib/extract-domain.js new file mode 100644 index 0000000000..fd290943b5 --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/extract-domain.js @@ -0,0 +1,13 @@ +/** + * Extract domain from URL + * @param {string} url - URL string + * @returns {string} Domain + */ +module.exports = function (url) { + try { + const urlObj = new URL(url) + return urlObj.host + } catch (e) { + return 'unknown' + } +} diff --git a/packages/plugin-network-instrumentation/lib/parse-query-params.js b/packages/plugin-network-instrumentation/lib/parse-query-params.js new file mode 100644 index 0000000000..e9dc18a054 --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/parse-query-params.js @@ -0,0 +1,17 @@ +/** + * Parse query parameters from URL + * @param {string} url - URL string + * @returns {Object} Parsed query parameters + */ +module.exports = function (url) { + try { + const urlObj = new URL(url) + const params = {} + urlObj.searchParams.forEach((value, key) => { + params[key] = value + }) + return params + } catch (e) { + return {} + } +} diff --git a/packages/plugin-network-instrumentation/lib/redact-query-parameters.js b/packages/plugin-network-instrumentation/lib/redact-query-parameters.js new file mode 100644 index 0000000000..3c69f97e08 --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/redact-query-parameters.js @@ -0,0 +1,38 @@ +const redactValues = require('./redact-values') + +function isAbsoluteURL (url) { + try { + // eslint-disable-next-line no-new + new URL(url) + return true + } catch (e) { + return false + } +} + +module.exports = function (url, redactedKeys) { + const isAbsolute = isAbsoluteURL(url) + const base = isAbsolute ? undefined : 'http://localhost' + + // Parse the URL - use a base only for relative URLs + const urlObj = new URL(url, base) + const params = new URLSearchParams(urlObj.search) + + // Convert URLSearchParams to object without using Object.fromEntries() + const paramsObject = {} + params.forEach((value, key) => { + paramsObject[key] = value + }) + + const redactedParams = redactValues(paramsObject, redactedKeys) + urlObj.search = new URLSearchParams(redactedParams).toString() + + // Return appropriate format based on original URL type + if (isAbsolute) { + return decodeURI(urlObj.toString()) + } + + // For relative URLs, return only the path + search + hash components + const relativePart = urlObj.pathname + urlObj.search + urlObj.hash + return decodeURI(relativePart) +} diff --git a/packages/plugin-network-instrumentation/lib/redact-values.js b/packages/plugin-network-instrumentation/lib/redact-values.js new file mode 100644 index 0000000000..23f20b7597 --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/redact-values.js @@ -0,0 +1,15 @@ +/** + * Redact values in an array of objects based on a list of keys + * @param {Record} object + * @param {string[]} keys + * @returns + */ +module.exports = function (object, keys) { + const lowercasedKeys = keys.map(key => key.toLowerCase()) + Object.keys(object).forEach((key) => { + if (lowercasedKeys.includes(key.toLowerCase())) { + object[key] = '[REDACTED]' + } + }) + return object +} diff --git a/packages/plugin-network-instrumentation/lib/should-capture-status-code.js b/packages/plugin-network-instrumentation/lib/should-capture-status-code.js new file mode 100644 index 0000000000..df9a1a0581 --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/should-capture-status-code.js @@ -0,0 +1,17 @@ +/** + * Check if a status code should be captured + * @param {number[]} codes - Array of HTTP status codes + * @param {number} statusCode - HTTP status code + * @returns {boolean} True if should be captured + */ +module.exports = function (codes, statusCode) { + return codes.some(code => { + if (typeof code === 'number') { + return code === statusCode + } + if (code && typeof code === 'object' && 'min' in code && 'max' in code) { + return statusCode >= code.min && statusCode <= code.max + } + return false + }) +} diff --git a/packages/plugin-network-instrumentation/lib/truncate.js b/packages/plugin-network-instrumentation/lib/truncate.js new file mode 100644 index 0000000000..e471cd45ef --- /dev/null +++ b/packages/plugin-network-instrumentation/lib/truncate.js @@ -0,0 +1,10 @@ +/** + * Truncate string to max length + * @param {string} str - String to truncate + * @param {number} maxLength - Maximum length + * @returns {string} Truncated string + */ +module.exports = function (str, maxLength) { + if (!str || str.length <= maxLength) return str + return str.substring(0, maxLength) +} diff --git a/packages/plugin-network-instrumentation/network-instrumentation.js b/packages/plugin-network-instrumentation/network-instrumentation.js new file mode 100644 index 0000000000..51185373ec --- /dev/null +++ b/packages/plugin-network-instrumentation/network-instrumentation.js @@ -0,0 +1,169 @@ +/** + * @bugsnag/plugin-network-instrumentation + * A plugin to automatically capture and report HTTP errors + */ + +const extractDomain = require('./lib/extract-domain') +const parseQueryParams = require('./lib/parse-query-params') +const redactQueryParameters = require('./lib/redact-query-parameters') +const shouldCaptureStatusCode = require('./lib/should-capture-status-code') +const truncate = require('./lib/truncate') + +const DEFAULT_HTTP_ERROR_CODES = [{ min: 400, max: 599 }] +const DEFAULT_MAX_REQUEST_SIZE = 5000 + +/** + * Creates the HTTP errors plugin with configuration + * @param {Object} config - Plugin configuration + * @param {Array|Object|number} config.httpErrorCodes - Error codes to capture + * @param {number} config.maxResponseSize - Maximum response body size to capture + * @param {number} config.maxRequestSize - Maximum request body size to capture + * @param {Function} config.onHttpError - Callback for intercepting HTTP errors + * @returns {Object} Bugsnag plugin + */ +module.exports = (config = {}, global = window) => { + const { + httpErrorCodes = DEFAULT_HTTP_ERROR_CODES, + maxRequestSize = DEFAULT_MAX_REQUEST_SIZE, + onHttpError + } = config + + // Normalize httpErrorCodes to an array + const normalizedStatusCodes = Array.isArray(httpErrorCodes) ? httpErrorCodes : [httpErrorCodes] + + let restoreFunctions = [] + const plugin = { + name: 'httpErrors', + load: (client) => { + // Try to get existing request tracker + let requestTrackerPlugin = client.getPlugin('requestTracker') + + // Auto-load request tracker if not present + if (!requestTrackerPlugin) { + try { + const { createRequestTrackerPlugin } = require('@bugsnag/request-tracker') + const trackerPlugin = createRequestTrackerPlugin([], global) + client._loadPlugin(trackerPlugin) + requestTrackerPlugin = client.getPlugin('requestTracker') + } catch (error) { + client._logger.warn('Failed to auto-load request tracker, using direct fetch patching:', error.message) + } + } + + // Use shared request tracker if available + if (requestTrackerPlugin) { + const { fetchTracker, xhrTracker } = requestTrackerPlugin + + if (fetchTracker) { + restoreFunctions.push(fetchTracker._restore) + fetchTracker.onStart((startContext) => { + return { + onRequestEnd: (endContext) => { + handleHttpError(startContext, endContext) + } + } + }) + } + if (xhrTracker) { + restoreFunctions.push(xhrTracker._restore) + xhrTracker.onStart((startContext) => { + return { + onRequestEnd: (endContext) => { + handleHttpError(startContext, endContext) + } + } + }) + } + } + + function handleHttpError (startContext, endContext) { + // Check if we should capture this status code + if (!shouldCaptureStatusCode(normalizedStatusCodes, endContext.status)) return + + try { + // Extract request information + const url = startContext.url + const requestParams = parseQueryParams(url) + const method = startContext.method + const domain = extractDomain(url) + + // Create request and response objects for callback + const requestObj = { + url: startContext.url, + httpMethod: startContext.method, + headers: startContext.headers, + params: requestParams, + body: startContext.body, + bodyLength: startContext.body ? startContext.body.length : undefined + } + const responseObj = { + statusCode: endContext.status, + headers: endContext.headers, + body: endContext.body, + bodyLength: endContext.body ? endContext.body.length : undefined + } + + // Call onHttpError callback if provided + if (onHttpError) { + const result = onHttpError({ request: requestObj, response: responseObj }) + + // If onHttpError returns false, don't capture + if (result === false) { + return + } + } + + // Truncate request body + if (requestObj.body) { + requestObj.body = truncate(requestObj.body, maxRequestSize) + } + + // Truncate response body - XHR only + if (responseObj.body) { + responseObj.body = truncate(responseObj.body, maxRequestSize) + } + + // Strip query parameters from URL + if (requestObj.url !== '[REDACTED]') { + requestObj.url = redactQueryParameters(requestObj.url, client._config.redactedKeys) + } + + // Create error and notify + const error = new Error(`${responseObj.statusCode}: ${requestObj.url}`) + error.name = 'HTTPError' + + const handledState = { + severity: 'error', + unhandled: true, + severityReason: { type: 'httpError' } + } + + const event = client.Event.create( + error, + true, + handledState, + 'http errors plugin', + 0 + ) + + event.request = requestObj + event.response = responseObj + event.context = `${method} ${domain}` + + client._notify(event) + } catch (err) { + client._logger.error('Failed to process HTTP error:', err.message) + } + } + } + } + + if (process.env.NODE_ENV !== 'production') { + plugin.destroy = () => { + restoreFunctions.forEach(fn => fn()) + restoreFunctions = [] + } + } + + return plugin +} diff --git a/packages/plugin-network-instrumentation/package.json b/packages/plugin-network-instrumentation/package.json new file mode 100644 index 0000000000..de3e9825ca --- /dev/null +++ b/packages/plugin-network-instrumentation/package.json @@ -0,0 +1,28 @@ +{ + "name": "@bugsnag/plugin-network-instrumentation", + "version": "8.6.0", + "main": "network-instrumentation.js", + "types": "types/bugsnag-plugin-network-instrumentation.d.ts", + "description": "@bugsnag/js plugin for HTTP error handling", + "homepage": "https://www.bugsnag.com/", + "repository": { + "type": "git", + "url": "git@github.com:bugsnag/bugsnag-js.git" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "network-instrumentation.js", + "lib", + "types" + ], + "author": "Bugsnag", + "license": "MIT", + "devDependencies": { + "@bugsnag/core": "^8.6.0" + }, + "peerDependencies": { + "@bugsnag/core": "^8.0.0" + } +} diff --git a/packages/plugin-network-instrumentation/test/network-instrumentation-xhr.test.ts b/packages/plugin-network-instrumentation/test/network-instrumentation-xhr.test.ts new file mode 100644 index 0000000000..811447700e --- /dev/null +++ b/packages/plugin-network-instrumentation/test/network-instrumentation-xhr.test.ts @@ -0,0 +1,242 @@ +import Client, { Delivery } from '@bugsnag/core/client' +import createPlugin from '..' +import Event from '@bugsnag/core/event' +import { Plugin } from '@bugsnag/core' + +const createMockDelivery = (notifyCallbacks: Event[]) => (): Delivery => ({ + sendEvent: (payload) => { + notifyCallbacks.push(payload.events[0]) + }, + sendSession: () => {} +}) + +describe('plugin-network-instrumentation', () => { + describe('XMLHttpRequest support', () => { + let originalXMLHttpRequest: typeof XMLHttpRequest + let plugin: Plugin + + class MockXMLHttpRequest { + _listeners: { load: Array<() => void>, error: Array<() => void>, loadend: Array<() => void> } + status: number | null + statusText: string + responseURL: string + response: string + responseText: string + responseType: string + _method: string + _url: string + _requestHeaders: Headers + _requestBody: string | null + + constructor () { + this._listeners = { load: [], error: [], loadend: [] } + this.status = null + this.statusText = '' + this.responseURL = '' + this.response = '' + this.responseText = '' + this.responseType = '' + this._method = 'GET' + this._url = '' + this._requestHeaders = new Headers() + this._requestBody = null + } + + open (method: string, url: string) { + this._method = method + this._url = url + this.responseURL = url + } + + send (body?: string | null) { + this._requestBody = body || null + // Simulate async request completion + setTimeout(() => { + this._listeners.load.forEach(fn => fn()) + this._listeners.loadend.forEach(fn => fn()) + }, 0) + } + + setRequestHeader (name: string, value: string) { + this._requestHeaders.set(name.toLowerCase(), value) + } + + addEventListener (evt: 'load' | 'error' | 'loadend', listener: () => void) { + this._listeners[evt]?.push(listener) + } + + removeEventListener (evt: 'load' | 'error' | 'loadend', listener: () => void) { + const listeners = this._listeners[evt] + if (listeners) { + const index = listeners.indexOf(listener) + if (index >= 0) { + listeners.splice(index, 1) + } + } + } + + getAllResponseHeaders () { + return 'content-type: application/json\r\ncontent-length: 45\r\n' + } + + // Helper method to simulate error responses + simulateError () { + setTimeout(() => { + this._listeners.error.forEach(fn => fn()) + this._listeners.loadend.forEach(fn => fn()) + }, 0) + } + } + + beforeEach(() => { + originalXMLHttpRequest = global.XMLHttpRequest + global.XMLHttpRequest = MockXMLHttpRequest as any + }) + + afterEach(() => { + global.XMLHttpRequest = originalXMLHttpRequest + plugin.destroy?.() + }) + + it('should capture XHR errors with response body and body length', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Create and configure XHR instance + const xhr = new XMLHttpRequest() as any + xhr.status = 404 + xhr.statusText = 'Not Found' + xhr.responseURL = 'https://api.example.com/users/123' + xhr.response = '{"error": "User not found", "code": "USER_NOT_FOUND"}' + xhr.responseText = '{"error": "User not found", "code": "USER_NOT_FOUND"}' + + // Simulate an XHR request + xhr.open('POST', 'https://api.example.com/users/123') + xhr.setRequestHeader('Content-Type', 'application/json') + + // Send request with body + const requestBody = '{"name": "John Doe", "email": "john@example.com"}' + xhr.send(requestBody) + + // Wait for async processing + await new Promise(resolve => setTimeout(resolve, 20)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + // Verify error details + expect(event.exceptions[0].errorClass).toBe('HTTPError') + expect(event.exceptions[0].errorMessage).toBe('404: https://api.example.com/users/123') + expect(event.context).toBe('POST api.example.com') + expect(event.severity).toBe('error') + expect(event.unhandled).toBe(true) + expect(event.severityReason.type).toBe('httpError') + + // Verify request metadata + expect(event.request.url).toBe('https://api.example.com/users/123') + expect(event.request.httpMethod).toBe('POST') + expect(event.request.body).toBe(requestBody) + expect(event.request.bodyLength).toBe(requestBody.length) + // expect(event.request.headers?.['content-type']).toBe('application/json') + + // Verify response metadata including body + expect(event.response.statusCode).toBe(404) + expect(event.response.headers['content-type']).toBe('application/json') + expect(event.response.headers['content-length']).toBe('45') + expect(event.response.body).toBe('{"error": "User not found", "code": "USER_NOT_FOUND"}') + expect(event.response.bodyLength).toBe(xhr.responseText.length) + }) + + it('should truncate XHR response body when it exceeds maxRequestSize', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 }, + maxRequestSize: 20 + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Create and configure XHR with large response body + const xhr = new XMLHttpRequest() as any + const largeResponseBody = 'A'.repeat(100) + xhr.status = 404 + xhr.statusText = 'Internal Server Error' + xhr.responseURL = 'https://api.example.com/error' + xhr.response = largeResponseBody + xhr.responseText = largeResponseBody + + xhr.open('GET', 'https://api.example.com/error') + xhr.send() + + // Wait for async processing + await new Promise(resolve => setTimeout(resolve, 20)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + // Verify response body is truncated but original length is preserved + expect(event.response.body?.length).toBeLessThanOrEqual(20) + expect(event.response.bodyLength).toBe(100) + }) + + it('should handle XHR network errors', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + const xhr = new XMLHttpRequest() as any + xhr.open('GET', 'https://api.example.com/error') + xhr.send() + + // Simulate a network error + xhr.simulateError() + + await new Promise(resolve => setTimeout(resolve, 20)) + + // Network errors typically don't generate HTTP error events in this plugin + // since they don't have status codes, but let's verify the behavior + expect(notifyCallbacks.length).toBe(0) + }) + + it('should redact specified query parameters in XHR URLs', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin], redactedKeys: ['token', 'userId'] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + const xhr = new XMLHttpRequest() as any + xhr.status = 403 + xhr.statusText = 'Forbidden' + xhr.response = 'Forbidden' + xhr.responseText = 'Forbidden' + + xhr.open('GET', 'https://api.example.com/data?userId=42') + xhr.send() + + await new Promise(resolve => setTimeout(resolve, 20)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + // Verify that sensitive query parameters are redacted + expect(event.request.url).toBe('https://api.example.com/data?userId=[REDACTED]') + }) + }) +}) diff --git a/packages/plugin-network-instrumentation/test/network-instrumentation.test.ts b/packages/plugin-network-instrumentation/test/network-instrumentation.test.ts new file mode 100644 index 0000000000..4754aadfb8 --- /dev/null +++ b/packages/plugin-network-instrumentation/test/network-instrumentation.test.ts @@ -0,0 +1,685 @@ +import Client, { Delivery } from '@bugsnag/core/client' +import createPlugin from '..' +import Event from '@bugsnag/core/event' +import { Plugin } from '@bugsnag/core' + +// Mock fetch globally +const originalFetch = global.fetch + +// Helper to create mock response with clone method +const createMockResponse = (options: any) => { + const response = { + ok: options.ok !== undefined ? options.ok : true, + status: options.status || 200, + statusText: options.statusText || 'OK', + url: options.url || '', + headers: options.headers || new Headers(), + text: options.text || (async () => '') + } + return response +} + +const createMockDelivery = (notifyCallbacks: Event[]) => (): Delivery => ({ + sendEvent: (payload) => { + notifyCallbacks.push(payload.events[0]) + }, + sendSession: () => {} +}) + +describe('plugin-network-instrumentation', () => { + let mockFetch: jest.Mock + let plugin: Plugin + + beforeEach(() => { + mockFetch = jest.fn() + global.fetch = mockFetch + }) + + afterEach(() => { + global.fetch = originalFetch + jest.clearAllMocks() + plugin.destroy?.() + }) + + describe('plugin configuration', () => { + it('should export a plugin with name and load function', () => { + plugin = createPlugin() + expect(plugin.name).toBe('httpErrors') + expect(typeof plugin.load).toBe('function') + }) + + it('should load without configuration', () => { + plugin = createPlugin() + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + expect(client).toBeDefined() + }) + }) + + describe('config.httpErrorCodes - single range', () => { + it('should capture 4xx errors when configured with single range', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue(createMockResponse({ + ok: false, + status: 404, + statusText: 'Not Found', + url: 'https://example.com/api/users', + headers: new Headers({ 'content-type': 'application/json' }), + text: async () => '{"error": "User not found"}' + })) + + await fetch('https://example.com/api/users') + + // Wait for async processing + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + expect(event.exceptions[0].errorClass).toBe('HTTPError') + expect(event.exceptions[0].errorMessage).toBe('404: https://example.com/api/users') + expect(event.context).toBe('GET example.com') + expect(event.severity).toBe('error') + expect(event.unhandled).toBe(true) + expect(event.severityReason.type).toBe('httpError') + expect(event.request.url).toBe('https://example.com/api/users') + expect(event.request.httpMethod).toBe('GET') + expect(event.response.statusCode).toBe(404) + expect(event.response.headers['content-type']).toBe('application/json') + }) + + it('should not capture 2xx successful responses', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: true, + status: 200, + statusText: 'OK', + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => '{"success": true}' + }) + + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(0) + }) + + it('should not capture 5xx errors when configured for 4xx only', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + url: 'https://example.com/api/error', + headers: new Headers(), + text: async () => 'Server error' + }) + + await fetch('https://example.com/api/error') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(0) + }) + }) + + describe('config.httpErrorCodes - multiple ranges and specific codes', () => { + it('should capture errors matching any range or specific code', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: [{ min: 400, max: 499 }, 500, 503] + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Test 404 (in range) + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + statusText: 'Not Found', + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Test 500 (specific code) + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + url: 'https://example.com/api/error', + headers: new Headers(), + text: async () => 'Server error' + }) + await fetch('https://example.com/api/error') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Test 503 (specific code) + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 503, + statusText: 'Service Unavailable', + url: 'https://example.com/api/service', + headers: new Headers(), + text: async () => 'Service unavailable' + }) + await fetch('https://example.com/api/service') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Test 502 (not in list) + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 502, + statusText: 'Bad Gateway', + url: 'https://example.com/api/gateway', + headers: new Headers(), + text: async () => 'Bad gateway' + }) + await fetch('https://example.com/api/gateway') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(3) + expect(notifyCallbacks[0].errors[0].errorMessage).toContain('404') + expect(notifyCallbacks[1].errors[0].errorMessage).toContain('500') + expect(notifyCallbacks[2].errors[0].errorMessage).toContain('503') + }) + }) + + describe('config.httpErrorCodes - default behavior', () => { + it('should capture all 4xx and 5xx errors by default', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin() // No config + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Test 404 + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Test 500 + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + url: 'https://example.com/api/error', + headers: new Headers(), + text: async () => 'Server error' + }) + await fetch('https://example.com/api/error') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(2) + }) + }) + + describe('config.maxRequestSize', () => { + it('should truncate request body when it exceeds maxRequestSize', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 }, + maxRequestSize: 50 + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + const largeRequestBody = 'C'.repeat(100) + mockFetch.mockResolvedValue({ + ok: false, + status: 400, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Bad request' + }) + + await fetch('https://example.com/api/users', { + method: 'POST', + body: largeRequestBody + }) + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + const requestMetadata = event.request + + expect(requestMetadata.body.length).toBeLessThanOrEqual(50) + expect(requestMetadata.bodyLength).toBe(100) + }) + + it('should use default maxRequestSize of 5000 when not specified', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + const largeRequestBody = 'D'.repeat(10000) + mockFetch.mockResolvedValue({ + ok: false, + status: 400, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Bad request' + }) + + await fetch('https://example.com/api/users', { + method: 'POST', + body: largeRequestBody + }) + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0] + const requestMetadata = event.request + + expect(requestMetadata.body.length).toBeLessThanOrEqual(5000) + expect(requestMetadata.bodyLength).toBe(10000) + }) + }) + + describe('config.onHttpError callback', () => { + it('should call onHttpError callback with request and response objects', async () => { + const onHttpError = jest.fn() + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 }, + onHttpError + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(onHttpError).toHaveBeenCalled() + const callArg = onHttpError.mock.calls[0][0] + expect(callArg.request).toBeDefined() + expect(callArg.request.url).toBe('https://example.com/api/users') + expect(callArg.response).toBeDefined() + expect(callArg.response.statusCode).toBe(404) + }) + + it('should prevent event creation when onHttpError returns false', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 }, + onHttpError: ({ request }) => { + // Filter out requests with PII + if (request.url?.includes('PII')) return false + return true + } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Request with PII - should be filtered + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + url: 'https://example.com/api/users/PII/data', + headers: new Headers(), + text: async () => 'Not found' + }) + await fetch('https://example.com/api/users/PII/data') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Normal request - should go through + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + expect(notifyCallbacks[0].errors[0].errorMessage).not.toContain('PII') + }) + + it('should allow onHttpError to modify request and response', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 }, + onHttpError: ({ request, response }) => { + // Redact sensitive information + request.url = '[REDACTED]' + response.statusCode = 418 + return true + } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + const requestMetadata = event.request + const responseMetadata = event.response + + expect(requestMetadata.url).toBe('[REDACTED]') + expect(responseMetadata.statusCode).toBe(418) + }) + + it('should filter errors by status code in onHttpError', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: [{ min: 400, max: 599 }], + onHttpError: ({ response }) => { + // Only handle 5xx errors + if (response.statusCode < 500 || response.statusCode > 599) return false + return true + } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + // Test 4xx - should be filtered + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + // Test 5xx - should be captured + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + url: 'https://example.com/api/error', + headers: new Headers(), + text: async () => 'Server error' + }) + await fetch('https://example.com/api/error') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + expect(notifyCallbacks[0].response.statusCode).toBe(500) + }) + }) + + describe('event data validation', () => { + it('should populate event.errors with correct structure', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + statusText: 'Not Found', + url: 'https://example.com/api/users/123', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/users/123') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0] + + expect(event.errors).toHaveLength(1) + expect(event.errors[0].errorClass).toBe('HTTPError') + expect(event.errors[0].errorMessage).toBe('404: https://example.com/api/users/123') + }) + + it('should set event.context to method and domain', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/users', { method: 'POST' }) + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0] + expect(event.context).toBe('POST example.com') + }) + + it('should populate request metadata with all fields', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 400, + url: 'https://example.com/api/users?page=1&limit=10', + headers: new Headers(), + text: async () => 'Bad request' + }) + + await fetch('https://example.com/api/users?page=1&limit=10', { + method: 'POST', + headers: new Headers({ 'Content-Type': 'application/json', Authorization: 'Bearer token' }), + body: JSON.stringify({ name: 'John' }) + }) + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + expect(event.request.url).toBe('https://example.com/api/users?page=1&limit=10') + expect(event.request.httpMethod).toBe('POST') + expect(event.request.headers).toBeDefined() + expect(event.request.headers?.['content-type']).toBe('application/json') + expect(event.request.params).toBeDefined() + expect(event.request.params.page).toBe('1') + expect(event.request.params.limit).toBe('10') + expect(event.request.body).toBeDefined() + expect(event.request.bodyLength).toBeDefined() + }) + + it('should populate response metadata with all fields', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 400, + statusText: 'Bad Request', + url: 'https://example.com/api/users', + headers: new Headers({ + 'content-type': 'application/json', + 'x-request-id': '12345' + }) + }) + + await fetch('https://example.com/api/users') + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + + expect(event.response.statusCode).toBe(400) + expect(event.response.headers).toBeDefined() + expect(event.response.headers['content-type']).toBe('application/json') + expect(event.response.headers['x-request-id']).toBe('12345') + }) + + it('should handle requests with different HTTP methods', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] + + for (const method of methods) { + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + url: 'https://example.com/api/resource', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/resource', { method }) + await new Promise(resolve => setTimeout(resolve, 10)) + } + + expect(notifyCallbacks.length).toBe(methods.length) + methods.forEach((method, index) => { + const requestMetadata = notifyCallbacks[index].request + expect(requestMetadata.httpMethod).toBe(method) + expect(notifyCallbacks[index].context).toBe(`${method} example.com`) + }) + }) + + it('should handle URLs with ports', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + url: 'https://example.com:8080/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com:8080/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0] + expect(event.context).toBe('GET example.com:8080') + expect(event.errors[0].errorMessage).toBe('404: https://example.com:8080/api/users') + }) + + it('should handle requests without query parameters', async () => { + const notifyCallbacks: Event[] = [] + + plugin = createPlugin({ + httpErrorCodes: { min: 400, max: 499 } + }) + + const client = new Client({ apiKey: 'api_key', plugins: [plugin] }) + client._setDelivery(createMockDelivery(notifyCallbacks)) + + mockFetch.mockResolvedValue({ + ok: false, + status: 404, + url: 'https://example.com/api/users', + headers: new Headers(), + text: async () => 'Not found' + }) + + await fetch('https://example.com/api/users') + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(notifyCallbacks.length).toBe(1) + const event = notifyCallbacks[0].toJSON() + const requestMetadata = event.request + expect(requestMetadata.params).toEqual({}) + }) + }) +}) diff --git a/packages/plugin-network-instrumentation/test/redact-query-parameters.test.ts b/packages/plugin-network-instrumentation/test/redact-query-parameters.test.ts new file mode 100644 index 0000000000..1e5889df21 --- /dev/null +++ b/packages/plugin-network-instrumentation/test/redact-query-parameters.test.ts @@ -0,0 +1,24 @@ +import redactQueryParameters from '../lib/redact-query-parameters' + +describe('redact-query-parameters', () => { + it('redacts specified query parameters in a URL', () => { + const url = 'http://example.com/path?token=abc123&userId=42&status=active' + const redactedKeys = ['token', 'userId'] + const redactedUrl = redactQueryParameters(url, redactedKeys) + expect(redactedUrl).toBe('http://example.com/path?token=[REDACTED]&userId=[REDACTED]&status=active') + }) + + it('handles URLs with no query parameters', () => { + const url = 'http://example.com/path' + const redactedKeys = ['token'] + const redactedUrl = redactQueryParameters(url, redactedKeys) + expect(redactedUrl).toBe('http://example.com/path') + }) + + it('handles relative URLs', () => { + const url = '/path?token=abc123&userId=42' + const redactedKeys = ['token', 'userId'] + const redactedUrl = redactQueryParameters(url, redactedKeys) + expect(redactedUrl).toBe('/path?token=[REDACTED]&userId=[REDACTED]') + }) +}) diff --git a/packages/plugin-network-instrumentation/types/bugsnag-plugin-network-instrumentation.d.ts b/packages/plugin-network-instrumentation/types/bugsnag-plugin-network-instrumentation.d.ts new file mode 100644 index 0000000000..234af92710 --- /dev/null +++ b/packages/plugin-network-instrumentation/types/bugsnag-plugin-network-instrumentation.d.ts @@ -0,0 +1,47 @@ +import { Plugin, Request, Response } from '@bugsnag/core' + +/** + * Represents a range of HTTP status codes. + * Inclusive of minimum and maximum value. + */ +export interface HttpErrorRange { + min: number + max: number +} + +export interface HttpErrorCallbackInfo { + request: Request + response: Response +} + +export interface BugsnagPluginHttpErrorsConfiguration { + /** + * HTTP status codes to capture. Can be: + * - A single number (e.g., 404) + * - A range object with min/max (e.g., { min: 400, max: 499 }) + * - An array of numbers and/or ranges (e.g., [404, { min: 500, max: 599 }]) + * @default [{ min: 400, max: 599 }] + */ + httpErrorCodes?: number | HttpErrorRange | Array + + /** + * Maximum size of the request body to capture (in characters) + * @default 5000 + */ + maxRequestSize?: number + + /** + * Callback function to intercept HTTP errors before they are reported. + * Return false to prevent the error from being reported. + * You can modify the request and response objects directly. + * @param info - Object containing request and response information + * @returns false to prevent reporting, or void/true to continue + */ + onHttpError?: (info: HttpErrorCallbackInfo) => boolean | void +} + +declare function BugsnagPluginHttpErrors( + config?: BugsnagPluginHttpErrorsConfiguration +): Plugin + +export default BugsnagPluginHttpErrors diff --git a/packages/request-tracker/index.js b/packages/request-tracker/index.js new file mode 100644 index 0000000000..f47ab2bc5c --- /dev/null +++ b/packages/request-tracker/index.js @@ -0,0 +1,42 @@ +const RequestTracker = require('./lib/request-tracker') +const createFetchTracker = require('./lib/fetch-tracker') +const createXhrTracker = require('./lib/xhr-tracker') +const { createUrlFilter, getDuration } = require('./lib/url-helpers') + +/** + * Create an auto-loading request tracker plugin + * @param {Array} ignoredUrls - Additional URLs to ignore + * @param {Object} global - Global object (window or global) + * @returns {Object} Bugsnag plugin + */ +function createRequestTrackerPlugin (ignoredUrls = [], global = window) { + return { + name: 'requestTracker', + load: (client) => { + try { + const fetchTracker = createFetchTracker(global) + const xhrTracker = createXhrTracker(global) + const urlFilter = createUrlFilter(client, ignoredUrls) + + return { + fetchTracker, + xhrTracker, + urlFilter, + getDuration + } + } catch (error) { + client._logger.error('Failed to load request tracker:', error) + throw new Error('Request tracking is not available: ' + error.message) + } + } + } +} + +module.exports = { + RequestTracker, + createFetchTracker, + createXhrTracker, + createUrlFilter, + getDuration, + createRequestTrackerPlugin +} diff --git a/packages/request-tracker/lib/fetch-tracker.js b/packages/request-tracker/lib/fetch-tracker.js new file mode 100644 index 0000000000..edbce2a05f --- /dev/null +++ b/packages/request-tracker/lib/fetch-tracker.js @@ -0,0 +1,103 @@ +const headersToObject = require('./headers-to-object') +const RequestTracker = require('./request-tracker') + +/** + * Create fetch request tracker with singleton pattern + * @param {Object} global - Global object (window or global) + * @param {Object} options - Configuration options + * @returns {Object} Tracker instance + */ +function createFetchTracker (global, options = {}) { + // only patch it if it exists and if it is not a polyfill (patching a polyfilled + // fetch() results in duplicate breadcrumbs for the same request because the + // implementation uses XMLHttpRequest which is also patched) + if (!('fetch' in global) || global.fetch.polyfill) return + + // Use singleton pattern - one tracker per global context + if (!global.__bugsnag_fetch_tracker__) { + const tracker = new RequestTracker() + const originalFetch = global.fetch + + global.fetch = function wrappedFetch (urlOrRequest, options = {}) { + let url = null + let method = 'GET' + + if (urlOrRequest && typeof urlOrRequest === 'object') { + url = urlOrRequest.url + if (options && 'method' in options) { + method = options.method + } else if (urlOrRequest && 'method' in urlOrRequest) { + method = urlOrRequest.method + } + } else { + url = urlOrRequest + if (options && 'method' in options) { + method = options.method + } + } + + if (method === undefined) { + method = 'GET' + } + + let requestHeaders = {} + if (options && options.headers) { + // eslint-disable-next-line no-undef + if (options.headers instanceof Headers) { + requestHeaders = headersToObject(options.headers) + } else if (typeof options.headers === 'object') { + requestHeaders = options.headers + } + } + + const startTime = Date.now() + const context = { + url: String(url), + method: String(method), + startTime, + type: 'fetch', + input: urlOrRequest, + headers: requestHeaders, + body: options ? options.body : undefined + } + + const { onRequestEnd } = tracker.start(context) + + // Call original fetch + return originalFetch.call(this, ...arguments).then( + response => { + onRequestEnd({ + endTime: Date.now(), + status: response.status, + state: 'success', + headers: headersToObject(response.headers) + }) + return response + }, + error => { + onRequestEnd({ + endTime: Date.now(), + state: 'error', + error + }) + throw error + } + ) + } + + // Store tracker and mark as active + global.__bugsnag_fetch_tracker__ = tracker + + // Restore function for development + if (process.env.NODE_ENV !== 'production') { + tracker._restore = () => { + global.fetch = originalFetch + delete global.__bugsnag_fetch_tracker__ + } + } + } + + return global.__bugsnag_fetch_tracker__ +} + +module.exports = createFetchTracker diff --git a/packages/request-tracker/lib/headers-to-object.js b/packages/request-tracker/lib/headers-to-object.js new file mode 100644 index 0000000000..c7f0964559 --- /dev/null +++ b/packages/request-tracker/lib/headers-to-object.js @@ -0,0 +1,24 @@ +/** + * Convert Headers object to plain object + * @param {Headers} headers - Headers object + * @returns {Object} Plain object with header key-value pairs + */ +module.exports = function (headers) { + if (!headers) return {} + + const obj = {} + if (typeof headers.entries === 'function') { + const iterator = headers.entries() + let entry = iterator.next() + while (!entry.done) { + const [key, value] = entry.value + obj[key] = value + entry = iterator.next() + } + } else if (headers.forEach) { + headers.forEach((value, key) => { + obj[key] = value + }) + } + return obj +} diff --git a/packages/request-tracker/lib/request-tracker.js b/packages/request-tracker/lib/request-tracker.js new file mode 100644 index 0000000000..c59330ec1a --- /dev/null +++ b/packages/request-tracker/lib/request-tracker.js @@ -0,0 +1,66 @@ +/** + * Singleton RequestTracker class for managing HTTP request instrumentation + * Allows multiple plugins to register callbacks for the same requests + */ +class RequestTracker { + constructor () { + this.callbacks = [] + } + + /** + * Register a callback to be called when a request starts + * @param {Function} callback - Function to call with request context + */ + onStart (callback) { + if (typeof callback !== 'function') { + throw new Error('RequestTracker onStart callback must be a function') + } + this.callbacks.push(callback) + } + + /** + * Notify all registered callbacks about a request start + * @param {Object} context - Request start context + * @returns {Object} Combined result with onRequestEnd callbacks + */ + start (context) { + const results = this.callbacks + .map(callback => { + try { + return callback(context) + } catch (error) { + // Isolate plugin errors - don't let one plugin break others + console.error('RequestTracker callback error:', error) + return null + } + }) + .filter(result => result && typeof result === 'object') + + return { + onRequestEnd: (endContext) => { + results.forEach(result => { + if (typeof result.onRequestEnd === 'function') { + try { + result.onRequestEnd(endContext) + } catch (error) { + console.error('RequestTracker onRequestEnd callback error:', error) + } + } + }) + }, + extraRequestHeaders: results + .map(result => result.extraRequestHeaders) + .filter(headers => headers && typeof headers === 'object') + .reduce((combined, headers) => Object.assign(combined, headers), {}) + } + } + + /** + * Reset tracker (for testing) + */ + _reset () { + this.callbacks = [] + } +} + +module.exports = RequestTracker diff --git a/packages/request-tracker/lib/url-helpers.js b/packages/request-tracker/lib/url-helpers.js new file mode 100644 index 0000000000..5d882bf01e --- /dev/null +++ b/packages/request-tracker/lib/url-helpers.js @@ -0,0 +1,46 @@ +const includes = require('@bugsnag/core/lib/es-utils/includes') + +/** + * Check if a URL should be ignored for tracking + * @param {string} url - URL to check + * @param {Array} ignoredUrls - Array of URLs to ignore + * @returns {boolean} True if URL should be ignored + */ +function shouldIgnoreUrl (url, ignoredUrls = []) { + if (!url || typeof url !== 'string') return true + + // Remove query parameters for comparison + const urlWithoutQuery = url.replace(/\?.*$/, '') + + return includes(ignoredUrls, urlWithoutQuery) +} + +/** + * Create URL filtering function for Bugsnag endpoints and custom ignored URLs + * @param {Object} client - Bugsnag client instance + * @param {Array} additionalIgnoredUrls - Additional URLs to ignore + * @returns {Function} URL filtering function + */ +function createUrlFilter (client, additionalIgnoredUrls = []) { + const ignoredUrls = [ + client._config.endpoints.notify, + client._config.endpoints.sessions + ].concat(additionalIgnoredUrls).filter(Boolean) + + return (url) => shouldIgnoreUrl(url, ignoredUrls) +} + +/** + * Calculate duration from start time + * @param {number} startTime - Start timestamp + * @returns {number} Duration in milliseconds + */ +function getDuration (startTime) { + return startTime && Date.now() - startTime +} + +module.exports = { + shouldIgnoreUrl, + createUrlFilter, + getDuration +} diff --git a/packages/request-tracker/lib/xhr-header-string-to-object.js b/packages/request-tracker/lib/xhr-header-string-to-object.js new file mode 100644 index 0000000000..ef17faf1c3 --- /dev/null +++ b/packages/request-tracker/lib/xhr-header-string-to-object.js @@ -0,0 +1,18 @@ + +/** + * Converts an XHR header string to an object + * @param {string} headersString + * @returns {Object} + */ +module.exports = function (headersString) { + if (!headersString) return {} + const arr = headersString.trim().split(/[\r\n]+/) + const headerMap = {} + arr.forEach((line) => { + const parts = line.split(': ') + const header = parts.shift() + const value = parts.join(': ') + headerMap[header] = value + }) + return headerMap +} diff --git a/packages/request-tracker/lib/xhr-tracker.js b/packages/request-tracker/lib/xhr-tracker.js new file mode 100644 index 0000000000..ea043af24c --- /dev/null +++ b/packages/request-tracker/lib/xhr-tracker.js @@ -0,0 +1,117 @@ +const RequestTracker = require('./request-tracker') +const xhrHeaderStringToObject = require('./xhr-header-string-to-object') + +/** + * Create XHR request tracker with singleton pattern + * @param {Object} global - Global object (window or global) + * @param {Object} options - Configuration options + * @returns {Object} Tracker instance + */ +function createXhrTracker (global, options = {}) { + if (!('addEventListener' in global.XMLHttpRequest.prototype) || !('WeakMap' in global)) return + + // Use singleton pattern - one tracker per global context + if (!global.__bugsnag_xhr_tracker__) { + const tracker = new RequestTracker() + + const trackedRequests = new WeakMap() + const requestHandlers = new WeakMap() + + const originalOpen = global.XMLHttpRequest.prototype.open + const originalSend = global.XMLHttpRequest.prototype.send + const originalSetRequestHeader = global.XMLHttpRequest.prototype.setRequestHeader + + global.XMLHttpRequest.prototype.open = function open (method, url) { + // it's possible for `this` to be `undefined`, which is not a valid key for a WeakMap + if (this) { + trackedRequests.set(this, { method: String(method), url: String(url) }) + } + originalOpen.apply(this, arguments) + } + + global.XMLHttpRequest.prototype.setRequestHeader = function setRequestHeader (header, value) { + // it's possible for `this` to be `undefined`, which is not a valid key for a WeakMap + if (this) { + const requestData = trackedRequests.get(this) + if (requestData) { + requestData.headers = requestData.headers || {} + requestData.headers[String(header)] = (requestData.headers[String(header)] || '') + String(value) + } + } + originalSetRequestHeader.apply(this, arguments) + } + + global.XMLHttpRequest.prototype.send = function send (body) { + const requestData = trackedRequests.get(this) + if (requestData) { + // if we have already setup listeners then this request instance is being reused, + // so we need to remove the listeners from the previous send + const listeners = requestHandlers.get(this) + if (listeners) { + this.removeEventListener('load', listeners.load) + this.removeEventListener('error', listeners.error) + } + + const startTime = Date.now() + const context = { + url: requestData.url, + method: requestData.method, + startTime, + type: 'xmlhttprequest', + body, + headers: requestData.headers + } + + const { onRequestEnd } = tracker.start(context) + + const getResponseHeaders = () => xhrHeaderStringToObject(this.getAllResponseHeaders()) + + const handleLoad = () => { + onRequestEnd({ + endTime: Date.now(), + status: this.status, + state: 'success', + headers: getResponseHeaders(), + body: this.responseText + }) + } + + const handleError = () => { + onRequestEnd({ + endTime: Date.now(), + state: 'error', + headers: getResponseHeaders(), + body: this.responseText + }) + } + + this.addEventListener('load', handleLoad) + this.addEventListener('error', handleError) + + // it's possible for `this` to be `undefined`, which is not a valid key for a WeakMap + if (this) { + requestHandlers.set(this, { load: handleLoad, error: handleError }) + } + } + + originalSend.apply(this, arguments) + } + + // Store tracker and mark as active + global.__bugsnag_xhr_tracker__ = tracker + + // Restore function for development + if (process.env.NODE_ENV !== 'production') { + tracker._restore = () => { + global.XMLHttpRequest.prototype.open = originalOpen + global.XMLHttpRequest.prototype.send = originalSend + global.XMLHttpRequest.prototype.setRequestHeader = originalSetRequestHeader + delete global.__bugsnag_xhr_tracker__ + } + } + } + + return global.__bugsnag_xhr_tracker__ +} + +module.exports = createXhrTracker diff --git a/packages/request-tracker/package.json b/packages/request-tracker/package.json new file mode 100644 index 0000000000..ff31eb31b7 --- /dev/null +++ b/packages/request-tracker/package.json @@ -0,0 +1,24 @@ +{ + "name": "@bugsnag/request-tracker", + "version": "8.0.0", + "main": "index.js", + "types": "index.d.ts", + "description": "Shared HTTP request tracking for Bugsnag JavaScript plugins", + "homepage": "https://www.bugsnag.com/", + "repository": { + "type": "git", + "url": "https://github.com/bugsnag/bugsnag-js.git" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "*.js", + "lib/" + ], + "author": "Bugsnag", + "license": "MIT", + "dependencies": { + "@bugsnag/core": "^8.0.0" + } +} \ No newline at end of file diff --git a/packages/request-tracker/test/request-tracker.test.js b/packages/request-tracker/test/request-tracker.test.js new file mode 100644 index 0000000000..4521141c22 --- /dev/null +++ b/packages/request-tracker/test/request-tracker.test.js @@ -0,0 +1,456 @@ +const RequestTracker = require('../lib/request-tracker') +const createFetchTracker = require('../lib/fetch-tracker') +const createXhrTracker = require('../lib/xhr-tracker') + +// Mock environment +const mockGlobal = { + fetch: jest.fn() +} + +// Mock XMLHttpRequest +class MockXMLHttpRequest { + constructor () { + this.status = 200 + this.readyState = 0 + this.listeners = {} + } + + open (method, url) { + this.method = method + this.url = url + } + + send (body) { + this.body = body + // Simulate async request + setTimeout(() => { + this.readyState = 4 + this.status = 200 + this._triggerEvent('load') + }, 0) + } + + getAllResponseHeaders () { + return '' + } + + addEventListener (event, listener) { + if (!this.listeners[event]) { + this.listeners[event] = [] + } + this.listeners[event].push(listener) + } + + removeEventListener (event, listener) { + if (this.listeners[event]) { + this.listeners[event] = this.listeners[event].filter(l => l !== listener) + } + } + + _triggerEvent (event, data = {}) { + if (this.listeners[event]) { + this.listeners[event].forEach(listener => listener(data)) + } + } + + _triggerError () { + this._triggerEvent('error') + } +} + +// Mock global with XMLHttpRequest +const mockGlobalWithXHR = { + XMLHttpRequest: MockXMLHttpRequest, + WeakMap: WeakMap +} + +describe('@bugsnag/request-tracker', () => { + beforeEach(() => { + jest.clearAllMocks() + // Clean up singleton instances + delete mockGlobal.__bugsnag_fetch_tracker__ + delete mockGlobalWithXHR.__bugsnag_xhr_tracker__ + + // Reset XMLHttpRequest prototype + mockGlobalWithXHR.XMLHttpRequest.prototype.open = MockXMLHttpRequest.prototype.open + mockGlobalWithXHR.XMLHttpRequest.prototype.send = MockXMLHttpRequest.prototype.send + }) + + describe('RequestTracker', () => { + it('should allow multiple callbacks to register', () => { + const tracker = new RequestTracker() + const callback1 = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + const callback2 = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + + tracker.onStart(callback1) + tracker.onStart(callback2) + + const context = { url: 'https://example.com', method: 'GET', startTime: Date.now() } + tracker.start(context) + + expect(callback1).toHaveBeenCalledWith(context) + expect(callback2).toHaveBeenCalledWith(context) + }) + + it('should handle errors in callbacks gracefully', () => { + const tracker = new RequestTracker() + const errorCallback = jest.fn().mockImplementation(() => { throw new Error('Test error') }) + const goodCallback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + + // Mock console.error to hide expected error output + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + tracker.onStart(errorCallback) + tracker.onStart(goodCallback) + + const context = { url: 'https://example.com', method: 'GET', startTime: Date.now() } + const result = tracker.start(context) + + expect(errorCallback).toHaveBeenCalled() + expect(goodCallback).toHaveBeenCalled() + expect(result.onRequestEnd).toBeDefined() + + // Verify console.error was called with the expected error + expect(consoleSpy).toHaveBeenCalledWith('RequestTracker callback error:', expect.any(Error)) + + // Restore console.error + consoleSpy.mockRestore() + }) + }) + + describe('createFetchTracker', () => { + it('should create singleton tracker instance', () => { + mockGlobal.fetch = jest.fn().mockResolvedValue({ status: 200 }) + + const tracker1 = createFetchTracker(mockGlobal) + const tracker2 = createFetchTracker(mockGlobal) + + expect(tracker1).toBe(tracker2) + expect(mockGlobal.__bugsnag_fetch_tracker__).toBe(tracker1) + }) + + it('should not throw error if fetch is not available', () => { + const globalWithoutFetch = {} + expect(() => createFetchTracker(globalWithoutFetch)).not.toThrow() + }) + + it('should wrap fetch and call callbacks', async () => { + const mockResponse = { status: 200 } + mockGlobal.fetch = jest.fn().mockResolvedValue(mockResponse) + + const tracker = createFetchTracker(mockGlobal) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + await mockGlobal.fetch('https://example.com') + + expect(callback).toHaveBeenCalledWith(expect.objectContaining({ + url: 'https://example.com', + method: 'GET', + type: 'fetch' + })) + }) + + it('should report headers from fetch options', async () => { + const mockResponse = { status: 200 } + mockGlobal.fetch = jest.fn().mockResolvedValue(mockResponse) + + const tracker = createFetchTracker(mockGlobal) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + const headers = { 'x-token': 'super-secret-token' } + await mockGlobal.fetch('https://example.com', { method: 'POST', headers }) + + expect(callback).toHaveBeenCalledTimes(1) + expect(callback).toHaveBeenCalledWith(expect.objectContaining({ + url: 'https://example.com', + method: 'POST', + type: 'fetch', + headers: headers + })) + + callback.mockClear() + + // eslint-disable-next-line no-undef + const headersObj = new Headers() + headersObj.set('x-token', 'super-secret-token') + await mockGlobal.fetch('https://example.com', { method: 'POST', headers: headersObj }) + + expect(callback).toHaveBeenCalledTimes(1) + expect(callback).toHaveBeenCalledWith(expect.objectContaining({ + url: 'https://example.com', + method: 'POST', + type: 'fetch', + headers: { 'x-token': 'super-secret-token' } + })) + }) + }) + + describe('createXhrTracker', () => { + it('should create singleton tracker instance', () => { + const tracker1 = createXhrTracker(mockGlobalWithXHR) + const tracker2 = createXhrTracker(mockGlobalWithXHR) + + expect(tracker1).toBe(tracker2) + expect(mockGlobalWithXHR.__bugsnag_xhr_tracker__).toBe(tracker1) + }) + + it('should return undefined if XMLHttpRequest does not have addEventListener', () => { + const globalWithoutAddEventListener = { + XMLHttpRequest: { + prototype: {} + }, + WeakMap: WeakMap + } + + const tracker = createXhrTracker(globalWithoutAddEventListener) + expect(tracker).toBeUndefined() + }) + + it('should return undefined if WeakMap is not available', () => { + const globalWithoutWeakMap = { + XMLHttpRequest: { + prototype: { + addEventListener: () => {} + } + } + } + + const tracker = createXhrTracker(globalWithoutWeakMap) + expect(tracker).toBeUndefined() + }) + + it('should wrap XMLHttpRequest.prototype.open and send', () => { + const originalOpen = mockGlobalWithXHR.XMLHttpRequest.prototype.open + const originalSend = mockGlobalWithXHR.XMLHttpRequest.prototype.send + + createXhrTracker(mockGlobalWithXHR) + + expect(mockGlobalWithXHR.XMLHttpRequest.prototype.open).not.toBe(originalOpen) + expect(mockGlobalWithXHR.XMLHttpRequest.prototype.send).not.toBe(originalSend) + }) + + it('should track XHR requests and call callbacks', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + xhr.open('POST', 'https://api.example.com/data') + xhr.send('{"test": "data"}') + + // Wait for async execution + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(callback).toHaveBeenCalledWith(expect.objectContaining({ + url: 'https://api.example.com/data', + method: 'POST', + type: 'xmlhttprequest', + body: '{"test": "data"}' + })) + }) + + it('should call onRequestEnd callback on successful request', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const onRequestEnd = jest.fn() + const callback = jest.fn().mockReturnValue({ onRequestEnd }) + tracker.onStart(callback) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + xhr.open('GET', 'https://example.com') + xhr.send() + + // Wait for async execution + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(onRequestEnd).toHaveBeenCalledWith(expect.objectContaining({ + endTime: expect.any(Number), + status: 200, + state: 'success', + headers: {}, + body: undefined + })) + }) + + it('should call onRequestEnd callback on error', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const onRequestEnd = jest.fn() + const callback = jest.fn().mockReturnValue({ onRequestEnd }) + tracker.onStart(callback) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + xhr.open('GET', 'https://example.com') + xhr.send() + + // Trigger error instead of load + xhr._triggerError() + + expect(onRequestEnd).toHaveBeenCalledWith(expect.objectContaining({ + endTime: expect.any(Number), + state: 'error', + headers: {}, + body: undefined + })) + }) + + it('should handle request data when this is undefined in open', () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + // The wrapper should not set anything in WeakMap when this is undefined + // but should still call the original method (which may throw) + const originalOpen = MockXMLHttpRequest.prototype.open + let originalCalled = false + MockXMLHttpRequest.prototype.open = function (method, url) { + originalCalled = true + // Don't call the problematic this.method = method line + } + + mockGlobalWithXHR.XMLHttpRequest.prototype.open.call(undefined, 'GET', 'https://example.com') + + expect(originalCalled).toBe(true) + expect(callback).not.toHaveBeenCalled() // No tracking should happen + + // Restore + MockXMLHttpRequest.prototype.open = originalOpen + }) + + it('should handle request handlers when this is undefined in send', () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + // The wrapper should not set event handlers when this is undefined + // but should still call the original method (which may throw) + const originalSend = MockXMLHttpRequest.prototype.send + let originalCalled = false + MockXMLHttpRequest.prototype.send = function (body) { + originalCalled = true + // Don't call the problematic this.body = body line + } + + mockGlobalWithXHR.XMLHttpRequest.prototype.send.call(undefined) + + expect(originalCalled).toBe(true) + expect(callback).not.toHaveBeenCalled() // No tracking should happen + + // Restore + MockXMLHttpRequest.prototype.send = originalSend + }) + + it('should remove old listeners when reusing XHR instance', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const onRequestEnd = jest.fn() + const callback = jest.fn().mockReturnValue({ onRequestEnd }) + tracker.onStart(callback) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + + // First request + xhr.open('GET', 'https://example.com/1') + xhr.send() + await new Promise(resolve => setTimeout(resolve, 10)) + + // Reset mock to track new calls + onRequestEnd.mockClear() + + // Second request on same instance + xhr.open('GET', 'https://example.com/2') + xhr.send() + await new Promise(resolve => setTimeout(resolve, 10)) + + // Should only get one callback for the second request + expect(onRequestEnd).toHaveBeenCalledTimes(1) + expect(onRequestEnd).toHaveBeenCalledWith(expect.objectContaining({ + state: 'success' + })) + }) + + it('should handle method and url as non-strings gracefully', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const callback = jest.fn().mockReturnValue({ onRequestEnd: jest.fn() }) + tracker.onStart(callback) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + xhr.open(123, { toString: () => 'https://example.com' }) + xhr.send() + + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(callback).toHaveBeenCalledWith(expect.objectContaining({ + url: 'https://example.com', + method: '123', + type: 'xmlhttprequest' + })) + }) + + it('should preserve original functionality when no request data exists', () => { + createXhrTracker(mockGlobalWithXHR) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + // Don't call open, just send + expect(() => { + xhr.send('data') + }).not.toThrow() + }) + + it('should include restore function in development', () => { + const originalEnv = process.env.NODE_ENV + process.env.NODE_ENV = 'development' + + try { + const tracker = createXhrTracker(mockGlobalWithXHR) + expect(typeof tracker._restore).toBe('function') + + // Test restore functionality + tracker._restore() + + expect(mockGlobalWithXHR.XMLHttpRequest.prototype.open).toBe(MockXMLHttpRequest.prototype.open) + expect(mockGlobalWithXHR.XMLHttpRequest.prototype.send).toBe(MockXMLHttpRequest.prototype.send) + expect(mockGlobalWithXHR.__bugsnag_xhr_tracker__).toBeUndefined() + } finally { + process.env.NODE_ENV = originalEnv + } + }) + + it('should not include restore function in production', () => { + const originalEnv = process.env.NODE_ENV + process.env.NODE_ENV = 'production' + + try { + const tracker = createXhrTracker(mockGlobalWithXHR) + expect(tracker._restore).toBeUndefined() + } finally { + process.env.NODE_ENV = originalEnv + } + }) + + it('should handle multiple callbacks with some returning null', async () => { + const tracker = createXhrTracker(mockGlobalWithXHR) + const onRequestEnd1 = jest.fn() + const onRequestEnd2 = jest.fn() + + const callback1 = jest.fn().mockReturnValue({ onRequestEnd: onRequestEnd1 }) + const callback2 = jest.fn().mockReturnValue(null) // This one returns null + const callback3 = jest.fn().mockReturnValue({ onRequestEnd: onRequestEnd2 }) + + tracker.onStart(callback1) + tracker.onStart(callback2) + tracker.onStart(callback3) + + const xhr = new mockGlobalWithXHR.XMLHttpRequest() + xhr.open('GET', 'https://example.com') + xhr.send() + + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(callback1).toHaveBeenCalled() + expect(callback2).toHaveBeenCalled() + expect(callback3).toHaveBeenCalled() + expect(onRequestEnd1).toHaveBeenCalled() + expect(onRequestEnd2).toHaveBeenCalled() + }) + }) +}) diff --git a/scripts/generate-react-native-fixture.js b/scripts/generate-react-native-fixture.js index 43169ccc5e..c4b79085c6 100644 --- a/scripts/generate-react-native-fixture.js +++ b/scripts/generate-react-native-fixture.js @@ -39,7 +39,8 @@ const fixtureDir = resolve(ROOT_DIR, fixturePath, reactNativeVersion) const replacementFilesDir = resolve(ROOT_DIR, 'test/react-native/features/fixtures/replacements/') const INTERNAL_DEPENDENCIES = [ - '@bugsnag/react-native' + '@bugsnag/react-native', + '@bugsnag/request-tracker' ] // make sure we install a compatible versions of peer dependencies diff --git a/test/browser/features/fixtures/handled/webpack3/webpack.config.js b/test/browser/features/fixtures/handled/webpack3/webpack.config.js index b5e65c2cea..a29d6eb672 100644 --- a/test/browser/features/fixtures/handled/webpack3/webpack.config.js +++ b/test/browser/features/fixtures/handled/webpack3/webpack.config.js @@ -14,7 +14,7 @@ module.exports = { filename: '[name].js' }, plugins: [ - new es3ifyPlugin(), - new webpack.optimize.UglifyJsPlugin({ compress: false, mangle: false, ie8: true }) + new es3ifyPlugin() + // UglifyJs plugin disabled due to ES6 compatibility issues ] } diff --git a/test/browser/features/fixtures/handled/webpack4/webpack.config.js b/test/browser/features/fixtures/handled/webpack4/webpack.config.js index 9ca9996749..b1c43daa83 100644 --- a/test/browser/features/fixtures/handled/webpack4/webpack.config.js +++ b/test/browser/features/fixtures/handled/webpack4/webpack.config.js @@ -15,6 +15,6 @@ module.exports = { }, plugins: [ new es3ifyPlugin(), - new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false, ie8: true } }) + new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false } }) ] } diff --git a/test/browser/features/fixtures/http_errors/.babelrc b/test/browser/features/fixtures/http_errors/.babelrc new file mode 100644 index 0000000000..202d425a09 --- /dev/null +++ b/test/browser/features/fixtures/http_errors/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ] +} diff --git a/test/browser/features/fixtures/http_errors/index.html b/test/browser/features/fixtures/http_errors/index.html new file mode 100644 index 0000000000..26ee664537 --- /dev/null +++ b/test/browser/features/fixtures/http_errors/index.html @@ -0,0 +1,11 @@ + + + + + HTTP Errors + + +

+ + + diff --git a/test/browser/features/fixtures/http_errors/package-lock.json b/test/browser/features/fixtures/http_errors/package-lock.json new file mode 100644 index 0000000000..0eb2b4265f --- /dev/null +++ b/test/browser/features/fixtures/http_errors/package-lock.json @@ -0,0 +1,7493 @@ +{ + "name": "bugsnag-js-fixtures-http-errors", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bugsnag-js-fixtures-http-errors", + "dependencies": { + "@babel/core": "^7.18.10", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "babel-loader": "^8.2.5", + "react": "^16.5.0", + "react-dom": "^16.5.0", + "typescript": "^4.1.3", + "uglifyjs-webpack-plugin": "2.0.1", + "webpack": "^4.8.1", + "webpack-cli": "^3.1.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", + "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "license": "MIT", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "license": "MIT", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "license": "ISC" + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.4", + "util": "^0.10.4" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "license": "MIT", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz", + "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-rsa/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "license": "MIT" + }, + "node_modules/cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "license": "ISC", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "license": "MIT", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001757", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "optional": true, + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/chokidar/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cipher-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "license": "ISC", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", + "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cyclist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", + "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "license": "MIT", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", + "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "license": "MIT", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "license": "MIT", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "deprecated": "This module is no longer supported.", + "license": "ISC" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "license": "MIT", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", + "license": "MIT" + }, + "node_modules/import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "license": "MIT", + "dependencies": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "license": "MIT", + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "license": "MIT", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", + "license": "MIT", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "license": "MIT", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nan": { + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.1.tgz", + "integrity": "sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw==", + "license": "MIT", + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "license": "MIT" + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "license": "MIT", + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "license": "MIT", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "license": "MIT", + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-asn1/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "license": "MIT" + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "license": "MIT", + "optional": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pbkdf2/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "license": "MIT" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + }, + "peerDependencies": { + "react": "^16.14.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "license": "ISC", + "optional": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", + "license": "MIT", + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "license": "MIT" + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "license": "MIT", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", + "license": "BSD-3-Clause" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sha.js/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "license": "MIT", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "license": "MIT", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "license": "MIT" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "license": "ISC", + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "license": "BSD-2-Clause", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.6.tgz", + "integrity": "sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==", + "license": "MIT", + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "license": "ISC", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "license": "MIT", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/terser-webpack-plugin/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", + "license": "MIT" + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/to-buffer/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", + "license": "MIT" + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglifyjs-webpack-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-2.0.1.tgz", + "integrity": "sha512-1HhCHkOB6wRCcv7htcz1QRPVbWPEY074RP9vzt/X0LF4xXm9l4YGd0qja7z88abDixQlnVwBjXsTBs+Xsn/eeQ==", + "license": "MIT", + "dependencies": { + "cacache": "^11.2.0", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-js": "^3.0.0", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "engines": { + "node": ">= 6.9.0 <7.0.0 || >= 8.9.0" + }, + "peerDependencies": { + "webpack": "^4.3.0" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "license": "MIT", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/uglifyjs-webpack-plugin/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "license": "MIT", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "license": "MIT", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "license": "MIT" + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "license": "MIT" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "license": "MIT" + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "license": "MIT" + }, + "node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, + "node_modules/watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "license": "MIT", + "optional": true, + "dependencies": { + "chokidar": "^2.1.8" + } + }, + "node_modules/watchpack-chokidar2/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "license": "ISC", + "optional": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "license": "MIT", + "optional": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "license": "MIT", + "optional": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/watchpack-chokidar2/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/webpack": { + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz", + "integrity": "sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "peerDependencies": { + "webpack": "4.x.x" + } + }, + "node_modules/webpack-cli/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/webpack-cli/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "license": "MIT", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/webpack/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "license": "MIT", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "license": "MIT", + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "license": "MIT", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + } + } +} diff --git a/test/browser/features/fixtures/http_errors/package.json b/test/browser/features/fixtures/http_errors/package.json new file mode 100644 index 0000000000..53d5397e2e --- /dev/null +++ b/test/browser/features/fixtures/http_errors/package.json @@ -0,0 +1,20 @@ +{ + "name": "bugsnag-js-fixtures-http-errors", + "private": true, + "scripts": { + "build": "webpack" + }, + "dependencies": { + "@babel/core": "^7.18.10", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "babel-loader": "^8.2.5", + "react": "^16.5.0", + "react-dom": "^16.5.0", + "typescript": "^4.1.3", + "uglifyjs-webpack-plugin": "2.0.1", + "webpack": "^4.8.1", + "webpack-cli": "^3.1.2" + } +} diff --git a/test/browser/features/fixtures/http_errors/src/app.tsx b/test/browser/features/fixtures/http_errors/src/app.tsx new file mode 100644 index 0000000000..ba275d225f --- /dev/null +++ b/test/browser/features/fixtures/http_errors/src/app.tsx @@ -0,0 +1,69 @@ +import Bugsnag from '@bugsnag/browser' +import ReactDOM from 'react-dom' +import React, { useEffect } from 'react' +import { apiKey, endpoints, plugins, REFLECT_ENDPOINT } from './lib/config' + +Bugsnag.start({ apiKey, endpoints, plugins, redactedKeys: ['X-Token', 'userId'] }) + +function xhrGet () { + const xhr = new XMLHttpRequest() + xhr.open('GET', `${REFLECT_ENDPOINT}?status=404&userId=12345`) + xhr.setRequestHeader('X-Token', 'super-secret-token') + xhr.setRequestHeader('X-Test-Value', 'one-two') + xhr.setRequestHeader('X-Test-Value', '-three-four') + xhr.send() +} + +function xhrPost () { + const xhr = new XMLHttpRequest() + xhr.open('POST', `${REFLECT_ENDPOINT}?status=403&userId=12345`) + xhr.setRequestHeader('X-Token', 'super-secret-token') + xhr.send('this is the request body') +} + +function fetchGet () { + fetch(`${REFLECT_ENDPOINT}?status=401&userId=12345`, { + headers: { 'x-token': 'super-secret-token' } + }) +} + +function fetchPost () { + fetch(`${REFLECT_ENDPOINT}?status=408&userId=12345`, { + method: 'POST', + body: 'this is the request body', + headers: { 'x-token': 'super-secret-token' } + }) +} + +function App () { + useEffect(() => { + const params = new URLSearchParams(window.location.search) + + switch(params.get('request')) { + case 'xhr': + case 'xhr-get': + xhrGet() + break + case 'xhr-post': + xhrPost() + break + case 'fetch': + case 'fetch-get': + fetchGet() + break + case 'fetch-post': + fetchPost() + break + default: + } + + }, []) + + return ( +
+

HTTP Errors

+
+ ) +} + +ReactDOM.render(, document.getElementById('root')) diff --git a/test/browser/features/fixtures/http_errors/src/lib/config.ts b/test/browser/features/fixtures/http_errors/src/lib/config.ts new file mode 100644 index 0000000000..c613678562 --- /dev/null +++ b/test/browser/features/fixtures/http_errors/src/lib/config.ts @@ -0,0 +1,19 @@ +import BugsnagPluginNetworkInstrumentation from '@bugsnag/plugin-network-instrumentation' + +function getQueryParam (key: string): string { + const match = window.location.search.match(new RegExp(key + '=([^&]+)')) + return match ? decodeURIComponent(match[1]) : '' +} + +export const apiKey = getQueryParam('API_KEY') + +export const REFLECT_ENDPOINT = getQueryParam('REFLECT') + +export const endpoints = { + notify: getQueryParam('NOTIFY'), + sessions: getQueryParam('SESSIONS') +} + +export const plugins = [ + BugsnagPluginNetworkInstrumentation() +] diff --git a/test/browser/features/fixtures/http_errors/tsconfig.json b/test/browser/features/fixtures/http_errors/tsconfig.json new file mode 100644 index 0000000000..e72b836a2a --- /dev/null +++ b/test/browser/features/fixtures/http_errors/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "jsx": "react", + "strict": false, + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/test/browser/features/fixtures/http_errors/webpack.config.js b/test/browser/features/fixtures/http_errors/webpack.config.js new file mode 100644 index 0000000000..ed9a539ef8 --- /dev/null +++ b/test/browser/features/fixtures/http_errors/webpack.config.js @@ -0,0 +1,37 @@ +const path = require('path') +const UglifyJsPlugin = require('uglifyjs-webpack-plugin') + +module.exports = { + entry: { app: './src/app.tsx' }, + mode: 'production', + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].js', + libraryTarget: 'umd' + }, + resolve: { + extensions: ['.js', '.ts', '.tsx'], + modules: ['node_modules', path.resolve(__dirname, 'src')], + }, + module: { + rules: [ + { + test: /\.tsx?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: [ + ['@babel/preset-env', { modules: 'commonjs' }], + '@babel/preset-react', + '@babel/preset-typescript' + ] + } + } + } + ] + }, + plugins: [ + new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false } }) + ] +} diff --git a/test/browser/features/fixtures/plugin_react/webpack4/webpack.config.js b/test/browser/features/fixtures/plugin_react/webpack4/webpack.config.js index 33bf3ce554..9f12973883 100644 --- a/test/browser/features/fixtures/plugin_react/webpack4/webpack.config.js +++ b/test/browser/features/fixtures/plugin_react/webpack4/webpack.config.js @@ -24,6 +24,6 @@ module.exports = { ] }, plugins: [ - new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false, ie8: true } }) + new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false } }) ] } diff --git a/test/browser/features/fixtures/plugin_vue/webpack4/webpack.config.js b/test/browser/features/fixtures/plugin_vue/webpack4/webpack.config.js index f28a80dd36..c2ff1469ca 100644 --- a/test/browser/features/fixtures/plugin_vue/webpack4/webpack.config.js +++ b/test/browser/features/fixtures/plugin_vue/webpack4/webpack.config.js @@ -22,6 +22,6 @@ module.exports = { ] }, plugins: [ - new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false, ie8: true } }) + new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: false, mangle: false } }) ] } diff --git a/test/browser/features/http_errors.feature b/test/browser/features/http_errors.feature new file mode 100644 index 0000000000..fef4138ee3 --- /dev/null +++ b/test/browser/features/http_errors.feature @@ -0,0 +1,127 @@ +@http_errors @requires_set @skip_safari_10 @skip_chrome_43 @skip_ie_11 +Feature: HTTP Errors + + HTTP errors plugin reports network request failures, including those made using fetch, and xml http requests. + + @requires_fetch + Scenario: Fetch Request - GET + When I navigate to the test URL "/http_errors?request=fetch" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + + And I define "expected.context" as "GET " + And I define "expected.exception.message" as "401: /reflect?status=401&userId=[REDACTED]" + And I define "expected.request.url" as "/reflect?status=401&userId=[REDACTED]" + + And the exception "errorClass" equals "HTTPError" + And the error payload field "events.0.exceptions.0.message" equals the stored value "expected.exception.message" + And the event "severity" equals "error" + And the event "unhandled" is true + And the event "severityReason.type" equals "httpError" + And the error payload field "events.0.context" equals the stored value "expected.context" + + And the error payload field "events.0.request.url" equals the stored value "expected.request.url" + And the event "request.httpMethod" equals "GET" + And the event "request.params.status" equals "401" + And the event "request.params.userId" equals "[REDACTED]" + And the event "request.headers.x-token" equals "[REDACTED]" + And the event "request.body" is null + And the event "request.bodyLength" is null + + And the event "response.statusCode" equals 401 + And the event "response.headers.content-length" equals "37" + # Response body is not captured for fetch requests + And the event "response.body" is null + And the event "response.bodyLength" is null + + Scenario: Fetch Request - POST + When I navigate to the test URL "/http_errors?request=fetch-post" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + + And I define "expected.context" as "POST " + And I define "expected.exception.message" as "408: /reflect?status=408&userId=[REDACTED]" + And I define "expected.request.url" as "/reflect?status=408&userId=[REDACTED]" + + And the exception "errorClass" equals "HTTPError" + And the error payload field "events.0.exceptions.0.message" equals the stored value "expected.exception.message" + And the event "severity" equals "error" + And the event "unhandled" is true + And the event "severityReason.type" equals "httpError" + And the error payload field "events.0.context" equals the stored value "expected.context" + + And the error payload field "events.0.request.url" equals the stored value "expected.request.url" + And the event "request.httpMethod" equals "POST" + And the event "request.params.status" equals "408" + And the event "request.params.userId" equals "[REDACTED]" + And the event "request.headers.x-token" equals "[REDACTED]" + And the event "request.body" equals "this is the request body" + And the event "request.bodyLength" equals 24 + + And the event "response.statusCode" equals 408 + And the event "response.headers.content-length" equals "37" + + # Response body is not captured for fetch requests + And the event "response.body" is null + And the event "response.bodyLength" is null + + @requires_xml_http_request + Scenario: XHR - GET + When I navigate to the test URL "/http_errors?request=xhr" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + + And I define "expected.context" as "GET " + And I define "expected.exception.message" as "404: /reflect?status=404&userId=[REDACTED]" + And I define "expected.request.url" as "/reflect?status=404&userId=[REDACTED]" + + And the exception "errorClass" equals "HTTPError" + And the error payload field "events.0.exceptions.0.message" equals the stored value "expected.exception.message" + And the event "severity" equals "error" + And the event "unhandled" is true + And the event "severityReason.type" equals "httpError" + And the error payload field "events.0.context" equals the stored value "expected.context" + + And the error payload field "events.0.request.url" equals the stored value "expected.request.url" + And the event "request.httpMethod" equals "GET" + And the event "request.headers.X-Token" equals "[REDACTED]" + And the event "request.headers.X-Test-Value" equals "one-two-three-four" + And the event "request.params.status" equals "404" + And the event "request.params.userId" equals "[REDACTED]" + And the event "request.body" is null + And the event "request.bodyLength" is null + + And the event "response.statusCode" equals 404 + And the event "response.headers.content-length" equals "37" + And the event "response.body" equals "Returned status 404 after waiting ms" + And the event "response.bodyLength" equals 37 + + @requires_xml_http_request + Scenario: XHR - POST + When I navigate to the test URL "/http_errors?request=xhr-post" + And I wait to receive an error + Then the error is a valid browser payload for the error reporting API + + And I define "expected.context" as "POST " + And I define "expected.exception.message" as "403: /reflect?status=403&userId=[REDACTED]" + And I define "expected.request.url" as "/reflect?status=403&userId=[REDACTED]" + + And the exception "errorClass" equals "HTTPError" + And the error payload field "events.0.exceptions.0.message" equals the stored value "expected.exception.message" + And the event "severity" equals "error" + And the event "unhandled" is true + And the event "severityReason.type" equals "httpError" + And the error payload field "events.0.context" equals the stored value "expected.context" + + And the error payload field "events.0.request.url" equals the stored value "expected.request.url" + And the event "request.httpMethod" equals "POST" + And the event "request.headers.X-Token" equals "[REDACTED]" + And the event "request.params.status" equals "403" + And the event "request.params.userId" equals "[REDACTED]" + And the event "request.body" equals "this is the request body" + And the event "request.bodyLength" equals 24 + + And the event "response.statusCode" equals 403 + And the event "response.headers.content-length" equals "37" + And the event "response.body" equals "Returned status 403 after waiting ms" + And the event "response.bodyLength" equals 37 diff --git a/test/browser/features/steps/browser_steps.rb b/test/browser/features/steps/browser_steps.rb index 81d017ed69..e0edca751c 100644 --- a/test/browser/features/steps/browser_steps.rb +++ b/test/browser/features/steps/browser_steps.rb @@ -53,3 +53,15 @@ "#{expected_data} was not found in any of the current payloads") end end + +# construct a value with placeholder using <> syntax and store it for later use +# the placeholders are replaced with existing stored values, i.e. browser.hostname +When('I define {string} as {string}') do |key, value| + resolved_value = value.gsub(/<([^>]+)>/) do + placeholder = $1 + stored_value = Maze::Store.values[placeholder] + raise "No stored value found for placeholder '#{placeholder}'" unless stored_value + stored_value + end + Maze::Store.values[key] = resolved_value +end diff --git a/test/browser/features/support/env.rb b/test/browser/features/support/env.rb index 23682e643c..0bcb51d5cd 100644 --- a/test/browser/features/support/env.rb +++ b/test/browser/features/support/env.rb @@ -7,7 +7,7 @@ def get_test_url(path) if Maze.config.aws_public_ip maze_runner = Maze.public_address else - maze_runner = "#{ENV['HOST']}:9339" + maze_runner = "#{ENV['HOST'] || 'localhost'}:9339" end protocol = Maze.config.https ? 'https' : 'http' @@ -20,6 +20,10 @@ def get_test_url(path) uri = URI("#{protocol}://#{maze_runner}/docs#{path}") + # store hostname and url for later use + Maze::Store.values["browser.hostname"] = maze_runner + Maze::Store.values["browser.url"] = "#{protocol}://#{maze_runner}" + if uri.query uri.query += "&#{config_query_string}" else diff --git a/tsconfig.json b/tsconfig.json index 08c8cd0543..d61484fb74 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -96,7 +96,9 @@ "packages/plugin-node-uncaught-exception", "packages/plugin-console-breadcrumbs", "packages/plugin-browser-session", - "packages/browser" + "packages/browser", + "packages/request-tracker", + "packages/plugin-network-instrumentation" ], "exclude": [ "packages/react-native/src/NativeBugsnag.ts" From 0dc1e6843d0183cb5d582327411515ed5e8296df Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Tue, 20 Jan 2026 11:11:40 +0000 Subject: [PATCH 43/43] docs: :memo: update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1d6c63a99..15e1c57cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [Unreleased] +## [8.8.0] - 2026-01-20 This release adds support for notitfying failed network requests using the new `plugin-network-instrumentation` package