diff --git a/.github/workflows/actions_release.yml b/.github/workflows/actions_release.yml new file mode 100644 index 0000000..2a60975 --- /dev/null +++ b/.github/workflows/actions_release.yml @@ -0,0 +1,27 @@ +name: Release GitHub Actions + +on: + workflow_dispatch: + inputs: + tag: + description: "Tag for the release" + required: true + node_version: + description: "Node.js version to use" + required: false + default: "24" + +permissions: + contents: read + +jobs: + release: + permissions: + actions: read + id-token: write + contents: write + + uses: step-security/reusable-workflows/.github/workflows/actions_release.yaml@v1 + with: + tag: "${{ github.event.inputs.tag }}" + node_version: ${{ inputs.node_version || '24' }} \ No newline at end of file diff --git a/.github/workflows/audit_package.yml b/.github/workflows/audit_package.yml new file mode 100644 index 0000000..7a38506 --- /dev/null +++ b/.github/workflows/audit_package.yml @@ -0,0 +1,32 @@ +name: NPM Audit Fix Run + +on: + workflow_dispatch: + inputs: + force: + description: "Use --force flag for npm audit fix?" + required: true + type: boolean + base_branch: + description: "Specify a base branch" + required: false + default: "main" + node_version: + description: "Node.js version to use" + required: false + default: "24" + schedule: + - cron: "0 0 * * 1" + +jobs: + audit-fix: + uses: step-security/reusable-workflows/.github/workflows/audit_fix.yml@v1 + with: + force: ${{ inputs.force || false }} + base_branch: ${{ inputs.base_branch || 'main' }} + node_version: ${{ inputs.node_version || '24' }} +permissions: + contents: write + pull-requests: write + packages: read + issues: write diff --git a/.github/workflows/auto_cherry_pick.yml b/.github/workflows/auto_cherry_pick.yml new file mode 100644 index 0000000..be4743b --- /dev/null +++ b/.github/workflows/auto_cherry_pick.yml @@ -0,0 +1,42 @@ +name: Auto Cherry-Pick from Upstream + +on: + workflow_run: + workflows: ["Release GitHub Actions"] + types: + - completed + + workflow_dispatch: + inputs: + base_branch: + description: "Base branch to create the PR against" + required: true + default: "main" + mode: + description: "Run mode: cherry-pick or verify" + required: false + default: "cherry-pick" + node_version: + description: "Node.js version to use" + required: false + default: "24" + + pull_request: + types: [opened, synchronize, labeled] + +permissions: + contents: write + pull-requests: write + packages: read + issues: write + +jobs: + cherry-pick: + if: (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || github.event_name == 'workflow_dispatch' || contains(fromJson(toJson(github.event.pull_request.labels)).*.name, 'review-required') + uses: step-security/reusable-workflows/.github/workflows/auto_cherry_pick.yaml@v1 + with: + original-owner: "shivammathur" + repo-name: "setup-php" + base_branch: ${{ inputs.base_branch || 'main' }} + mode: ${{ github.event_name == 'pull_request' && 'verify' || inputs.mode || 'cherry-pick' }} + node_version: ${{ inputs.node_version || '24' }} \ No newline at end of file diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml new file mode 100644 index 0000000..0995b2b --- /dev/null +++ b/.github/workflows/node.yml @@ -0,0 +1,47 @@ +name: Node workflow +on: + pull_request: + branches: + - main + paths-ignore: + - '**.md' + - 'examples/**' + push: + branches: + - main + paths-ignore: + - '**.md' + - 'examples/**' +permissions: + contents: read + +jobs: + run: + name: Run + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: ${{ github.actor == 'dependabot[bot]' && fromJson('["ubuntu-latest"]') || fromJson('["ubuntu-latest", "windows-latest", "macos-latest"]') }} + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 2 + + - name: Setup Node.js 24.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + + - name: Install dependencies + run: npm install + + - name: Prettier Format Check + run: npm run format-check + + - name: ESLint Check + run: npm run lint + + - name: Run tests + run: npm test diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..e8dc057 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,89 @@ +name: Main workflow +on: + workflow_dispatch: + pull_request: + branches: + - main + paths-ignore: + - '**.md' + - 'examples/**' + push: + branches: + - main + paths-ignore: + - '**.md' + - 'examples/**' +permissions: + contents: read +env: + default-php-version: '8.2' +jobs: + run: + name: Run + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: ${{ github.actor == 'dependabot[bot]' && fromJson('["ubuntu-24.04"]') || fromJson('["ubuntu-24.04", "ubuntu-22.04", "windows-2022", "macos-15-intel"]') }} + php-versions: ${{ github.actor == 'dependabot[bot]' && fromJson('["8.6"]') || fromJson('["5.3", "5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6"]') }} + include: + - operating-system: ubuntu-24.04 + php-versions: '' + php-version-file: 'php-version-file' + env: + extensions: xml, opcache, xdebug, pcov, gd + key: cache-v5 + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup cache environment + id: cache-env + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php-versions || env.default-php-version }} + extensions: ${{ env.extensions }} + key: ${{ env.key }} + + - name: Cache extensions + uses: actions/cache@v5 + with: + path: ${{ steps.cache-env.outputs.dir }} + key: ${{ steps.cache-env.outputs.key }} + restore-keys: ${{ steps.cache-env.outputs.key }} + + - name: Stage php-version-file + if: ${{ matrix.php-version-file == 'php-version-file' }} + run: | + echo ${{ env.default-php-version }} > php-version-file + + - name: Setup PHP with extensions and custom config + run: node dist/index.js + env: + php-version: ${{ matrix.php-versions }} + php-version-file: ${{ matrix.php-version-file }} + extensions: ${{ env.extensions }} + ini-values: post_max_size=256M, short_open_tag=On, date.timezone=Asia/Kolkata + + - name: Testing PHP version + run: | + php -v + php -r "if(strpos(phpversion(), '${{ matrix.php-versions || env.default-php-version }}') === false) {throw new Exception('Wrong PHP version Installed');}" + + - name: Testing Composer version + run: | + composer -V + php -r "if(strpos(@exec('composer -V'), 'Composer version') === false) {throw new Exception('Composer not found');}" + - name: Testing Extensions + run: | + php -m + php -r "if(! extension_loaded('gd')) {throw new Exception('gd not found');}" + php -r "if(! extension_loaded('xml')) {throw new Exception('xml not found');}" + php -r "if(! extension_loaded('Xdebug')) {throw new Exception('Xdebug not found');}" + php -r "if(phpversion()>=7.1 && ! extension_loaded('pcov')) {throw new Exception('PCOV not found');}" + - name: Testing ini values + run: | + php -r "if(ini_get('memory_limit')!='-1') {throw new Exception('memory_limit not disabled');}" + php -r "if(ini_get('post_max_size')!='256M') {throw new Exception('post_max_size not added');}" + php -r "if(ini_get('short_open_tag')!=1) {throw new Exception('short_open_tag not added');}" + php -r "if(ini_get('date.timezone')!='Asia/Kolkata') {throw new Exception('date.timezone not added');}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0010af --- /dev/null +++ b/.gitignore @@ -0,0 +1,93 @@ +# Explicitly not ignoring node_modules so that they are included in package downloaded by runner +node_modules/ +__tests__/runner/* +lib/ + +# Rest of the file pulled from https://github.com/github/gitignore/blob/main/Node.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ \ No newline at end of file diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..cabf43b --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24 \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..78c50d2 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +min-release-age=3 \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..966db1e --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,12 @@ +{ + "arrowParens": "avoid", + "bracketSpacing": false, + "endOfLine": "auto", + "parser": "typescript", + "printWidth": 80, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6f5523c --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) shivammathur and contributors +Copyright (c) 2026 Step Security, Inc. + +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/README.md b/README.md index 66bffd5..d6bee3d 100644 --- a/README.md +++ b/README.md @@ -1 +1,1028 @@ -# setup-php \ No newline at end of file +[![StepSecurity Maintained Action](https://raw.githubusercontent.com/step-security/maintained-actions-assets/main/assets/maintained-action-banner.png)](https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions) + + +

Setup PHP in GitHub Actions

+ +

+ GitHub Actions status + LICENSE + PHP Versions Supported +

+ +Setup PHP with required extensions, php.ini configuration, code-coverage support and various tools like composer in [GitHub Actions](https://github.com/features/actions "GitHub Actions"). This action gives you a cross-platform interface to set up the PHP environment you need to test your application. Refer to [Usage](#memo-usage "How to use this") section and [examples](#examples "Examples of use") to see how to use this. + +## Contents + +- [OS/Platform Support](#cloud-osplatform-support) + - [GitHub-Hosted Runners](#github-hosted-runners) + - [Self-Hosted Runners](#self-hosted-runners) +- [PHP Support](#tada-php-support) +- [PHP Extension Support](#heavy_plus_sign-php-extension-support) +- [Tools Support](#wrench-tools-support) +- [Coverage Support](#signal_strength-coverage-support) + - [Xdebug](#xdebug) + - [PCOV](#pcov) + - [Disable Coverage](#disable-coverage) +- [Usage](#memo-usage) + - [Inputs](#inputs) + - [Outputs](#outputs) + - [Flags](#flags) + - [Basic Setup](#basic-setup) + - [Matrix Setup](#matrix-setup) + - [Nightly Build Setup](#nightly-build-setup) + - [Debug Build Setup](#debug-build-setup) + - [Thread Safe Setup](#thread-safe-setup) + - [Force Update Setup](#force-update-setup) + - [Multi-Arch Setup](#multi-arch-setup) + - [Self Hosted Setup](#self-hosted-setup) + - [Local Testing Setup](#local-testing-setup) + - [JIT Configuration](#jit-configuration) + - [Cache Extensions](#cache-extensions) + - [Cache Composer Dependencies](#cache-composer-dependencies) + - [GitHub Composer Authentication](#github-composer-authentication) + - [Private Packagist Authentication](#private-packagist-authentication) + - [Manual Composer Authentication](#manual-composer-authentication) + - [Inline PHP Scripts](#inline-php-scripts) + - [Problem Matchers](#problem-matchers) + - [Examples](#examples) +- [Versioning](#bookmark-versioning) +- [License](#scroll-license) +- [Further Reading](#bookmark_tabs-further-reading) + +## :cloud: OS/Platform Support + +Both `GitHub-hosted` and `self-hosted` runners are supported by `setup-php` on the following OS/Platforms. + +### GitHub-Hosted Runners + +| Virtual environment | Arch | YAML workflow label | Pre-installed PHP | +|---------------------|---------|------------------------------------|-------------------| +| Ubuntu 24.04 | x86_64 | `ubuntu-latest` or `ubuntu-24.04` | `PHP 8.3` | +| Ubuntu 22.04 | x86_64 | `ubuntu-22.04` | `PHP 8.1` | +| Ubuntu 24.04 | aarch64 | `ubuntu-24.04-arm` | `PHP 8.3` | +| Ubuntu 22.04 | aarch64 | `ubuntu-22.04-arm` | `PHP 8.1` | +| Windows Server 2025 | x64 | `windows-2025` | `PHP 8.5` | +| Windows Server 2022 | x64 | `windows-latest` or `windows-2022` | `PHP 8.5` | +| macOS Tahoe 26.x | arm64 | `macos-26` | - | +| macOS Sequoia 15.x | arm64 | `macos-latest` or `macos-15` | - | +| macOS Sonoma 14.x | arm64 | `macos-14` | - | +| macOS Tahoe 26.x | x86_64 | `macos-26-intel` | `PHP 8.5` | +| macOS Sequoia 15.x | x86_64 | `macos-15-intel` | `PHP 8.5` | + +### Self-Hosted Runners + +| Host OS/Virtual environment | YAML workflow label | +|----------------------------------|----------------------------| +| Ubuntu 24.04 | `self-hosted` or `Linux` | +| Ubuntu 22.04 | `self-hosted` or `Linux` | +| Debian 13 | `self-hosted` or `Linux` | +| Debian 12 | `self-hosted` or `Linux` | +| Debian 11 | `self-hosted` or `Linux` | +| Windows 7 and newer | `self-hosted` or `Windows` | +| Windows Server 2012 R2 and newer | `self-hosted` or `Windows` | +| macOS Tahoe 26.x x86_64/arm64 | `self-hosted` or `macOS` | +| macOS Sequoia 15.x x86_64/arm64 | `self-hosted` or `macOS` | +| macOS Sonoma 14.x x86_64/arm64 | `self-hosted` or `macOS` | + +- Refer to the [self-hosted setup](#self-hosted-setup) to use the action on self-hosted runners. +- Operating systems based on the above Ubuntu and Debian versions are also supported on best effort basis. +- If the requested PHP version is pre-installed, `setup-php` switches to it, otherwise it installs the PHP version. + +## :tada: PHP Support + +On all supported OS/Platforms, the following PHP versions can be set up as per the runner. + +- PHP 5.3 to PHP 8.6 on GitHub-hosted runners, except for macOS ARM64 runners (macos-14). +- PHP 5.6 to PHP 8.6 on GitHub-hosted macOS ARM64 runners (macos-14). +- PHP 5.6 to PHP 8.6 on self-hosted runners. + +| PHP Version | Stability | Release Support | Runner Support | +|-------------|-----------|-----------------------|--------------------------------| +| `5.3` | `Stable` | `End of life` | `GitHub-hosted` | +| `5.4` | `Stable` | `End of life` | `GitHub-hosted` | +| `5.5` | `Stable` | `End of life` | `GitHub-hosted` | +| `5.6` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `7.0` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `7.1` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `7.2` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `7.3` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `7.4` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `8.0` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `8.1` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` | +| `8.2` | `Stable` | `Security fixes only` | `GitHub-hosted`, `self-hosted` | +| `8.3` | `Stable` | `Security fixes only` | `GitHub-hosted`, `self-hosted` | +| `8.4` | `Stable` | `Active` | `GitHub-hosted`, `self-hosted` | +| `8.5` | `Stable` | `Active` | `GitHub-hosted`, `self-hosted` | +| `8.6` | `Nightly` | `In development` | `GitHub-hosted`, `self-hosted` | + + +> [!Note] +> - Specifying `8.6` in `php-version` input installs a nightly build of `PHP 8.6.0-dev` from the master branch of PHP. See [nightly build setup](#nightly-build-setup) for more information. +> - To use JIT on `PHP 8.0` and above, refer to the [JIT configuration](#jit-configuration) section. + +## :heavy_plus_sign: PHP Extension Support + +PHP extensions can be set up using the `extensions` input. It accepts a `string` in csv-format. + +- On `Ubuntu`, extensions which are available as a package, available on `PECL` or a git repository can be set up. + +```yaml +- name: Setup PHP with PECL extension + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: imagick, redis +``` + +- On `Windows`, extensions available on `PECL` which have the `DLL` binary can be set up. + +- On `macOS`, extensions available on `PECL` or a git repository can be set up. + +- On `Ubuntu` and `macOS` to compile and install an extension from a git repository follow this [guide](https://github.com/step-security/setup-php/wiki/Add-extension-from-source "Guide to compile and install PHP extensions in setup-php"). + +- Extensions installed along with PHP if specified are enabled. + +- Specific versions of extensions available on `PECL` can be set up by suffixing the extension's name with the version. This is useful for installing old versions of extensions which support end of life PHP versions. + +```yaml +- name: Setup PHP with specific version of PECL extension + uses: step-security/setup-php@v2 + with: + php-version: '5.4' + extensions: swoole-1.9.3 +``` + +- Extensions with pre-release versions available on `PECL` can be set up by suffixing the extension's name with its state i.e `alpha`, `beta`, `devel` or `snapshot`. + +```yaml +- name: Setup PHP with pre-release PECL extension + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: xdebug-beta +``` + +- On `Ubuntu` and `macOS` to compile and install an extension from PECL with libraries or custom configuration follow this [guide](https://github.com/step-security/setup-php/wiki/Add-extension-from-PECL-with-libraries-and-custom-configuration "Guide to compile and install PHP extensions using PECL with libraries and custom configuration in setup-php"). + +- Shared extensions can be disabled by prefixing them with a `:`. All extensions depending on the specified extension will also be disabled. + +```yaml +- name: Setup PHP and disable opcache + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: :mbstring +``` + +- All shared extensions can be disabled by specifying `none`. When `none` is specified along with other extensions, it is hoisted to the start of the input. So, all the shared extensions will be disabled first, then rest of the extensions in the input will be processed. + +This disables all core and third-party shared extensions and thus, can break some tools that need them. Required extensions are enabled again when the tools are set up on a best-effort basis. So it is recommended to add the extensions required for your tools after `none` in the `extensions` input to avoid any issues. + +```yaml +- name: Setup PHP without any shared extensions except mbstring + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: none, mbstring +``` + +- Extension `intl` can be set up with specific `ICU` version for `PHP 5.6` and above in `Ubuntu` workflows by suffixing `intl` with the `ICU` version. `ICU 50.2` and newer versions are supported for PHP 8.4 and lower, `ICU 57.2` and newer versions are supported for PHP 8.5 and above. Refer to [`ICU builds`](https://github.com/shivammathur/icu-intl#icu4c-builds) for the specific versions supported. + +```yaml +- name: Setup PHP with intl + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: intl-77.1 +``` + +- Extensions loaded by default after `setup-php` runs can be found on the [wiki](https://github.com/step-security/setup-php/wiki). + +- These extensions have custom support: + - `cubrid` and `pdo_cubrid` on `Ubuntu`. + - `event`, `gearman`, `geos` and `relay` on `Ubuntu` and `macOS`. + - `blackfire`, `couchbase`, `ibm_db2`, `ioncube`, `oci8`, `pdo_firebird`, `pdo_ibm`, `pdo_oci`, `pecl_http`, `phalcon3`, `phalcon4`, `phalcon5`, and `zephir_parser` on all supported OS. + +- By default, extensions which cannot be added or disabled gracefully leave an error message in the logs, the execution is not interrupted. To change this behaviour you can set `fail-fast` flag to `true`. + +```yaml +- name: Setup PHP with fail-fast + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: oci8 + env: + fail-fast: true +``` + +## :wrench: Tools Support + +These tools can be set up globally using the `tools` input. It accepts a string in csv-format. + +[`backward-compatibility-check`], [`behat`], [`blackfire`], [`blackfire-player`], [`box`], [`castor`], [`churn`], [`codeception`], [`composer`], [`composer-dependency-analyser`], [`composer-normalize`], [`composer-prefetcher`], [`composer-require-checker`], [`composer-unused`], [`cs2pr`], [`deployer`], [`ecs`], [`flex`], [`grpc_php_plugin`], [`infection`], [`mago`], [`name-collision-detector`], [`parallel-lint`], [`pecl`], [`phan`], [`phing`], [`phinx`], [`phive`], [`php-config`], [`php-cs-fixer`], [`php-scoper`], [`phpcbf`], [`phpcpd`], [`phpcs`], [`phpdoc`] or [`phpDocumentor`], [`phpize`], [`phplint`], [`phpmd`], [`phpspec`], [`phpstan`], [`phpunit`], [`phpunit-bridge`], [`phpunit-polyfills`], [`pie`], [`pint`], [`prestissimo`], [`protoc`], [`psalm`], [`rector`], [`symfony`] or [`symfony-cli`], [`vapor`] or [`vapor-cli`], [`wp`] or [`wp-cli`] + +```yaml +- name: Setup PHP with tools + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: php-cs-fixer, phpunit +``` + +- In addition to above tools any composer tool or package can also be set up globally by specifying it as `vendor/package` matching the listing on Packagist. This format accepts the same [version constraints](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints "Composer version constraints") as `composer`. + +```yaml +- name: Setup PHP with tools + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: vimeo/psalm +``` + +- To set up a particular version of a tool, specify it in the form `tool:version`. + + Version can be in the following format: + - Semver. For example `tool:1.2.3` or `tool:1.2.3-beta1`. + - Major version. For example `tool:1` or `tool:1.x`. + - Major and minor version. For example `tool:1.2` or `tool:1.2.x`. + + When you specify just the major version or the version in `major.minor` format, the latest patch version matching the input will be setup. + +- The latest stable version of `composer` is set up by default. You can set up the required `composer` version by specifying the major version `v1` or `v2`, or the version in `major.minor` or `semver` format. Additionally, for composer `snapshot` and `preview` can also be specified to set up the respective releases. + +```yaml +- name: Setup PHP with composer v2 + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: composer:v1 +``` + +- If you do not use composer in your workflow, you can specify `tools: none` to skip it. + +```yaml +- name: Setup PHP without composer + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: none +``` + +- Tools `pear`, `pecl`, `phpize` and `php-config` are set up by default for all supported PHP versions on Linux and macOS. + +- The latest version of `blackfire` cli is set up when `blackfire` is specified in tools input. Please refer to the [official documentation](https://blackfire.io/docs/integrations/ci/github-actions "Blackfire.io documentation for GitHub Actions") for using `blackfire` with GitHub Actions. + +- Tools `prestissimo` and `composer-prefetcher` will be skipped unless `composer:v1` is also specified in tools input. It is recommended to drop `prestissimo` and use `composer v2`. + +- By default, except `composer` tools which cannot be set up gracefully leave an error message in the logs, the execution is not interrupted. To change this behaviour you can set `fail-fast` flag to `true`. + +```yaml +- name: Setup PHP with fail-fast + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: deployer + env: + fail-fast: true +``` + +- By default, `composer` blocks all its plugins. If you are using the `tools` input to install a composer plugin it will be added to the allow list, alternatively if your dependencies have composer plugins, you can allow them by setting `COMPOSER_ALLOW_PLUGINS` that accepts a csv string of plugin names. + +```yaml +- name: Setup PHP with fail-fast + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + COMPOSER_ALLOW_PLUGINS: composer/installers, composer/satis +``` + +> [!NOTE] +> - Input `tools` is useful to set up tools which are only used in CI workflows, thus keeping your `composer.json` tidy. +> - If you do not want to use all your dev-dependencies in workflow, you can run composer with `--no-dev` and install required tools using `tools` input to speed up your workflow. +> - By default, `COMPOSER_NO_INTERACTION` is set to `1` and `COMPOSER_PROCESS_TIMEOUT` is set to `0`. In effect, this means that Composer commands in your scripts do not need to specify `--no-interaction`. +> - Also, `COMPOSER_NO_AUDIT` is set to `1`. So if you want to audit your dependencies for security vulnerabilities, it is recommended to add a `composer audit` step before you install them. +> - If you want to set a different `COMPOSER_PROCESS_TIMEOUT`, you can set it in your workflow file using the `env` keyword. + +```yaml +- name: Setup PHP with composer and custom process timeout + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + COMPOSER_PROCESS_TIMEOUT: 300 +``` + +## :signal_strength: Coverage Support + +### Xdebug + +Specify `coverage: xdebug` to use `Xdebug` and disable `PCOV`. +Runs on all [PHP versions supported](#tada-php-support "List of PHP versions supported on this GitHub Action"). + +```yaml +- name: Setup PHP with Xdebug + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + coverage: xdebug +``` + +- When you specify `coverage: xdebug`, the latest version of Xdebug compatible with the PHP version is set up by default. +- If you need Xdebug 2.x on PHP 7.2, 7.3 or 7.4, you can specify `coverage: xdebug2`. + +```yaml +- name: Setup PHP with Xdebug 2.x + uses: step-security/setup-php@v2 + with: + php-version: '7.4' + coverage: xdebug2 +``` + +> [!NOTE] +> Xdebug is enabled by default on Ubuntu GitHub Actions images, so if you are not using it in your workflow it is recommended to disable it as that will have a positive impact on your PHP performance. Please refer to the [disable coverage](#disable-coverage) section for details. + +### PCOV + +Specify `coverage: pcov` to use `PCOV` and disable `Xdebug`. +Runs on PHP 7.1 and newer PHP versions. + +- If your source code directory is other than `src`, `lib` or, `app`, specify `pcov.directory` using the `ini-values` input. + +```yaml +- name: Setup PHP with PCOV + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + ini-values: pcov.directory=api #optional, see above for usage. + coverage: pcov +``` + +- PHPUnit 8.x and above support PCOV out of the box. +- If you are using PHPUnit 5.x, 6.x or 7.x, you need to set up `pcov/clobber` before executing your tests. + +```yaml +- name: Setup PCOV + run: | + composer require pcov/clobber + vendor/bin/pcov clobber +``` + +### Disable Coverage + +Specify `coverage: none` to disable both `Xdebug` and `PCOV`. + +Disable coverage for these reasons: + +- You are not generating coverage reports while testing. +- You are using `phpdbg` for running your tests. +- You are profiling your code using `blackfire`. +- You are using PHP in JIT mode. Please refer to [JIT configuration](#jit-configuration) section for more details. + +```yaml +- name: Setup PHP with no coverage driver + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + coverage: none +``` + +## :memo: Usage + +### Inputs + +> Specify using `with` keyword + +#### `php-version` (optional) + +- Specify the PHP version you want to set up. +- Accepts a `string`. For example `'8.5'`. +- Accepts `lowest` to set up the lowest supported PHP version. +- Accepts `highest` or `latest` to set up the latest stable PHP version. +- Accepts `nightly` to set up a nightly build from the master branch of PHP. +- Accepts `pre-installed` to set up the highest pre-installed PHP version. You can combine this with `update: true` to update the pre-installed PHP version. +- Accepts the format `d.x`, where `d` is the major version. For example `5.x`, `7.x` and `8.x`. +- See [PHP support](#tada-php-support) for the supported PHP versions. +- If not specified, it looks for the following in order: + - The `php-version-file` input if it exists + - A `composer.lock` file and the `platform-overrides.php` value + - A `composer.json` file and the `config.platform.php` value + - If the `composer.lock` or `composer.json` file is in a subdirectory in your repository, please specify the subdirectory path in `COMPOSER_PROJECT_DIR` env. + +#### `php-version-file` (optional) + +- Specify a file with the PHP version you want to set up. +- Accepts a `string`. For example `'.phpenv-version'`. +- See [PHP support](#tada-php-support) for the supported PHP versions. +- By default, `.php-version` file is used. +- The file needs to either have the PHP version as its content or follows the asdf `.tool-versions` format. +- If not specified and the default `.php-version` file is not found, the latest stable PHP version is set up. + +#### `extensions` (optional) + +- Specify the extensions you want to add or disable. +- Accepts a `string` in csv-format. For example `mbstring, :opcache`. +- Accepts `none` to disable all shared extensions. +- Shared extensions prefixed with `:` are disabled. +- See [PHP extension support](#heavy_plus_sign-php-extension-support) for more info. + +#### `ini-file` (optional) + +- Specify the base `php.ini` file. +- Accepts `production`, `development` or `none`. +- By default, production `php.ini` file is used. + +#### `ini-values` (optional) + +- Specify the values you want to add to `php.ini`. +- Accepts a `string` in csv-format. For example `post_max_size=256M, max_execution_time=180`. +- Accepts ini values with commas if wrapped in quotes. For example `xdebug.mode="develop,coverage"`. + +#### `coverage` (optional) + +- Specify the code-coverage driver you want to set up. +- Accepts `xdebug`, `pcov` or `none`. +- See [coverage support](#signal_strength-coverage-support) for more info. + +#### `tools` (optional) + +- Specify the tools you want to set up. +- Accepts a `string` in csv-format. For example: `phpunit, phpcs` +- See [tools support](#wrench-tools-support) for tools supported. + +#### `github-token` (optional) + +- Specify the GitHub token to use for authentication. +- Accepts a `string`. +- By default, `GITHUB_TOKEN` secret provided by GitHub Actions is used. +- For GitHub Enterprise users, it is recommended to use a Personal Access Token (PAT). + +### Outputs + +#### `php-version` + +On GitHub Actions you can assign the `setup-php` step an `id`, you can use the same to get the outputs in a later step. + +- Provides the PHP version in semver format. + +```yaml +- name: Setup PHP + id: setup-php + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + +- name: Print PHP version + run: echo ${{ steps.setup-php.outputs.php-version }} +``` + +### Flags + +> Specify using `env` keyword + +#### `fail-fast` (optional) + +- Specify to mark the workflow as failed if an extension or tool fails to set up. +- This changes the default mode from graceful warnings to fail-fast. +- By default, it is set to `false`. +- Accepts `true` and `false`. + +#### `phpts` (optional) + +- Specify to set up a thread-safe build of PHP. +- Accepts `nts` for non-thread-safe and `zts` or `ts` for thread-safe. +- By default, it is set to `nts`. +- See [thread safe setup](#thread-safe-setup) for more info. + +#### `update` (optional) + +- Specify to update PHP on the runner to the latest patch version. +- Accepts `true` and `false`. +- By default, it is set to `false`. +- See [force update setup](#force-update-setup) for more info. + +See below for more info. + +### Basic Setup + +> Set up a particular PHP version. + +```yaml +steps: +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl + ini-values: post_max_size=256M, max_execution_time=180 + coverage: xdebug + tools: php-cs-fixer, phpunit +``` + +### Matrix Setup + +> Set up multiple PHP versions on multiple operating systems. + +```yaml +jobs: + run: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: ['ubuntu-latest', 'windows-latest', 'macos-latest'] + php-versions: ['8.2', '8.3', '8.4', '8.5'] + phpunit-versions: ['latest'] + include: + - operating-system: 'ubuntu-latest' + php-versions: '8.1' + phpunit-versions: 10 + steps: + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, intl + ini-values: post_max_size=256M, max_execution_time=180 + coverage: xdebug + tools: php-cs-fixer, phpunit:${{ matrix.phpunit-versions }} +``` + +### Nightly Build Setup + +> Set up a nightly build of `PHP 8.6`. + +- These PHP versions are currently in active development and might contain bugs and breaking changes. +- Some user space extensions might not support these versions currently. + +```yaml +steps: +- name: Setup nightly PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.6' + extensions: mbstring + ini-values: post_max_size=256M, max_execution_time=180 + coverage: xdebug + tools: php-cs-fixer, phpunit +``` + +### Debug Build Setup + +> Set up a PHP build with debugging symbols. + +- Production release builds of PHP without debugging symbols are set up by default. +- You can use the `debug` environment variable to set up a build with debugging symbols for PHP 5.6 and above. + +> [!NOTE] +> - On Linux, the debug symbols are added as [debug info files](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Separate-Debug-Files.html) in the `/usr/lib/debug/.build-id` directory. These files match the `build-id` in the ELF section of the PHP binaries and debugging tools like `gdb` are able to resolve the symbols from these files. +> - On Windows, the debug symbols are added as `pdb` files in the PHP installation directory. +> - On macOS, the debug symbols are compiled into the binaries. + +```yaml +steps: +- name: Setup PHP with debugging symbols + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + debug: true # specify true or false +``` + +### Thread Safe Setup + +> Set up `TS` or `NTS` PHP. + +- `NTS` versions are set up by default. + +```yaml +jobs: + run: + runs-on: [ubuntu-latest, windows-latest, macos-latest] + name: Setup PHP TS + steps: + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + phpts: ts # specify ts or nts +``` + +### Force Update Setup + +> Update to the latest patch of PHP versions. + +- Pre-installed PHP versions are not updated to their latest patch release by default. +- If `ppa:ondrej/php` is missing on the Ubuntu GitHub environment, the PHP version is updated to the latest patch release. +- You can specify the `update` environment variable to `true` for updating to the latest release. + +```yaml +- name: Setup PHP with latest versions + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + update: true # specify true or false +``` + +### Multi-Arch Setup + +> Set up PHP on multiple architecture on Ubuntu GitHub Runners. + +- `PHP 5.6` to `PHP 8.5` are supported by `setup-php` on multiple architecture on `Ubuntu` and `Debian`. +- For this, you can use `shivammathur/node` images as containers. These have compatible `Nodejs` and `PHP` installed for `setup-php`. + +```yaml +jobs: + run: + runs-on: ${{ matrix.os }} + container: shivammathur/node:php-${{ matrix.php-versions }}-24.04-${{ matrix.arch }} + strategy: + matrix: + arch: ["amd64", "arm64v8"] + php-versions: [8.4, 8.5] + include: + - arch: "amd64" + os: "ubuntu-24.04" + - arch: "arm64v8" + os: "ubuntu-24.04-arm" + steps: + - name: Install PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} +``` + +### Self Hosted Setup + +> Set up PHP on a self-hosted runner. + +- To set up a containerised self-hosted runner, refer to the following guides as per your base operating system. + - [Linux](https://github.com/step-security/setup-php/wiki/Dockerized-self-hosted-runner-on-Linux) + - [Windows](https://github.com/step-security/setup-php/wiki/Dockerized-self-hosted-runner-on-Windows) + +- To set up the runner directly on the host OS or in a virtual machine, follow this [requirements guide](https://github.com/step-security/setup-php/wiki/Requirements-for-self-hosted-runners "Requirements guide for self-hosted runner to run setup-php") before setting up the self-hosted runner. +- If your workflow uses [service containers](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idservices "GitHub Actions Services"), then set up the runner on a Linux host or in a Linux virtual machine. GitHub Actions does not support nested virtualization on Linux, so services will not work in a dockerized container. + +It is recommended to specify the environment variable `runner` with the value `self-hosted` for self-hosted environments. + +```yaml +jobs: + run: + runs-on: self-hosted + strategy: + matrix: + php-versions: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + name: PHP ${{ matrix.php-versions }} + steps: + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + env: + runner: self-hosted +``` + +> [!NOTE] +> - Do not set up multiple self-hosted runners on a single server instance as parallel workflow will conflict with each other. +> - Do not set up self-hosted runners on the side of your development environment or your production server. +> - Avoid using the same labels for your `self-hosted` runners which are used by `GitHub-hosted` runners. + +### Local Testing Setup + +> Test your `Ubuntu` workflow locally using [`nektos/act`](https://github.com/nektos/act "Project to test GitHub Actions locally"). + +```yaml +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' +``` + +Run the workflow locally with `act` using [`shivammathur/node`](https://github.com/shivammathur/node-docker "Docker image to run setup-php") docker images. + +Choose the image tag which matches the `runs-on` property in your workflow. For example, if you are using `ubuntu-22.04` in your workflow, run `act -P ubuntu-22.04=shivammathur/node:22.04`. + +```bash +# For runs-on: ubuntu-latest +act -P ubuntu-latest=shivammathur/node:latest + +# For runs-on: ubuntu-24.04 +act -P ubuntu-24.04=shivammathur/node:24.04 + +# For runs-on: ubuntu-22.04 +act -P ubuntu-22.04=shivammathur/node:22.04 +``` + +### JIT Configuration + +> Enable Just-in-time (JIT) on PHP 8.0 and above. + +- To enable JIT, enable `opcache` in cli mode by setting `opcache.enable_cli=1`. +- JIT conflicts with `Xdebug`, `PCOV`, and other extensions which override `zend_execute_ex` function, so set `coverage: none` and disable any such extension if added. +- By default, `opcache.jit=1235` and `opcache.jit_buffer_size=256M` (`opcache.jit_buffer_size=128M` on ARM-based environments) are set which can be changed using `ini-values` input. +- For detailed information about JIT related directives refer to the [`official PHP documentation`](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit "opcache.jit documentation"). + +For example to enable JIT in `tracing` mode with buffer size of `64 MB`. + +```yaml +- name: Setup PHP with JIT in tracing mode + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + coverage: none + ini-values: opcache.enable_cli=1, opcache.jit=tracing, opcache.jit_buffer_size=64M +``` + +### Cache Extensions + +You can cache PHP extensions using `shivammathur/cache-extensions` and `action/cache` GitHub Actions. Extensions which take very long to set up when cached are available in the next workflow run and are enabled directly. This reduces the workflow execution time. +Refer to [`shivammathur/cache-extensions`](https://github.com/shivammathur/cache-extensions "GitHub Action to cache php extensions") for details. + +### Cache Composer Dependencies + +If your project uses composer, you can persist the composer's internal cache directory. Dependencies cached are loaded directly instead of downloading them while installation. The files cached are available across check-runs and will reduce the workflow execution time. + +```yaml +- name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + +- name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + +- name: Install dependencies + run: composer install --prefer-dist +``` + +> [!NOTE] +> - Please do not cache `vendor` directory using `action/cache` as that will have side effects. +> - If you do not commit `composer.lock`, you can use the hash of `composer.json` as the key for your cache. +```yaml +key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} +``` + +- If you support a range of `composer` dependencies and use `prefer-lowest` and `prefer-stable` options, you can store them in your matrix and add them to the keys. +```yaml +key: ${{ runner.os }}-composer-${{ matrix.prefer }}-${{ hashFiles('**/composer.lock') }} +restore-keys: ${{ runner.os }}-composer-${{ matrix.prefer }}- +``` + +### GitHub Composer Authentication + +By default, setup-php uses the `GITHUB_TOKEN` secret that is generated for each workflow run. In case you want to use a Personal Access Token (PAT) instead, you can set the `github-token` input. + +```yaml +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + github-token: ${{ secrets.YOUR_PAT_TOKEN }} +``` + +The `COMPOSER_TOKEN` and `GITHUB_TOKEN` environment variables have been deprecated in favor of the `github-token` input and will be removed in the next major version. + +For GitHub Enterprise users, the `github-token` input does not default to the `GITHUB_TOKEN` secret. Therefore, it's recommended to set the `github-token` input to a Personal Access Token (PAT). + +### Private Packagist Authentication + +If you use Private Packagist for your private composer dependencies, you can set the `PACKAGIST_TOKEN` environment variable to authenticate. + +```yaml +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + PACKAGIST_TOKEN: ${{ secrets.PACKAGIST_TOKEN }} +``` + +### Manual Composer Authentication + +In addition to GitHub or Private Packagist, if you want to authenticate private repositories hosted elsewhere, you can set the `COMPOSER_AUTH_JSON` environment variable with the authentication methods and the credentials in json format. +Please refer to the authentication section in [`composer documentation`](https://getcomposer.org/doc/articles/authentication-for-private-packages.md "composer documentation") for more details. + +```yaml +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + env: + COMPOSER_AUTH_JSON: | + { + "http-basic": { + "example.org": { + "username": "${{ secrets.EXAMPLE_ORG_USERNAME }}", + "password": "${{ secrets.EXAMPLE_ORG_PASSWORD }}" + } + } + } +``` + +### Inline PHP Scripts + +If you have to run multiple lines of PHP code in your workflow, you can do that easily without saving it to a file. + +Put the code in the run property of a step and specify the shell as `php {0}`. + +```yaml +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + +- name: Run PHP code + shell: php {0} + run: | + Here is an example with `phpcs`. + +```yaml +- name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + tools: cs2pr, phpcs + +- name: Run phpcs + run: phpcs -q --report=checkstyle src | cs2pr +``` + +### Examples + +Examples of using `setup-php` with various PHP frameworks and packages. + +| Framework/Package | Runs on | Workflow | +|----------------------------------------|---------------------------------|---------------------------------------------------------------------------------------------------------------| +| Blackfire | `macOS`, `ubuntu` and `windows` | [blackfire.yml](./examples/blackfire.yml "GitHub Action using Blackfire") | +| Blackfire Player | `macOS` and `ubuntu` | [blackfire-player.yml](./examples/blackfire-player.yml "GitHub Action using Blackfire Player") | +| CakePHP with `MySQL` and `Redis` | `ubuntu` | [cakephp-mysql.yml](./examples/cakephp-mysql.yml "GitHub Action for CakePHP with MySQL and Redis") | +| CakePHP with `PostgreSQL` and `Redis` | `ubuntu` | [cakephp-postgres.yml](./examples/cakephp-postgres.yml "GitHub Action for CakePHP with Postgres and Redis") | +| CakePHP without services | `macOS`, `ubuntu` and `windows` | [cakephp.yml](./examples/cakephp.yml "GitHub Action for CakePHP without services") | +| CodeIgniter | `macOS`, `ubuntu` and `windows` | [codeigniter.yml](./examples/codeigniter.yml "GitHub Action for CodeIgniter") | +| Drupal 11 (Composer-managed) | `ubuntu` | [drupal.yml](./examples/drupal.yml "GitHub Action for Drupal 11 composer-managed projects") | +| Laminas MVC | `macOS`, `ubuntu` and `windows` | [laminas-mvc.yml](./examples/laminas-mvc.yml "GitHub Action for Laminas Framework MVC Projects") | +| Laravel with `MySQL` and `Redis` | `ubuntu` | [laravel-mysql.yml](./examples/laravel-mysql.yml "GitHub Action for Laravel with MySQL and Redis") | +| Laravel with `PostgreSQL` and `Redis` | `ubuntu` | [laravel-postgres.yml](./examples/laravel-postgres.yml "GitHub Action for Laravel with PostgreSQL and Redis") | +| Laravel without services | `macOS`, `ubuntu` and `windows` | [laravel.yml](./examples/laravel.yml "GitHub Action for Laravel without services") | +| Lumen with `MySQL` and `Redis` | `ubuntu` | [lumen-mysql.yml](./examples/lumen-mysql.yml "GitHub Action for Lumen with MySQL and Redis") | +| Lumen with `PostgreSQL` and `Redis` | `ubuntu` | [lumen-postgres.yml](./examples/lumen-postgres.yml "GitHub Action for Lumen with PostgreSQL and Redis") | +| Lumen without services | `macOS`, `ubuntu` and `windows` | [lumen.yml](./examples/lumen.yml "GitHub Action for Lumen without services") | +| Phalcon with `MySQL` | `ubuntu` | [phalcon-mysql.yml](./examples/phalcon-mysql.yml "GitHub Action for Phalcon with MySQL") | +| Phalcon with `PostgreSQL` | `ubuntu` | [phalcon-postgres.yml](./examples/phalcon-postgres.yml "GitHub Action for Phalcon with PostgreSQL") | +| Slim Framework | `macOS`, `ubuntu` and `windows` | [slim-framework.yml](./examples/slim-framework.yml "GitHub Action for Slim Framework") | +| Symfony with `MySQL` | `ubuntu` | [symfony-mysql.yml](./examples/symfony-mysql.yml "GitHub Action for Symfony with MySQL") | +| Symfony with `PostgreSQL` | `ubuntu` | [symfony-postgres.yml](./examples/symfony-postgres.yml "GitHub Action for Symfony with PostgreSQL") | +| Symfony without services | `macOS`, `ubuntu` and `windows` | [symfony.yml](./examples/symfony.yml "GitHub Action for Symfony without services") | +| WordPress plugin | `ubuntu` | [wordpress.yml](./examples/wordpress.yml "GitHub Action for WordPress plugins") | +| WordPress with Roots/Bedrock | `ubuntu` | [bedrock.yml](./examples/bedrock.yml "GitHub Action for WordPress development using @roots/bedrock") | +| WordPress with Roots/Sage | `ubuntu` | [sage.yml](./examples/sage.yml "GitHub Action for WordPress development using @roots/sage") | +| Yii3 web application with `MySQL` | `ubuntu` | [yii3-mysql.yml](./examples/yii3-mysql.yml "GitHub Action for Yii3 web application with MySQL") | +| Yii3 web application with `PostgreSQL` | `ubuntu` | [yii3-postgres.yml](./examples/yii3-postgres.yml "GitHub Action for Yii3 web application with PostgreSQL") | +| Yii3 web application | `ubuntu` and `windows` | [yii3.yml](./examples/yii3.yml "GitHub Action for Yii3 web application") | + +## :bookmark: Versioning + +- Semantic release versions can also be used. It is recommended to [use dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot "Setup Dependabot with GitHub Actions") with semantic versioning to keep the actions in your workflows up to date. +- A new major version of the action will only be tagged when there are breaking changes in the setup-php API i.e. inputs, outputs, and environment flags. +- It is highly discouraged to use the `main` branch as version, it might break your workflow after major releases as they have breaking changes. + +## :scroll: License + +- The scripts and documentation in this project are under the [MIT License](LICENSE "License for step-security/setup-php"). +- This project has multiple dependencies. Their licenses can be found in their respective repositories. +- The logo for `setup-php` is a derivative work of [php.net logo](https://www.php.net/download-logos.php) and is licensed under the [CC BY-SA 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/ "Creative Commons License"). + +## :bookmark_tabs: Further Reading + +- [About GitHub Actions](https://github.com/features/actions "GitHub Actions") +- [GitHub Actions Syntax](https://help.github.com/en/articles/workflow-syntax-for-github-actions "GitHub Actions Syntax") +- [Other Awesome Actions](https://github.com/sdras/awesome-actions "List of Awesome GitHub Actions") + + + +[`backward-compatibility-check`]: https://github.com/Roave/BackwardCompatibilityCheck +[`behat`]: https://docs.behat.org/en/latest/ +[`blackfire`]: https://blackfire.io/docs/php/index +[`blackfire-player`]: https://blackfire.io/docs/builds-cookbooks/player +[`box`]: https://github.com/humbug/box +[`castor`]: https://github.com/jolicode/castor +[`churn`]: https://github.com/bmitch/churn-php +[`codeception`]: https://codeception.com/ +[`composer`]: https://getcomposer.org/ +[`composer-dependency-analyser`]: https://github.com/shipmonk-rnd/composer-dependency-analyser +[`composer-normalize`]: https://github.com/ergebnis/composer-normalize +[`composer-prefetcher`]: https://github.com/narrowspark/automatic-composer-prefetcher +[`composer-require-checker`]: https://github.com/maglnet/ComposerRequireChecker +[`composer-unused`]: https://github.com/composer-unused/composer-unused +[`cs2pr`]: https://github.com/staabm/annotate-pull-request-from-checkstyle +[`deployer`]: https://deployer.org/ +[`ecs`]: https://github.com/easy-coding-standard/easy-coding-standard +[`flex`]: https://github.com/symfony/flex +[`grpc_php_plugin`]: https://grpc.io/ +[`infection`]: https://infection.github.io/ +[`mago`]: https://github.com/carthage-software/mago +[`name-collision-detector`]: https://github.com/shipmonk/name-collision-detector +[`parallel-lint`]: https://github.com/php-parallel-lint/PHP-Parallel-Lint +[`pecl`]: https://pecl.php.net/ +[`phan`]: https://github.com/phan/phan/wiki +[`phing`]: https://www.phing.info/ +[`phinx`]: https://phinx.org/ +[`phive`]: https://phar.io/ +[`php-config`]: https://www.php.net/manual/en/install.pecl.php-config.php +[`php-cs-fixer`]: https://cs.symfony.com/ +[`php-scoper`]: https://github.com/humbug/php-scoper +[`phpcbf`]: https://github.com/PHPCSStandards/php_codesniffer +[`phpcpd`]: https://github.com/sebastianbergmann/phpcpd +[`phpcs`]: https://github.com/PHPCSStandards/php_codesniffer +[`phpdoc`]: https://phpdoc.org/ +[`phpDocumentor`]: https://phpdoc.org/ +[`phpize`]: https://www.php.net/manual/en/install.pecl.phpize.php +[`phplint`]: https://github.com/overtrue/phplint +[`phpmd`]: https://phpmd.org/ +[`phpspec`]: https://www.phpspec.net/ +[`phpstan`]: https://phpstan.org/ +[`phpunit`]: https://phpunit.de/ +[`phpunit-bridge`]: https://symfony.com/doc/current/components/phpunit_bridge.html +[`phpunit-polyfills`]: https://github.com/Yoast/PHPUnit-Polyfills +[`pie`]: https://github.com/php/pie +[`pint`]: https://github.com/laravel/pint +[`prestissimo`]: https://github.com/hirak/prestissimo +[`protoc`]: https://developers.google.com/protocol-buffers/ +[`psalm`]: https://psalm.dev/ +[`rector`]: https://getrector.org/ +[`symfony`]: https://symfony.com/download +[`symfony-cli`]: https://symfony.com/download +[`vapor`]: https://docs.vapor.build/ +[`vapor-cli`]: https://docs.vapor.build/ +[`wp`]: https://wp-cli.org/ +[`wp-cli`]: https://wp-cli.org/ diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..77568b2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +Please report security vulnerabilities to security@stepsecurity.io diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts new file mode 100644 index 0000000..6c9dc56 --- /dev/null +++ b/__tests__/config.test.ts @@ -0,0 +1,16 @@ +import * as config from '../src/config'; + +describe('Config tests', () => { + it.each` + ini_values | os | output + ${'a=b, c=d'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b\nc=d"'} + ${'a=b, c=d'} | ${'linux'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'} + ${'a=b, c=d'} | ${'darwin'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'} + ${'a=b & ~c'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'b & ~c\'"'} + ${'a="~(b)"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'~(b)\'"'} + ${'a="b, c"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b, c"'} + ${'a=b, c=d'} | ${'openbsd'} | ${'Platform openbsd is not supported'} + `('checking addINIValues on $os', async ({ini_values, os, output}) => { + expect(await config.addINIValues(ini_values, os)).toContain(output); + }); +}); diff --git a/__tests__/core.test.ts b/__tests__/core.test.ts new file mode 100644 index 0000000..b9bb1a1 --- /dev/null +++ b/__tests__/core.test.ts @@ -0,0 +1,106 @@ +import * as core from '../src/core'; + +describe('Core tests', () => { + const originalEnv = process.env; + const originalExitCode = process.exitCode; + let stdoutOutput: string; + const originalWrite = process.stdout.write; + + beforeEach(() => { + process.env = {...originalEnv}; + process.exitCode = undefined; + stdoutOutput = ''; + process.stdout.write = jest.fn((chunk: string | Uint8Array): boolean => { + stdoutOutput += chunk.toString(); + return true; + }) as unknown as typeof process.stdout.write; + }); + + afterEach(() => { + process.env = originalEnv; + process.exitCode = originalExitCode; + process.stdout.write = originalWrite; + }); + + it('checking issueCommand with no properties', () => { + core.issueCommand('warning', {}, 'test message'); + expect(stdoutOutput).toContain('::warning::test message'); + }); + + it('checking issueCommand with properties', () => { + core.issueCommand('error', {file: 'test.ts', line: '10'}, 'error message'); + expect(stdoutOutput).toContain( + '::error file=test.ts,line=10::error message' + ); + }); + + it('checking issueCommand escapes special characters in message', () => { + core.issueCommand('warning', {}, 'line1\nline2\rline3%percent'); + expect(stdoutOutput).toContain( + '::warning::line1%0Aline2%0Dline3%25percent' + ); + }); + + it('checking issueCommand escapes special characters in properties', () => { + core.issueCommand('error', {file: 'path:to,file'}, 'message'); + expect(stdoutOutput).toContain('::error file=path%3Ato%2Cfile::message'); + }); + + it('checking issueCommand with Error object', () => { + const error = new Error('test error'); + core.issueCommand('error', {}, error); + expect(stdoutOutput).toContain('::error::Error: test error'); + }); + + it('checking issueCommand filters empty properties', () => { + core.issueCommand('warning', {file: 'test.ts', line: ''}, 'message'); + expect(stdoutOutput).toContain('::warning file=test.ts::message'); + }); + + it('checking error', () => { + core.error('error message'); + expect(stdoutOutput).toContain('::error::error message'); + }); + + it('checking error with Error object', () => { + core.error(new Error('error instance')); + expect(stdoutOutput).toContain('::error::Error: error instance'); + }); + + it('checking setFailed', () => { + core.setFailed('failure message'); + expect(process.exitCode).toBe(1); + expect(stdoutOutput).toContain('::error::failure message'); + }); + + it('checking setFailed with Error object', () => { + core.setFailed(new Error('failure error')); + expect(process.exitCode).toBe(1); + expect(stdoutOutput).toContain('::error::Error: failure error'); + }); + + it('checking getInput returns value', () => { + process.env['INPUT_TEST-INPUT'] = 'test value'; + expect(core.getInput('test-input')).toBe('test value'); + }); + + it('checking getInput trims value', () => { + process.env['INPUT_TEST-INPUT'] = ' trimmed '; + expect(core.getInput('test-input')).toBe('trimmed'); + }); + + it('checking getInput returns empty string for missing input', () => { + expect(core.getInput('missing-input')).toBe(''); + }); + + it('checking getInput throws for required missing input', () => { + expect(() => core.getInput('missing-input', true)).toThrow( + 'Input required and not supplied: missing-input' + ); + }); + + it('checking getInput handles spaces in name', () => { + process.env['INPUT_INPUT_WITH_SPACES'] = 'spaced value'; + expect(core.getInput('input with spaces')).toBe('spaced value'); + }); +}); diff --git a/__tests__/coverage.test.ts b/__tests__/coverage.test.ts new file mode 100644 index 0000000..f8e460e --- /dev/null +++ b/__tests__/coverage.test.ts @@ -0,0 +1,44 @@ +import * as coverage from '../src/coverage'; + +describe('Config tests', () => { + it.each` + driver | php | os | output + ${'PCOV'} | ${'7.4'} | ${'win32'} | ${'Add-Extension pcov,Disable-Extension xdebug false'} + ${'pcov'} | ${'7.4'} | ${'win32'} | ${'$pcov_version = php -r "echo phpversion(\'pcov\');"'} + ${'pcov'} | ${'7.4'} | ${'win32'} | ${'PCOV $pcov_version enabled as coverage driver'} + ${'pcov'} | ${'7.0'} | ${'win32'} | ${'PHP 7.1 or newer is required'} + ${'pcov'} | ${'5.6'} | ${'win32'} | ${'PHP 7.1 or newer is required'} + ${'pcov'} | ${'7.4'} | ${'win32'} | ${'Add-Extension pcov,Disable-Extension xdebug false'} + ${'pcov'} | ${'7.4'} | ${'linux'} | ${'add_extension pcov,disable_extension xdebug false'} + ${'pcov'} | ${'7.4'} | ${'darwin'} | ${'add_brew_extension pcov,disable_extension xdebug false'} + ${'xdebug'} | ${'7.4'} | ${'win32'} | ${'Add-Extension xdebug'} + ${'xdebug3'} | ${'7.1'} | ${'win32'} | ${'xdebug3 is not supported on PHP 7.1'} + ${'xdebug2'} | ${'7.4'} | ${'win32'} | ${'Add-Extension xdebug stable 2.9.8'} + ${'xdebug'} | ${'8.0'} | ${'linux'} | ${'add_extension xdebug'} + ${'xdebug3'} | ${'8.0'} | ${'linux'} | ${'add_extension xdebug'} + ${'xdebug2'} | ${'7.4'} | ${'linux'} | ${'add_pecl_extension xdebug 2.9.8 zend_extension'} + ${'xdebug'} | ${'7.4'} | ${'linux'} | ${'xdebug_version="$(php -r "echo phpversion(\'xdebug\');")"'} + ${'xdebug'} | ${'7.4'} | ${'linux'} | ${'Xdebug $xdebug_version enabled as coverage driver'} + ${'xdebug'} | ${'7.4'} | ${'darwin'} | ${'add_brew_extension xdebug'} + ${'xdebug3'} | ${'7.1'} | ${'darwin'} | ${'xdebug3 is not supported on PHP 7.1'} + ${'xdebug2'} | ${'7.4'} | ${'darwin'} | ${'add_brew_extension xdebug2'} + ${'xdebug2'} | ${'8.0'} | ${'darwin'} | ${'xdebug2 is not supported on PHP 8.0'} + ${'none'} | ${'7.4'} | ${'win32'} | ${'Disable-Extension xdebug false,Disable-Extension pcov false'} + ${'none'} | ${'7.4'} | ${'linux'} | ${'disable_extension xdebug false,disable_extension pcov false'} + ${'none'} | ${'7.4'} | ${'darwin'} | ${'disable_extension xdebug false,disable_extension pcov false'} + ${'nocov'} | ${'7.x'} | ${'any'} | ${''} + ${''} | ${'7.x'} | ${'any'} | ${''} + `( + 'checking addCoverage with $driver on $os', + async ({driver, php, os, output}) => { + const script: string = await coverage.addCoverage(driver, php, os); + if (output) { + output.split(',').forEach((command: string) => { + expect(script).toContain(command); + }); + } else { + expect(script).toEqual(output); + } + } + ); +}); diff --git a/__tests__/extensions.test.ts b/__tests__/extensions.test.ts new file mode 100644 index 0000000..b0518d7 --- /dev/null +++ b/__tests__/extensions.test.ts @@ -0,0 +1,162 @@ +import * as fs from 'fs'; +import * as extensions from '../src/extensions'; + +describe('Extension tests', () => { + it.each` + extension | version | output + ${'none'} | ${'7.4'} | ${'Disable-AllShared'} + ${':intl'} | ${'7.4'} | ${'Disable-Extension intl'} + ${'ast-beta'} | ${'7.4'} | ${'Add-Extension ast beta'} + ${'blackfire'} | ${'7.3'} | ${'Add-Blackfire blackfire'} + ${'blackfire-1.31.0'} | ${'7.3'} | ${'Add-Blackfire blackfire-1.31.0'} + ${'grpc-1.2.3'} | ${'7.4'} | ${'Add-Extension grpc stable 1.2.3'} + ${'inotify-1.2.3alpha2'} | ${'7.4'} | ${'Add-Extension inotify alpha 1.2.3'} + ${'ioncube'} | ${'7.4'} | ${'Add-Ioncube'} + ${'mongodb-mongodb/mongo-php-driver@master'} | ${'7.3'} | ${'Add-Log "$cross" "mongodb-mongodb/mongo-php-driver@master" "mongodb-mongodb/mongo-php-driver@master is not supported on PHP 7.3"'} + ${'mysql'} | ${'7.4'} | ${'Add-Extension mysqli\nAdd-Extension mysqlnd'} + ${'mysql'} | ${'5.5'} | ${'Add-Extension mysql\nAdd-Extension mysqli\nAdd-Extension mysqlnd'} + ${'oci8'} | ${'7.4'} | ${'Add-Oci oci8'} + ${'pcov'} | ${'5.6'} | ${'Add-Log "$cross" "pcov" "pcov is not supported on PHP 5.6"'} + ${'pdo_oci'} | ${'7.4'} | ${'Add-Oci pdo_oci'} + ${'ibm_db2'} | ${'7.4'} | ${'Add-Ibm ibm_db2'} + ${'pdo_ibm'} | ${'7.4'} | ${'Add-Ibm pdo_ibm'} + ${'pecl_http'} | ${'7.4'} | ${'Add-Http'} + ${'http'} | ${'8.5'} | ${'Add-Http'} + ${'pdo_sqlsrv'} | ${'7.4'} | ${'Add-Sqlsrv pdo_sqlsrv'} + ${'phalcon3'} | ${'7.2'} | ${'Add-Phalcon phalcon3'} + ${'phalcon4'} | ${'7.4'} | ${'Add-Phalcon phalcon4'} + ${'sqlite'} | ${'7.4'} | ${'Add-Extension sqlite3'} + ${'sqlsrv'} | ${'5.6'} | ${'Add-Extension sqlsrv'} + ${'sqlsrv'} | ${'7.4'} | ${'Add-Sqlsrv sqlsrv'} + ${'sqlsrv-1.2.3preview1'} | ${'7.4'} | ${'Add-Extension sqlsrv devel 1.2.3'} + ${'Xdebug'} | ${'7.4'} | ${'Add-Extension xdebug'} + ${'xdebug2'} | ${'7.2'} | ${'Add-Extension xdebug stable 2.9.8'} + ${'zephir_parser'} | ${'7.2'} | ${'Add-ZephirParser zephir_parser'} + `( + 'checking addExtensionOnWindows for extension $extension on version $version', + async ({extension, version, output}) => { + expect( + await extensions.addExtension(extension, version, 'win32') + ).toContain(output); + } + ); + + it.each` + extension | version | output + ${'none'} | ${'7.4'} | ${'disable_all_shared'} + ${':intl'} | ${'7.4'} | ${'disable_extension intl'} + ${'ast-beta'} | ${'7.4'} | ${'add_unstable_extension ast beta extension'} + ${'blackfire'} | ${'7.3'} | ${'add_blackfire blackfire'} + ${'blackfire-1.31.0'} | ${'7.3'} | ${'add_blackfire blackfire-1.31.0'} + ${'couchbase'} | ${'7.4'} | ${'add_couchbase'} + ${'gearman'} | ${'5.6'} | ${'add_gearman'} + ${'geos'} | ${'7.3'} | ${'add_geos'} + ${'grpc-1.2.3'} | ${'7.4'} | ${'add_pecl_extension grpc 1.2.3 extension'} + ${'http-1.2.3'} | ${'7.3'} | ${'add_http http-1.2.3'} + ${'intl-65.1'} | ${'5.6'} | ${'add_intl intl-65.1'} + ${'ioncube'} | ${'7.3'} | ${'add_ioncube'} + ${'memcache-8.2'} | ${'8.2'} | ${'add_pecl_extension memcache 8.2 extension'} + ${'mongodb-mongodb/mongo-php-driver@master'} | ${'7.3'} | ${'add_extension_from_source mongodb https://github.com mongodb mongo-php-driver master extension'} + ${'oci8'} | ${'7.3'} | ${'add_oci oci8'} + ${'pcov'} | ${'5.6'} | ${'add_log "$cross" "pcov" "pcov is not supported on PHP 5.6'} + ${'ibm_db2'} | ${'7.3'} | ${'add_ibm ibm_db2'} + ${'pdo-odbc'} | ${'7.4'} | ${'add_pdo_extension odbc'} + ${'pdo_cubrid'} | ${'7.0'} | ${'add_cubrid pdo_cubrid'} + ${'pdo_cubrid'} | ${'7.4'} | ${'add_pdo_extension cubrid'} + ${'pdo_mysql'} | ${'7.4'} | ${'add_pdo_extension mysql'} + ${'pdo_oci'} | ${'7.3'} | ${'add_oci pdo_oci'} + ${'pdo_ibm'} | ${'7.3'} | ${'add_ibm pdo_ibm'} + ${'pdo_sqlsrv'} | ${'7.4'} | ${'add_sqlsrv pdo_sqlsrv'} + ${'pecl_http'} | ${'7.3'} | ${'add_http'} + ${'phalcon3'} | ${'7.3'} | ${'add_phalcon phalcon3'} + ${'relay'} | ${'7.4'} | ${'add_relay relay'} + ${'relay-v1.2.3'} | ${'7.4'} | ${'add_relay relay-v1.2.3'} + ${'sqlite'} | ${'7.4'} | ${'add_extension sqlite3'} + ${'sqlsrv-1.2.3-beta1'} | ${'7.4'} | ${'add_pecl_extension sqlsrv 1.2.3beta1 extension'} + ${'Xdebug'} | ${'7.4'} | ${'add_extension xdebug'} + ${'xdebug-alpha'} | ${'7.4'} | ${'add_unstable_extension xdebug alpha zend_extension'} + ${'xdebug2'} | ${'7.2'} | ${'add_pecl_extension xdebug 2.9.8 zend_extension'} + ${'zephir_parser-1.2.3'} | ${'7.2'} | ${'add_zephir_parser zephir_parser-1.2.3'} + `( + 'checking addExtensionOnLinux for extension $extension on version $version', + async ({extension, version, output}) => { + expect( + await extensions.addExtension(extension, version, 'linux') + ).toContain(output); + } + ); + + it.each` + extension | version | output + ${'none'} | ${'7.2'} | ${'disable_all_shared'} + ${':intl'} | ${'7.2'} | ${'disable_extension intl'} + ${'ast-beta'} | ${'7.2'} | ${'add_unstable_extension ast beta extension'} + ${'blackfire'} | ${'7.3'} | ${'add_blackfire blackfire'} + ${'blackfire-1.31.0'} | ${'7.3'} | ${'add_blackfire blackfire-1.31.0'} + ${'couchbase'} | ${'5.6'} | ${'add_couchbase'} + ${'does_not_exist'} | ${'7.2'} | ${'add_extension does_not_exist'} + ${'geos'} | ${'7.3'} | ${'add_geos'} + ${'grpc-1.2.3'} | ${'7.2'} | ${'add_pecl_extension grpc 1.2.3 extension'} + ${'http-1.2.3'} | ${'7.3'} | ${'add_http http-1.2.3'} + ${'imagick'} | ${'5.5'} | ${'add_extension imagick'} + ${'ioncube'} | ${'7.3'} | ${'add_ioncube'} + ${'mongodb-mongodb/mongo-php-driver@master'} | ${'7.2'} | ${'add_extension_from_source mongodb https://github.com mongodb mongo-php-driver master extension'} + ${'oci8'} | ${'7.3'} | ${'add_oci oci8'} + ${'pcov'} | ${'5.6'} | ${'add_log "$cross" "pcov" "pcov is not supported on PHP 5.6"'} + ${'pdo_oci'} | ${'7.3'} | ${'add_oci pdo_oci'} + ${'pecl_http'} | ${'7.3'} | ${'add_http'} + ${'relay-1.2.3'} | ${'7.4'} | ${'add_relay relay-1.2.3'} + ${'sqlite'} | ${'7.2'} | ${'add_extension sqlite3'} + ${'zephir_parser-v1.2.3'} | ${'7.2'} | ${'add_zephir_parser zephir_parser-v1.2.3'} + `( + 'checking addExtensionOnDarwin for extension $extension on version $version', + async ({extension, version, output}) => { + expect( + await extensions.addExtension(extension, version, 'darwin') + ).toContain(output); + } + ); + + const data: string[][] = fs + .readFileSync('src/configs/brew_extensions') + .toString() + .split(/\r?\n/) + .filter(Boolean) + .map(line => { + const [formula, extension]: string[] = line.split('='); + const prefix: string = + extension == 'xdebug' ? 'zend_extension' : 'extension'; + const ext_name = extension.replace(/\d+|(pdo|pecl)[_-]/, ''); + const output: string = fs.existsSync( + `src/scripts/extensions/${ext_name}.sh` + ) + ? `add_${ext_name}` + : `add_brew_extension ${formula} ${prefix}`; + return [ + formula, + formula.match(/phalcon3|lua|propro/) ? '7.3' : '8.1', + output + ]; + }); + + it.each(data)( + 'checking addExtensionOnDarwin for brew extension %s', + async (extension, version, output) => { + expect( + await extensions.addExtension(extension, version, 'darwin') + ).toContain(output); + } + ); + + it.each` + extension | version | output + ${'xdebug'} | ${'7.2'} | ${'Platform openbsd is not supported'} + `( + 'checking addExtension on openbsd for extension $extension on version $version', + async ({extension, version, output}) => { + expect( + await extensions.addExtension(extension, version, 'openbsd') + ).toContain(output); + } + ); +}); diff --git a/__tests__/fetch.test.ts b/__tests__/fetch.test.ts new file mode 100644 index 0000000..419101a --- /dev/null +++ b/__tests__/fetch.test.ts @@ -0,0 +1,45 @@ +import * as fetch from '../src/fetch'; +import nock from 'nock'; + +it('checking fetch', async () => { + const host_url = 'https://example.com'; + const manifest_url = host_url + '/manifest'; + const ping_url = host_url + '/ping'; + + nock(host_url) + .get('/manifest') + .reply(200, {latest: 'latest'}) + .get('/manifest', '', { + reqheaders: {authorization: 'Bearer invalid_token'} + }) + .reply(401, {error: '401: Unauthorized'}) + .get('/ping') + .twice() + .reply(301, undefined, { + Location: host_url + '/pong' + }) + .get('/pong') + .reply(200, 'pong') + .get('/error') + .replyWithError('Network failure'); + + let response: Record = await fetch.fetch(manifest_url); + expect(response.error).toBe(undefined); + expect(response.data).toContain('latest'); + + response = await fetch.fetch(ping_url, '', 1); + expect(response.error).toBe(undefined); + expect(response.data).toContain('pong'); + + response = await fetch.fetch(ping_url, '', 0); + expect(response.error).toBe('301: Redirect error'); + expect(response.data).toBe(undefined); + + response = await fetch.fetch(manifest_url, 'invalid_token'); + expect(response.error).not.toBe(undefined); + expect(response.data).toBe(undefined); + + response = await fetch.fetch(host_url + '/error'); + expect(response.error).toContain('Fetch error:'); + expect(response.data).toBe(undefined); +}); diff --git a/__tests__/install.test.ts b/__tests__/install.test.ts new file mode 100644 index 0000000..de2b9f4 --- /dev/null +++ b/__tests__/install.test.ts @@ -0,0 +1,87 @@ +import * as install from '../src/install'; +import * as utils from '../src/utils'; + +/** + * Mock install.ts + */ +jest.mock('../src/install', () => ({ + getScript: jest + .fn() + .mockImplementation(async (os: string): Promise => { + const filename = os + (await utils.scriptExtension(os)); + const version: string = await utils.parseVersion( + await utils.readPHPVersion() + ); + const ini_file: string = await utils.parseIniFile( + await utils.getInput('ini-file', false) + ); + const extension_csv: string = process.env['extensions'] || ''; + const ini_values_csv: string = process.env['ini-values'] || ''; + const coverage_driver: string = process.env['coverage'] || ''; + const tools_csv: string = process.env['tools'] || ''; + let script = await utils.joins(filename, version, ini_file); + script += extension_csv ? ' install extensions' : ''; + script += tools_csv ? ' add_tool' : ''; + script += coverage_driver ? ' set coverage driver' : ''; + script += ini_values_csv ? ' edit php.ini' : ''; + return script; + }), + run: jest.fn().mockImplementation(async (): Promise => { + const os: string = process.env['RUNNER_OS'] || ''; + const tool = await utils.scriptTool(os); + return tool + (await install.getScript(os)); + }) +})); + +/** + * Mock fetch.ts + */ +jest.mock('../src/fetch', () => ({ + fetch: jest.fn().mockImplementation(() => { + return { + data: '{ "latest": "8.3", "lowest": "8.1", "highest": "8.3", "nightly": "8.4", "5.x": "5.6" }' + }; + }) +})); + +describe('Install', () => { + it.each` + version | os | extension_csv | ini_file | ini_values_csv | coverage_driver | tools | output + ${'7.3'} | ${'darwin'} | ${''} | ${'production'} | ${''} | ${''} | ${''} | ${'bash darwin.sh 7.3 production'} + ${'7.3'} | ${'darwin'} | ${'a, b'} | ${'development'} | ${'a=b'} | ${'x'} | ${''} | ${'bash darwin.sh 7.3 development install extensions set coverage driver edit php.ini'} + ${'7.4.1'} | ${'darwin'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash darwin.sh 7.4 none'} + ${'8'} | ${'darwin'} | ${''} | ${''} | ${''} | ${''} | ${''} | ${'bash darwin.sh 8.0 production'} + ${'8.0'} | ${'darwin'} | ${''} | ${'development'} | ${''} | ${''} | ${''} | ${'bash darwin.sh 8.0 development'} + ${'8.1'} | ${'darwin'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash darwin.sh 8.1 none'} + ${'7.3'} | ${'linux'} | ${''} | ${'invalid'} | ${''} | ${''} | ${''} | ${'bash linux.sh 7.3 production'} + ${'7.3'} | ${'linux'} | ${'a, b'} | ${'development'} | ${'a=b'} | ${'x'} | ${'phpunit'} | ${'bash linux.sh 7.3 development install extensions add_tool set coverage driver edit php.ini'} + ${'latest'} | ${'linux'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash linux.sh 8.3 none'} + ${'lowest'} | ${'linux'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash linux.sh 8.1 none'} + ${'highest'} | ${'linux'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash linux.sh 8.3 none'} + ${'nightly'} | ${'linux'} | ${''} | ${'none'} | ${''} | ${''} | ${''} | ${'bash linux.sh 8.4 none'} + ${'7.0'} | ${'win32'} | ${''} | ${'production'} | ${''} | ${''} | ${''} | ${'pwsh win32.ps1 7.0 production'} + ${'7.3'} | ${'win32'} | ${''} | ${'development'} | ${''} | ${''} | ${''} | ${'pwsh win32.ps1 7.3 development'} + ${'7.3'} | ${'win32'} | ${'a, b'} | ${'none'} | ${'a=b'} | ${'x'} | ${''} | ${'pwsh win32.ps1 7.3 none install extensions set coverage driver edit php.ini'} + `( + 'Test install on $os for $version with extensions=$extension_csv, ini_values=$ini_values_csv, coverage_driver=$coverage_driver, tools=$tools', + async ({ + version, + os, + extension_csv, + ini_file, + ini_values_csv, + coverage_driver, + tools, + output + }) => { + process.env['php-version'] = version.toString(); + process.env['RUNNER_OS'] = os; + process.env['extensions'] = extension_csv; + process.env['ini-file'] = ini_file; + process.env['ini-values'] = ini_values_csv; + process.env['coverage'] = coverage_driver; + process.env['tools'] = tools; + expect(await install.run()).toBe(output); + } + ); +}); diff --git a/__tests__/packagist.test.ts b/__tests__/packagist.test.ts new file mode 100644 index 0000000..fac6b0a --- /dev/null +++ b/__tests__/packagist.test.ts @@ -0,0 +1,50 @@ +import * as packagist from '../src/packagist'; +import nock from 'nock'; + +describe('search function', () => { + const mockResponse = { + packages: { + 'test-package': [ + { + require: { + php: '8.0.0' + }, + version: '1.0.0' + }, + { + version: '2.0.0' + } + ] + } + }; + + test('should return the version if matching php version is found', async () => { + nock('https://repo.packagist.org') + .get('/p2/test-package.json') + .reply(200, mockResponse); + const result = await packagist.search('test-package', '8.0'); + expect(result).toBe('1.0.0'); + }); + + test('should return null if no matching php version is found', async () => { + nock('https://repo.packagist.org') + .get('/p2/test-package.json') + .reply(200, mockResponse); + const result = await packagist.search('test-package', '5.6'); + expect(result).toBeNull(); + }); + + test('should return null if fetch fails', async () => { + nock('https://repo.packagist.org').get('/p2/test-package.json').reply(404); + const result = await packagist.search('test-package', '8.0'); + expect(result).toBeNull(); + }); + + test('should return null if the response is empty', async () => { + nock('https://repo.packagist.org') + .get('/p2/test-package.json') + .reply(200, {error: true, data: '[]'}); + const result = await packagist.search('test-package', '8.0'); + expect(result).toBeNull(); + }); +}); diff --git a/__tests__/tools.test.ts b/__tests__/tools.test.ts new file mode 100644 index 0000000..1c63eda --- /dev/null +++ b/__tests__/tools.test.ts @@ -0,0 +1,715 @@ +import * as fs from 'fs'; +import * as tools from '../src/tools'; +import {ToolData, ToolInput} from '../src/tools'; + +function getData(data: Partial): ToolData { + const tool = data.tool || 'tool'; + const version = data.version || ''; + return { + tool, + version, + url: data.url || '', + domain: data.domain || 'https://example.com', + extension: data.extension || '.phar', + os: data.os || 'linux', + php_version: data.php_version || '7.4', + release: data.release || [tool, version].join(':'), + repository: data.repository || '', + scope: data.scope || 'global', + type: data.type || 'phar', + fetch_latest: data.fetch_latest || 'false', + version_parameter: data.version_parameter || '-V', + version_prefix: data.version_prefix || '', + github: data.github || 'https://github.com', + prefix: data.prefix || 'releases', + verb: data.verb || 'download', + packagist: data.packagist || data.repository || '', + function: data.function, + alias: data.alias, + uri: data.uri, + error: data.error + }; +} + +/** + * Mock fetch.ts + */ +jest.mock('../src/fetch', () => ({ + fetch: jest + .fn() + .mockImplementation( + async (url: string, token?: string): Promise> => { + if (url.includes('deployer')) { + return { + data: '[{"version": "1.2.3", "url": "https://deployer.org/releases/v1.2.3/deployer.phar"}]' + }; + } else if (url.includes('atom') && !url.includes('no-')) { + return { + data: '"releases/tag/1.2.3", "releases/tag/3.2.1", "releases/tag/2.3.1"' + }; + } else if (url.includes('no-data')) { + return {}; + } else if (url.includes('no-release')) { + return {data: 'no-release'}; + } else if (!token || token === 'valid_token') { + return {data: `[{"ref": "refs/tags/1.2.3", "url": "${url}"}]`}; + } else if (token === 'beta_token') { + return {data: `[{"ref": "refs/tags/1.2.3beta1", "url": "${url}"}]`}; + } else if (token === 'rc_token') { + return { + data: `[{"ref":"refs/tags/3.0.0RC1"},{"ref":"refs/tags/3.0.0RC2"}]` + }; + } else if (token === 'non_semver_tags') { + return { + data: `[{"ref":"refs/tags/release-2025-09-18"},{"ref":"refs/tags/release-2025-09-17"}]` + }; + } else if (token === 'undefined_ref') { + return { + data: `[{"url":"${url}"},{"ref":"refs/tags/v1.2.4","url":"${url}"}]` + }; + } else if (token === 'multi_refs') { + return { + data: `[{"ref":"refs/tags/v1.2.3","url":"${url}"},{"ref":"refs/tags/1.2.4","url":"${url}"}]` + }; + } else if (token === 'no_data') { + return {data: '[]'}; + } else { + return {error: 'Invalid token'}; + } + } + ) +})); + +jest.mock('../src/packagist', () => ({ + search: jest + .fn() + .mockImplementation( + async ( + package_name: string, + php_version: string + ): Promise => { + if (package_name === 'phpunit/phpunit') { + return php_version + '.0'; + } + return null; + } + ) +})); + +describe('Tools tests', () => { + it.each` + token | version + ${'invalid_token'} | ${'1.2'} + ${'valid_token'} | ${'1.2.3'} + ${'beta_token'} | ${'1.2.3beta1'} + ${'undefined_ref'} | ${'1.2.4'} + ${'multi_refs'} | ${'1.2.4'} + ${'non_semver_tags'} | ${'release-2025-09-18'} + ${''} | ${'1.2.3'} + `('checking getSemverVersion: $token', async ({token, version}) => { + process.env['GITHUB_TOKEN'] = token; + expect( + await tools.getSemverVersion(getData({tool: 'tool', version: '1.2'})) + ).toBe(version); + }); + + it('checking getSemverVersion triggers ?? fallback via Map#get mock', async () => { + process.env['GITHUB_TOKEN'] = 'rc_token'; + const spy = jest + .spyOn(Map.prototype as Map, 'get') + .mockImplementation(function ( + this: Map, + key: string + ): string | undefined { + if (key === '3.0.0-RC2') { + return undefined; + } + return Map.prototype.get.call(this, key); + }); + const result = await tools.getSemverVersion( + getData({tool: 'tool', version: '3.0.0'}) + ); + expect(result).toBe('3.0.0-RC2'); + spy.mockRestore(); + }); + + it.each` + tool | fetch_latest | version + ${'tool'} | ${'true'} | ${'3.2.1'} + ${'tool-no-data'} | ${'true'} | ${'latest'} + ${'tool-no-release'} | ${'true'} | ${'latest'} + ${'tool'} | ${'false'} | ${'latest'} + `( + 'checking getLatestVersion: $tool, $fetch_latest, $version', + async ({tool, fetch_latest, version}) => { + expect( + await tools.getLatestVersion( + getData({ + tool: tool, + repository: 'user/' + tool, + fetch_latest: fetch_latest + }) + ) + ).toBe(version); + } + ); + + it('checking getLatestVersion with fetch_latest=true but no repository', async () => { + expect( + await tools.getLatestVersion( + getData({ + tool: 'tool', + repository: '', + fetch_latest: 'true' + }) + ) + ).toBe('latest'); + }); + + it.each` + version | tool | type | expected + ${'latest'} | ${'tool'} | ${'phar'} | ${'latest'} + ${'1'} | ${'composer'} | ${'phar'} | ${'1'} + ${'1.2'} | ${'tool'} | ${'composer'} | ${'1.2.*'} + ${'^1.2.3'} | ${'tool'} | ${'phar'} | ${'1.2.3'} + ${'>=1.2.3'} | ${'tool'} | ${'phar'} | ${'1.2.3'} + ${'>1.2.3'} | ${'tool'} | ${'phar'} | ${'1.2.3'} + ${'1.2.3-ALPHA'} | ${'tool'} | ${'phar'} | ${'1.2.3-ALPHA'} + ${'1.2.3-alpha'} | ${'tool'} | ${'phar'} | ${'1.2.3-alpha'} + ${'1.2.3-beta'} | ${'tool'} | ${'phar'} | ${'1.2.3-beta'} + ${'1.2.3-rc'} | ${'tool'} | ${'phar'} | ${'1.2.3-rc'} + ${'1.2.3-dev'} | ${'tool'} | ${'phar'} | ${'1.2.3-dev'} + ${'1.2.3-alpha1'} | ${'tool'} | ${'phar'} | ${'1.2.3-alpha1'} + ${'1.2.3-alpha.1'} | ${'tool'} | ${'phar'} | ${'1.2.3-alpha.1'} + `( + 'checking getVersion: $version, $tool, $type', + async ({version, tool, type, expected}) => { + expect( + await tools.getVersion( + version, + getData({tool: tool, version: version, type: type}) + ) + ).toBe(expected); + } + ); + + it.each` + input | expected + ${'tool'} | ${'tool'} + ${'alias:1.2.3'} | ${'tool:1.2.3'} + ${'tool:1.2.3'} | ${'tool:1.2.3'} + ${'tool:^1.2.3'} | ${'tool:^1.2.3'} + ${'tool:>=1.2.3'} | ${'tool:>=1.2.3'} + ${'tool:>1.2.3'} | ${'tool:>1.2.3'} + ${'tool:1.2.3-ALPHA'} | ${'tool:1.2.3-ALPHA'} + ${'tool:1.2.3-beta'} | ${'tool:1.2.3-beta'} + ${'tool:1.2.3-rc'} | ${'tool:1.2.3-rc'} + ${'tool:1.2.3-dev'} | ${'tool:1.2.3-dev'} + ${'tool:1.2.3-alpha1'} | ${'tool:1.2.3-alpha1'} + ${'tool:1.2.3-alpha.1'} | ${'tool:1.2.3-alpha.1'} + ${'user/tool:^1.2.3'} | ${'tool:^1.2.3'} + `('checking getRelease: $input', async ({input, expected}) => { + expect( + await tools.getRelease(input, getData({tool: 'tool', version: 'latest'})) + ).toBe(expected); + }); + + it.each` + input_list | filtered_list + ${'a, b'} | ${'composer, a, b'} + ${'a, b, composer'} | ${'composer, a, b'} + ${'a, b, composer:1.2.3'} | ${'composer:1.2.3, a, b'} + ${'a, b, composer:v1.2.3'} | ${'composer:1.2.3, a, b'} + ${'a, b, composer:snapshot'} | ${'composer:snapshot, a, b'} + ${'a, b, composer:preview'} | ${'composer:preview, a, b'} + ${'a, b, composer:1'} | ${'composer:1, a, b'} + ${'a, b, composer:2'} | ${'composer:2, a, b'} + ${'a, b, composer:v1'} | ${'composer:1, a, b'} + ${'a, b, composer:v2'} | ${'composer:2, a, b'} + `('checking filterList $input_list', async ({input_list, filtered_list}) => { + expect(await tools.filterList(input_list.split(', '))).toStrictEqual( + filtered_list.split(', ') + ); + }); + + it.each` + version | version_prefix | url_suffix + ${'latest'} | ${'v'} | ${'latest/download/tool.phar'} + ${'1.2.3'} | ${'v'} | ${'download/v1.2.3/tool.phar'} + ${'1.2.3'} | ${''} | ${'download/1.2.3/tool.phar'} + `( + 'checking getUrl: $version_prefix$version', + async ({version, version_prefix, url_suffix}) => { + const data = getData({ + tool: 'tool', + version: version, + version_prefix: version_prefix + }); + expect(await tools.getUrl(data)).toContain(url_suffix); + } + ); + + it('checking getUrl handles undefined version without double slash', async () => { + const data: ToolInput = { + ...getData({ + tool: 'cs2pr', + repository: 'staabm/annotate-pull-request-from-checkstyle', + domain: 'https://github.com' + }), + version: undefined + }; + data.extension = ''; + expect(await tools.getUrl(data)).toBe( + 'https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/latest/download/cs2pr' + ); + }); + + it.each` + version | version_prefix | url + ${'latest'} | ${''} | ${'https://example.com/tool.phar'} + ${'1.2.3'} | ${'v'} | ${'https://example.com/tool-v1.2.3.phar'} + `( + 'checking getPharUrl: $version_prefix$version', + async ({version, version_prefix, url}) => { + const data = getData({ + tool: 'tool', + version: version, + version_prefix: version_prefix + }); + expect(await tools.getPharUrl(data)).toBe(url); + } + ); + + it.each` + os | script + ${'linux'} | ${'add_tool https://example.com/tool.phar tool "-v"'} + ${'darwin'} | ${'add_tool https://example.com/tool.phar tool "-v"'} + ${'win32'} | ${'Add-Tool https://example.com/tool.phar tool "-v"'} + ${'openbsd'} | ${'Platform openbsd is not supported'} + `('checking addArchive: $os', async ({os, script}) => { + const data = getData({ + tool: 'tool', + version: 'latest', + version_parameter: JSON.stringify('-v'), + os: os, + url: 'https://example.com/tool.phar' + }); + expect(await tools.addArchive(data)).toContain(script); + }); + + it.each` + os | script | scope + ${'linux'} | ${'add_composer_tool tool tool:1.2.3 user/ global'} | ${'global'} + ${'darwin'} | ${'add_composer_tool tool tool:1.2.3 user/ scoped'} | ${'scoped'} + ${'win32'} | ${'Add-ComposerTool tool tool:1.2.3 user/ scoped'} | ${'scoped'} + ${'openbsd'} | ${'Platform openbsd is not supported'} | ${'global'} + `('checking addPackage: $os, $scope', async ({os, script, scope}) => { + const data = getData({ + tool: 'tool', + version: '1.2.3', + repository: 'user/tool', + os: os, + scope: scope + }); + data['release'] = [data['tool'], data['version']].join(':'); + expect(await tools.addPackage(data)).toContain(script); + }); + + it.each` + version | php_version | os | script + ${'latest'} | ${'8.0'} | ${'linux'} | ${'add_tool https://github.com/phar-io/phive/releases/download/3.2.1/phive-3.2.1.phar phive'} + ${'1.2.3'} | ${'8.0'} | ${'darwin'} | ${'add_tool https://github.com/phar-io/phive/releases/download/1.2.3/phive-1.2.3.phar phive'} + ${'1.2.3'} | ${'7.4'} | ${'win32'} | ${'Add-Tool https://github.com/phar-io/phive/releases/download/0.15.3/phive-0.15.3.phar phive'} + ${'1.2.3'} | ${'7.2'} | ${'win32'} | ${'Add-Tool https://github.com/phar-io/phive/releases/download/0.14.5/phive-0.14.5.phar phive'} + ${'1.2.3'} | ${'7.1'} | ${'win32'} | ${'Add-Tool https://github.com/phar-io/phive/releases/download/0.13.5/phive-0.13.5.phar phive'} + ${'latest'} | ${'5.6'} | ${'win32'} | ${'Add-Tool https://github.com/phar-io/phive/releases/download/0.12.1/phive-0.12.1.phar phive'} + ${'latest'} | ${'5.5'} | ${'win32'} | ${'Phive is not supported on PHP 5.5'} + `( + 'checking addPhive: $version, $php_version, $os', + async ({version, php_version, os, script}) => { + const data = getData({ + tool: 'phive', + repository: 'phar-io/phive', + version_parameter: 'status', + version: version, + php_version: php_version, + os: os + }); + script = await tools.addPhive(data); + expect(script).toContain(script); + } + ); + + it.each` + os | version | php_version | url + ${'linux'} | ${'latest'} | ${'8.1'} | ${'https://get.blackfire.io/blackfire-player.phar'} + ${'linux'} | ${'1.2.3'} | ${'7.4'} | ${'https://get.blackfire.io/blackfire-player-v1.2.3.phar'} + ${'linux'} | ${'latest'} | ${'7.4'} | ${'https://get.blackfire.io/blackfire-player-v1.22.0.phar'} + ${'linux'} | ${'latest'} | ${'5.5'} | ${'https://get.blackfire.io/blackfire-player-v1.9.3.phar'} + ${'linux'} | ${'latest'} | ${'7.0'} | ${'https://get.blackfire.io/blackfire-player-v1.9.3.phar'} + ${'win32'} | ${'latest'} | ${'7.0'} | ${'blackfire-player is not a windows tool'} + `( + 'checking addBlackfirePlayer: $os, $version, $php_version', + async ({os, version, php_version, url}) => { + const data = getData({ + os: os, + tool: 'blackfire-player', + domain: 'https://get.blackfire.io', + version_prefix: 'v', + version: version, + php_version: php_version + }); + expect(await tools.addBlackfirePlayer(data)).toContain(url); + } + ); + + it.each` + version | url + ${'latest'} | ${'https://deployer.org/deployer.phar'} + ${'1.2.3'} | ${'https://deployer.org/releases/v1.2.3/deployer.phar'} + ${'3.2.1'} | ${'Version missing in deployer manifest'} + `('checking addDeployer: $version', async ({version, url}) => { + const data = getData({ + tool: 'deployer', + domain: 'https://deployer.org', + version: version + }); + expect(await tools.addDeployer(data)).toContain(url); + }); + + it.each` + version | php_version | no_tool_cache | cache_url | source_url + ${'latest'} | ${'7.4'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'stable'} | ${'7.4'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'snapshot'} | ${'7.4'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-snapshot.phar'} | ${'https://getcomposer.org/composer.phar'} + ${'preview'} | ${'7.4'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-preview.phar'} | ${'https://getcomposer.org/composer-preview.phar'} + ${'1'} | ${'7.4'} | ${'false'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-1.phar'} | ${'https://getcomposer.org/composer-1.phar'} + ${'2'} | ${'7.4'} | ${'false'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-2.phar'} | ${'https://getcomposer.org/composer-2.phar'} + ${'latest'} | ${'7.4'} | ${'true'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'stable'} | ${'7.4'} | ${'true'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'snapshot'} | ${'7.4'} | ${'true'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-snapshot.phar'} | ${'https://getcomposer.org/composer.phar'} + ${'preview'} | ${'7.4'} | ${'true'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-preview.phar'} | ${'https://getcomposer.org/composer-preview.phar'} + ${'1'} | ${'7.4'} | ${'false'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-1.phar'} | ${'https://getcomposer.org/composer-1.phar'} + ${'2'} | ${'7.4'} | ${'false'} | ${'https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-2.phar'} | ${'https://getcomposer.org/composer-2.phar'} + ${'latest'} | ${'7.4'} | ${'true'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'stable'} | ${'7.4'} | ${'true'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-stable.phar'} | ${'https://getcomposer.org/composer-stable.phar'} + ${'snapshot'} | ${'7.4'} | ${'true'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-snapshot.phar'} | ${'https://getcomposer.org/composer.phar'} + ${'preview'} | ${'7.4'} | ${'true'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-preview.phar'} | ${'https://getcomposer.org/composer-preview.phar'} + ${'1'} | ${'7.4'} | ${'false'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-1.phar'} | ${'https://getcomposer.org/composer-1.phar'} + ${'2'} | ${'7.4'} | ${'false'} | ${'https://artifacts.setup-php.com/composer/composer-7.4-2.phar'} | ${'https://getcomposer.org/composer-2.phar'} + ${'latest'} | ${'7.1'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-stable.phar'} | ${'https://getcomposer.org/download/latest-2.2.x/composer.phar'} + ${'stable'} | ${'7.1'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-stable.phar'} | ${'https://getcomposer.org/download/latest-2.2.x/composer.phar'} + ${'snapshot'} | ${'7.1'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-snapshot.phar'} | ${'https://getcomposer.org/download/latest-2.2.x/composer.phar'} + ${'preview'} | ${'7.1'} | ${'true'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-preview.phar'} | ${'https://getcomposer.org/download/latest-2.2.x/composer.phar'} + ${'1'} | ${'7.1'} | ${'false'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-1.phar'} | ${'https://getcomposer.org/composer-1.phar'} + ${'2'} | ${'7.1'} | ${'false'} | ${'https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.1-2.phar'} | ${'https://getcomposer.org/download/latest-2.2.x/composer.phar'} + ${'1.2.3'} | ${'7.4'} | ${'false'} | ${'https://github.com/composer/composer/releases/download/1.2.3/composer.phar'} | ${'https://getcomposer.org/download/1.2.3/composer.phar'} + ${'1.2.3-RC1'} | ${'7.4'} | ${'false'} | ${'https://github.com/composer/composer/releases/download/1.2.3-RC1/composer.phar'} | ${'https://getcomposer.org/download/1.2.3-RC1/composer.phar'} + `( + 'checking addComposer: $version, $php_version, $no_tool_cache', + async ({version, php_version, no_tool_cache, cache_url, source_url}) => { + const data = getData({ + tool: 'composer', + php_version: php_version, + domain: 'https://getcomposer.org', + repository: 'composer/composer', + version: version + }); + process.env['no_tools_cache'] = no_tool_cache; + expect(await tools.addComposer(data)).toContain(source_url); + if (no_tool_cache !== 'true') { + expect(await tools.addComposer(data)).toContain(cache_url); + } + } + ); + + it.each` + version | uri + ${'latest'} | ${'wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true'} + ${'1.2.3'} | ${'wp-cli/wp-cli/releases/download/v1.2.3/wp-cli-1.2.3.phar'} + `('checking addWPCLI: $version', async ({version, uri}) => { + const data = getData({ + tool: 'wp-cli', + repository: 'wp-cli/wp-cli', + php_version: '7.4', + version_prefix: 'v', + version: version + }); + expect(await tools.addWPCLI(data)).toContain(uri); + }); + + it.each` + tool | os | script + ${'phpize'} | ${'linux'} | ${'add_devtools phpize'} + ${'php-config'} | ${'linux'} | ${'add_devtools php-config'} + ${'phpize'} | ${'darwin'} | ${'add_devtools phpize'} + ${'php-config'} | ${'darwin'} | ${'add_devtools php-config'} + ${'phpize'} | ${'win32'} | ${'Add-Log "$tick" "phpize" "phpize is not a windows tool"'} + ${'php-config'} | ${'win32'} | ${'Add-Log "$tick" "php-config" "php-config is not a windows tool"'} + ${'phpize'} | ${'openbsd'} | ${'Platform openbsd is not supported'} + `('checking addDevTools: $tool, $os', async ({tool, os, script}) => { + const data = getData({ + version: '7.4', + tool: tool, + os: os + }); + expect(await tools.addDevTools(data)).toContain(script); + }); + + it.each([ + [ + 'blackfire, blackfire-player, box, churn, cs2pr, flex, grpc_php_plugin, mago, name-collision-detector, parallel-lint, php-cs-fixer, php-scoper, phpDocumentor, phplint, phpstan, phpunit, pecl, phing, phinx, phinx:1.2.3, phive, phpunit-bridge, phpunit-polyfills, pint, php-config, phpize, protoc, symfony, vapor, wp, pie', + [ + 'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar,https://artifacts.setup-php.com/composer/composer-7.4-stable.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar,https://getcomposer.org/composer-stable.phar composer', + 'add_blackfire', + 'add_tool https://get.blackfire.io/blackfire-player-v1.22.0.phar blackfire-player "-V"', + 'add_tool https://github.com/box-project/box/releases/latest/download/box.phar box "--version"', + 'add_tool https://github.com/bmitch/churn-php/releases/latest/download/churn.phar churn "-V"', + 'add_tool https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/latest/download/cs2pr cs2pr "-V"', + 'add_composer_tool flex flex symfony/ global', + 'add_grpc_php_plugin latest', + 'add_mago', + 'add_composer_tool name-collision-detector name-collision-detector shipmonk/ scoped', + 'add_tool https://github.com/php-parallel-lint/PHP-Parallel-Lint/releases/latest/download/parallel-lint.phar parallel-lint "--version"', + 'add_tool https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases/download/v3.2.1/php-cs-fixer.phar php-cs-fixer "-V"', + 'add_tool https://github.com/humbug/php-scoper/releases/latest/download/php-scoper.phar php-scoper "--version"', + 'add_tool https://github.com/phpDocumentor/phpDocumentor/releases/latest/download/phpDocumentor.phar phpDocumentor "--version"', + 'add_composer_tool phplint phplint overtrue/', + 'add_tool https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar phpstan "-V"', + 'add_tool https://phar.phpunit.de/phpunit-7.4.0.phar,https://phar.phpunit.de/phpunit-7.phar phpunit "--version"', + 'add_pecl', + 'add_tool https://www.phing.info/get/phing-latest.phar phing "-v"', + 'add_composer_tool phinx phinx robmorgan/ scoped', + 'add_composer_tool phinx phinx:1.2.3 robmorgan/ scoped', + 'add_tool https://github.com/phar-io/phive/releases/download/0.15.3/phive-0.15.3.phar phive "status"', + 'add_composer_tool phpunit-bridge phpunit-bridge symfony/ global', + 'add_composer_tool phpunit-polyfills phpunit-polyfills yoast/ global', + 'add_tool https://github.com/laravel/pint/releases/latest/download/pint.phar pint "-V"', + 'add_devtools php-config', + 'add_devtools phpize', + 'add_protoc latest', + 'add_symfony latest', + 'add_composer_tool vapor-cli vapor-cli laravel/ scoped', + 'add_tool https://github.com/wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true wp-cli "--version"', + 'add_tool https://github.com/php/pie/releases/latest/download/pie.phar pie "-V"' + ] + ] + ])('checking addTools on linux', async (tools_csv, scripts) => { + const expected = await tools.addTools(tools_csv, '7.4', 'linux'); + scripts.forEach(script => { + expect(expected).toContain(script); + }); + }); + + it.each([ + [ + 'backward-compatibility-check, behat, blackfire, blackfire-player, churn, composer-dependency-analyser, composer-normalize, composer-require-checker, composer-unused, cs2pr:1.2.3, ecs, flex, grpc_php_plugin:1.2.3, infection, mago:0.26.1, name-collision-detector, phan, phan:1.2.3, phing:1.2.3, phinx, phive:1.2.3, php-config, phpcbf, phpcpd, phpcs, phpdoc, phpize, phpmd, phpspec, phpunit-bridge:5.6, phpunit-polyfills:1.0.1, protoc:v1.2.3, psalm, rector, symfony-cli, vapor-cli, wp-cli, pie', + [ + 'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar,https://artifacts.setup-php.com/composer/composer-7.4-stable.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar,https://getcomposer.org/composer-stable.phar composer', + 'add_composer_tool behat behat behat/ scoped', + 'add_blackfire', + 'add_tool https://get.blackfire.io/blackfire-player-v1.22.0.phar blackfire-player "-V"', + 'add_tool https://github.com/bmitch/churn-php/releases/latest/download/churn.phar churn "-V"', + 'add_tool https://github.com/ergebnis/composer-normalize/releases/latest/download/composer-normalize.phar composer-normalize "diagnose"', + 'add_composer_tool composer-dependency-analyser composer-dependency-analyser shipmonk/ scoped', + 'add_composer_tool composer-require-checker composer-require-checker maglnet/ scoped', + 'add_tool https://github.com/composer-unused/composer-unused/releases/latest/download/composer-unused.phar composer-unused "-V"', + 'add_tool https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/download/1.2.3/cs2pr cs2pr "-V"', + 'add_composer_tool flex flex symfony/ global', + 'add_grpc_php_plugin 1.2.3', + 'add_tool https://github.com/infection/infection/releases/latest/download/infection.phar infection "-V"', + 'add_mago 0.26.1', + 'add_composer_tool name-collision-detector name-collision-detector shipmonk/ scoped', + 'add_tool https://github.com/phan/phan/releases/latest/download/phan.phar phan "-v"', + 'add_tool https://github.com/phan/phan/releases/download/1.2.3/phan.phar phan "-v"', + 'add_tool https://www.phing.info/get/phing-1.2.3.phar,https://github.com/phingofficial/phing/releases/download/1.2.3/phing-1.2.3.phar phing "-v"', + 'add_composer_tool phinx phinx robmorgan/ scoped', + 'add_tool https://github.com/phar-io/phive/releases/download/0.15.3/phive-0.15.3.phar phive', + 'add_devtools php-config', + 'add_tool https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/latest/download/phpcbf.phar phpcbf "--version"', + 'add_tool https://phar.phpunit.de/phpcpd.phar phpcpd "--version"', + 'add_tool https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/latest/download/phpcs.phar phpcs "--version"', + 'add_tool https://github.com/phpDocumentor/phpDocumentor/releases/latest/download/phpDocumentor.phar phpDocumentor "--version"', + 'add_devtools phpize', + 'add_tool https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar phpmd "--version"', + 'add_tool https://github.com/phpspec/phpspec/releases/latest/download/phpspec.phar phpspec "-V"', + 'add_composer_tool phpunit-bridge phpunit-bridge:5.6.* symfony/ global', + 'add_composer_tool phpunit-polyfills phpunit-polyfills:1.0.1 yoast/ global', + 'add_protoc 1.2.3', + 'add_tool https://github.com/vimeo/psalm/releases/latest/download/psalm.phar psalm "-v"', + 'add_composer_tool rector rector rector/ scoped', + 'add_composer_tool backward-compatibility-check backward-compatibility-check roave/ scoped', + 'add_symfony latest', + 'add_composer_tool vapor-cli vapor-cli laravel/ scoped', + 'add_tool https://github.com/wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true wp-cli "--version"', + 'add_composer_tool easy-coding-standard easy-coding-standard symplify/ scoped', + 'add_tool https://github.com/php/pie/releases/latest/download/pie.phar pie "-V"' + ] + ] + ])('checking addTools on darwin', async (tools_csv, scripts) => { + const expected = await tools.addTools(tools_csv, '7.4', 'darwin'); + scripts.forEach(script => { + expect(expected).toContain(script); + }); + }); + + it.each([ + [ + 'blackfire, blackfire-player:1.2.3, cs2pr, churn, deployer, does_not_exist, flex, mago, name-collision-detector, phinx, phive:0.13.2, php-config, phpize, phpmd, simple-phpunit, symfony, wp, pie', + [ + 'Add-Tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar,https://artifacts.setup-php.com/composer/composer-7.4-stable.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar,https://getcomposer.org/composer-stable.phar composer', + 'Add-Blackfire', + 'blackfire-player is not a windows tool', + 'Add-Tool https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/latest/download/cs2pr cs2pr "-V"', + 'Add-Tool https://github.com/bmitch/churn-php/releases/latest/download/churn.phar churn "-V"', + 'Add-Tool https://deployer.org/deployer.phar deployer "-V"', + 'Tool does_not_exist is not supported', + 'Add-ComposerTool flex flex symfony/ global', + 'Add-Mago', + 'Add-ComposerTool name-collision-detector name-collision-detector shipmonk/ scoped', + 'Add-ComposerTool phinx phinx robmorgan/ scoped', + 'Add-Tool https://github.com/phar-io/phive/releases/download/0.15.3/phive-0.15.3.phar phive "status"', + 'php-config is not a windows tool', + 'phpize is not a windows tool', + 'Add-Tool https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar phpmd "--version"', + 'Add-ComposerTool phpunit-bridge phpunit-bridge symfony/ global', + 'Add-Symfony', + 'Add-Tool https://github.com/wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true wp-cli "--version"', + 'Add-Tool https://github.com/php/pie/releases/latest/download/pie.phar pie "-V"' + ] + ] + ])('checking addTools on Windows', async (tools_csv, scripts) => { + const expected = await tools.addTools(tools_csv, '7.4', 'win32'); + scripts.forEach(script => { + expect(expected).toContain(script); + }); + }); + + it.each([ + [ + 'composer:v1, codeception/codeception, prestissimo, hirak/prestissimo, composer-prefetcher, narrowspark/automatic-composer-prefetcher, phinx: 1.2, robmorgan/phinx: ^1.2, user/tool:1.2.3, user/tool:~1.2', + [ + 'Add-Tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-1.phar,https://artifacts.setup-php.com/composer/composer-7.4-1.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-1.phar,https://getcomposer.org/composer-1.phar composer', + 'Add-ComposerTool codeception codeception codeception/ global', + 'Add-ComposerTool prestissimo prestissimo hirak/ global', + 'Add-ComposerTool automatic-composer-prefetcher automatic-composer-prefetcher narrowspark/ global', + 'Add-ComposerTool phinx phinx:1.2.* robmorgan/ scoped', + 'Add-ComposerTool phinx phinx:^1.2 robmorgan/ global', + 'Add-ComposerTool tool tool:1.2.3 user/ global', + 'Add-ComposerTool tool tool:~1.2 user/ global' + ] + ] + ])( + 'checking addTools with composer tool using user/tool as input', + async (tools_csv, scripts) => { + const expected = await tools.addTools(tools_csv, '7.4', 'win32'); + scripts.forEach(script => { + expect(expected).toContain(script); + }); + } + ); + + it.each` + version | os | uri + ${'latest'} | ${'linux'} | ${'releases/latest/download/castor.linux-amd64.phar'} + ${'0.5.1'} | ${'linux'} | ${'releases/download/v0.5.1/castor.linux-amd64.phar'} + ${'latest'} | ${'darwin'} | ${'releases/latest/download/castor.darwin-amd64.phar'} + ${'0.5.1'} | ${'darwin'} | ${'releases/download/v0.5.1/castor.darwin-amd64.phar'} + ${'latest'} | ${'win32'} | ${'releases/latest/download/castor.windows-amd64.phar'} + ${'0.5.1'} | ${'win32'} | ${'releases/download/v0.5.1/castor.windows-amd64.phar castor -V'} + ${'latest'} | ${'openbsd'} | ${'Platform openbsd is not supported'} + `('checking addCastor: $version, $os', async ({version, os, uri}) => { + const data = getData({ + tool: 'castor', + php_version: '8.1', + version_prefix: 'v', + version: version, + os: os + }); + if (os === 'win32' && version === '0.5.1') { + fs.writeFileSync('castor.php', ''); + expect(await tools.addCastor(data)).toContain(uri); + fs.unlinkSync('castor.php'); + } else { + expect(await tools.addCastor(data)).toContain(uri); + } + }); + + it.each` + tools_csv | script + ${'none'} | ${''} + ${'none, phpunit'} | ${'\nstep_log "Setup Tools"\nadd_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-stable.phar,https://artifacts.setup-php.com/composer/composer-7.4-stable.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-stable.phar,https://getcomposer.org/composer-stable.phar composer latest\n\nadd_tool https://phar.phpunit.de/phpunit-7.4.0.phar,https://phar.phpunit.de/phpunit-7.phar phpunit "--version"'} + ${'composer:preview'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-preview.phar,https://artifacts.setup-php.com/composer/composer-7.4-preview.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-preview.phar,https://getcomposer.org/composer-preview.phar composer preview'} + ${'composer, composer:v1'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-1.phar,https://artifacts.setup-php.com/composer/composer-7.4-1.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-1.phar,https://getcomposer.org/composer-1.phar composer'} + ${'composer:v1, composer:preview, composer:snapshot'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-snapshot.phar,https://artifacts.setup-php.com/composer/composer-7.4-snapshot.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-snapshot.phar,https://getcomposer.org/composer.phar composer snapshot'} + `('checking composer setup: $tools_csv', async ({tools_csv, script}) => { + expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script); + }); + + it.each` + tools_csv | token | script + ${'cs2pr:1.2'} | ${'invalid_token'} | ${'add_log "$cross" "cs2pr" "Invalid token"'} + ${'phpunit:1.2'} | ${'invalid_token'} | ${'add_log "$cross" "phpunit" "Invalid token"'} + ${'phpunit:0.1'} | ${'no_data'} | ${'add_log "$cross" "phpunit" "No version found with prefix 0.1."'} + `('checking error: $tools_csv', async ({tools_csv, token, script}) => { + process.env['GITHUB_TOKEN'] = token; + expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script); + }); + + it('checking error when custom-function tool is missing function field', async () => { + const brokenToolsJson = JSON.stringify({ + composer: { + type: 'custom-function', + domain: 'https://getcomposer.org', + repository: 'composer/composer', + function: 'composer' + }, + 'broken-tool': { + type: 'custom-function' + } + }); + + let result: string = ''; + await jest.isolateModulesAsync(async () => { + jest.doMock('fs', () => ({ + ...jest.requireActual('fs'), + readFileSync: ( + filePath: fs.PathOrFileDescriptor, + options?: unknown + ) => { + if (String(filePath).includes('tools.json')) { + return brokenToolsJson; + } + return (jest.requireActual('fs') as typeof fs).readFileSync( + filePath, + options as fs.ObjectEncodingOptions & {flag?: string} + ); + } + })); + const isolatedTools = await import('../src/tools'); + result = await isolatedTools.addTools('broken-tool', '7.4', 'linux'); + }); + + expect(result).toContain( + 'add_log "$cross" "broken-tool" "broken-tool has no function defined. Please report this issue."' + ); + }); + + it.each` + tools_csv | php_version | resolved + ${'phpunit'} | ${'8.2'} | ${'/phpunit-8.2.0.phar'} + ${'phpunit'} | ${'8.1'} | ${'/phpunit-8.1.0.phar'} + ${'phpunit'} | ${'8.0'} | ${'/phpunit-8.0.0.phar'} + ${'phpunit'} | ${'7.3'} | ${'/phpunit-7.3.0.phar'} + ${'phpunit'} | ${'7.2'} | ${'/phpunit-7.2.0.phar'} + ${'phpunit'} | ${'7.1'} | ${'/phpunit-7.1.0.phar'} + ${'phpunit'} | ${'7.0'} | ${'/phpunit-7.0.0.phar'} + `( + 'checking error: $tools_csv', + async ({tools_csv, php_version, resolved}) => { + expect(await tools.addTools(tools_csv, php_version, 'linux')).toContain( + resolved + ); + } + ); +}); diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts new file mode 100644 index 0000000..0631b55 --- /dev/null +++ b/__tests__/utils.test.ts @@ -0,0 +1,323 @@ +import fs from 'fs'; +import * as path from 'path'; +import * as utils from '../src/utils'; +import * as fetchModule from '../src/fetch'; + +describe('Utils tests', () => { + it('checking readEnv', async () => { + process.env['test'] = 'setup-php'; + process.env['test-hyphen'] = 'setup-php'; + expect(await utils.readEnv('test')).toBe('setup-php'); + expect(await utils.readEnv('TEST')).toBe('setup-php'); + expect(await utils.readEnv('test_hyphen')).toBe('setup-php'); + expect(await utils.readEnv('TEST_HYPHEN')).toBe('setup-php'); + expect(await utils.readEnv('undefined')).toBe(''); + }); + + it('checking getInput', async () => { + process.env['test'] = 'setup-php'; + process.env['INPUT_SETUP-PHP'] = 'setup-php'; + expect(await utils.getInput('test', false)).toBe('setup-php'); + expect(await utils.getInput('setup-php', false)).toBe('setup-php'); + expect(await utils.getInput('DoesNotExist', false)).toBe(''); + await expect(async () => { + await utils.getInput('DoesNotExist', true); + }).rejects.toThrow('Input required and not supplied: DoesNotExist'); + delete process.env['INPUT_SETUP-PHP']; + }); + + it('checking getManifestURL', async () => { + for (const url of await utils.getManifestURLS()) { + expect(url).toContain('php-versions.json'); + } + }); + + it('checking parseVersion', async () => { + const fetchSpy = jest + .spyOn(fetchModule, 'fetch') + .mockResolvedValue({data: '{ "latest": "8.1", "5.x": "5.6" }'}); + expect(await utils.parseVersion('latest')).toBe('8.1'); + expect(await utils.parseVersion('7')).toBe('7.0'); + expect(await utils.parseVersion('7.4')).toBe('7.4'); + expect(await utils.parseVersion('5.x')).toBe('5.6'); + expect(await utils.parseVersion('4.x')).toBe(undefined); + + fetchSpy.mockReset(); + fetchSpy.mockResolvedValueOnce({}).mockResolvedValueOnce({}); + await expect(utils.parseVersion('latest')).rejects.toThrow( + 'Could not fetch the PHP version manifest.' + ); + expect(fetchSpy).toHaveBeenCalledTimes(2); + }); + + it('checking parseIniFile', async () => { + expect(await utils.parseIniFile('production')).toBe('production'); + expect(await utils.parseIniFile('development')).toBe('development'); + expect(await utils.parseIniFile('none')).toBe('none'); + expect(await utils.parseIniFile('php.ini-production')).toBe('production'); + expect(await utils.parseIniFile('php.ini-development')).toBe('development'); + expect(await utils.parseIniFile('invalid')).toBe('production'); + }); + + it('checking asyncForEach', async () => { + const array: Array = ['a', 'b', 'c']; + let concat = ''; + await utils.asyncForEach( + array, + async function (str: string): Promise { + concat += str; + } + ); + expect(concat).toBe('abc'); + }); + + it('checking asyncForEach', async () => { + expect(await utils.color('error')).toBe('31'); + expect(await utils.color('success')).toBe('32'); + expect(await utils.color('any')).toBe('32'); + expect(await utils.color('warning')).toBe('33'); + }); + + it('checking extensionArray', async () => { + expect( + await utils.extensionArray('a, :b, php_c, none, php-d, Zend e, :Zend f') + ).toEqual(['none', 'a', ':b', 'c', 'd', 'e', ':f']); + + expect(await utils.extensionArray('')).toEqual([]); + expect(await utils.extensionArray(' ')).toEqual([]); + + expect( + await utils.extensionArray('apcu, mbstring, \\ pdo_pgsql, posix, session') + ).toEqual(['apcu', 'mbstring', 'pdo_pgsql', 'posix', 'session']); + }); + + it('checking INIArray', async () => { + expect(await utils.CSVArray('a=1, b=2, c=3')).toEqual([ + 'a=1', + 'b=2', + 'c=3' + ]); + expect(await utils.CSVArray('\'a=1,2\', "b=3, 4", c=5, d=~e~')).toEqual([ + 'a=1,2', + 'b=3, 4', + 'c=5', + "d='~e~'" + ]); + expect(await utils.CSVArray('a=\'1,2\', b="3, 4", c=5')).toEqual([ + 'a=1,2', + 'b=3, 4', + 'c=5' + ]); + expect( + await utils.CSVArray('a=E_ALL, b=E_ALL & ~ E_ALL, c="E_ALL", d=\'E_ALL\'') + ).toEqual(['a=E_ALL', 'b=E_ALL & ~ E_ALL', 'c=E_ALL', 'd=E_ALL']); + expect( + await utils.CSVArray('a="b=c;d=e", b=\'c=d,e\', c="g=h,i=j", d=g=h, a===') + ).toEqual(["a='b=c;d=e'", "b='c=d,e'", "c='g=h,i=j'", "d='g=h'", "a='=='"]); + expect(await utils.CSVArray('')).toEqual([]); + expect(await utils.CSVArray(' ')).toEqual([]); + }); + + it('checking log', async () => { + const message = 'Test message'; + + let warning_log: string = await utils.log(message, 'win32', 'warning'); + expect(warning_log).toEqual('printf "\\033[33;1m' + message + ' \\033[0m"'); + warning_log = await utils.log(message, 'linux', 'warning'); + expect(warning_log).toEqual('echo "\\033[33;1m' + message + '\\033[0m"'); + warning_log = await utils.log(message, 'darwin', 'warning'); + expect(warning_log).toEqual('echo "\\033[33;1m' + message + '\\033[0m"'); + + let error_log: string = await utils.log(message, 'win32', 'error'); + expect(error_log).toEqual('printf "\\033[31;1m' + message + ' \\033[0m"'); + error_log = await utils.log(message, 'linux', 'error'); + expect(error_log).toEqual('echo "\\033[31;1m' + message + '\\033[0m"'); + error_log = await utils.log(message, 'darwin', 'error'); + expect(error_log).toEqual('echo "\\033[31;1m' + message + '\\033[0m"'); + + let success_log: string = await utils.log(message, 'win32', 'success'); + expect(success_log).toEqual('printf "\\033[32;1m' + message + ' \\033[0m"'); + success_log = await utils.log(message, 'linux', 'success'); + expect(success_log).toEqual('echo "\\033[32;1m' + message + '\\033[0m"'); + success_log = await utils.log(message, 'darwin', 'success'); + expect(success_log).toEqual('echo "\\033[32;1m' + message + '\\033[0m"'); + + let step_log: string = await utils.stepLog(message, 'win32'); + expect(step_log).toEqual('Step-Log "Test message"'); + step_log = await utils.stepLog(message, 'linux'); + expect(step_log).toEqual('step_log "Test message"'); + step_log = await utils.stepLog(message, 'darwin'); + expect(step_log).toEqual('step_log "Test message"'); + step_log = await utils.stepLog(message, 'openbsd'); + expect(step_log).toContain('Platform openbsd is not supported'); + + let add_log: string = await utils.addLog( + 'tick', + 'xdebug', + 'enabled', + 'win32' + ); + expect(add_log).toEqual('Add-Log "tick" "xdebug" "enabled"'); + add_log = await utils.addLog('tick', 'xdebug', 'enabled', 'linux'); + expect(add_log).toEqual('add_log "tick" "xdebug" "enabled"'); + add_log = await utils.addLog('tick', 'xdebug', 'enabled', 'darwin'); + expect(add_log).toEqual('add_log "tick" "xdebug" "enabled"'); + add_log = await utils.addLog('tick', 'xdebug', 'enabled', 'openbsd'); + expect(add_log).toContain('Platform openbsd is not supported'); + }); + + it('checking getExtensionPrefix', async () => { + expect(await utils.getExtensionPrefix('extensionDoesNotExist')).toEqual( + 'extension' + ); + expect(await utils.getExtensionPrefix('xsl')).toEqual('extension'); + expect(await utils.getExtensionPrefix('xdebug')).toEqual('zend_extension'); + expect(await utils.getExtensionPrefix('xdebug3')).toEqual('zend_extension'); + expect(await utils.getExtensionPrefix('opcache')).toEqual('zend_extension'); + }); + + it('checking suppressOutput', async () => { + expect(await utils.suppressOutput('win32')).toEqual(' >$null 2>&1'); + expect(await utils.suppressOutput('linux')).toEqual(' >/dev/null 2>&1'); + expect(await utils.suppressOutput('darwin')).toEqual(' >/dev/null 2>&1'); + expect(await utils.suppressOutput('openbsd')).toContain( + 'Platform openbsd is not supported' + ); + }); + + it('checking getUnsupportedLog', async () => { + expect(await utils.getUnsupportedLog('ext', '5.6', 'linux')).toContain( + 'add_log "$cross" "ext" "ext is not supported on PHP 5.6"' + ); + }); + + it('checking getCommand', async () => { + expect(await utils.getCommand('linux', 'tool')).toBe('add_tool '); + expect(await utils.getCommand('darwin', 'tool')).toBe('add_tool '); + expect(await utils.getCommand('win32', 'tool')).toBe('Add-Tool '); + expect(await utils.getCommand('win32', 'tool_name')).toBe('Add-ToolName '); + expect(await utils.getCommand('openbsd', 'tool')).toContain( + 'Platform openbsd is not supported' + ); + }); + + it('checking joins', async () => { + expect(await utils.joins('a', 'b', 'c')).toBe('a b c'); + }); + + it('checking scriptExtension', async () => { + expect(await utils.scriptExtension('linux')).toBe('.sh'); + expect(await utils.scriptExtension('darwin')).toBe('.sh'); + expect(await utils.scriptExtension('win32')).toBe('.ps1'); + expect(await utils.scriptExtension('openbsd')).toContain( + 'Platform openbsd is not supported' + ); + }); + + it('checking scriptTool', async () => { + expect(await utils.scriptTool('linux')).toBe('bash '); + expect(await utils.scriptTool('darwin')).toBe('bash '); + expect(await utils.scriptTool('win32')).toBe('pwsh '); + expect(await utils.scriptTool('openbsd')).toContain( + 'Platform openbsd is not supported' + ); + }); + + it('checking customPackage', async () => { + const script_path: string = path.join('ext', 'pkg.sh'); + expect(await utils.customPackage('pkg', 'ext', '1.2.3', 'linux')).toContain( + script_path + '\nadd_pkg 1.2.3' + ); + expect( + await utils.customPackage('pdo_pkg', 'ext', '1.2.3', 'linux') + ).toContain(script_path + '\nadd_pkg 1.2.3'); + expect( + await utils.customPackage('pkg8', 'ext', '1.2.3', 'linux') + ).toContain(script_path + '\nadd_pkg 1.2.3'); + }); + + it('checking parseExtensionSource', async () => { + expect( + await utils.parseExtensionSource( + 'ext-org-name/repo-name@release', + 'extension' + ) + ).toContain( + '\nadd_extension_from_source ext https://github.com org-name repo-name release extension' + ); + expect( + await utils.parseExtensionSource( + 'ext-https://sub.domain.tld/org/repo@release', + 'extension' + ) + ).toContain( + '\nadd_extension_from_source ext https://sub.domain.tld org repo release extension' + ); + expect( + await utils.parseExtensionSource( + 'ext-https://sub.domain.XN--tld/org/repo@release', + 'extension' + ) + ).toContain( + '\nadd_extension_from_source ext https://sub.domain.XN--tld org repo release extension' + ); + }); + + it('checking readPHPVersion', async () => { + expect(await utils.readPHPVersion()).toBe('latest'); + + process.env['php-version-file'] = '.phpenv-version'; + await expect(utils.readPHPVersion()).rejects.toThrow( + "Could not find '.phpenv-version' file." + ); + + const existsSync = jest.spyOn(fs, 'existsSync').mockImplementation(); + const readFileSync = jest.spyOn(fs, 'readFileSync').mockImplementation(); + + existsSync.mockReturnValue(true); + readFileSync.mockReturnValue('8.1'); + + expect(await utils.readPHPVersion()).toBe('8.1'); + + process.env['php-version'] = '8.2'; + expect(await utils.readPHPVersion()).toBe('8.2'); + + delete process.env['php-version-file']; + delete process.env['php-version']; + + existsSync.mockReturnValue(true); + readFileSync.mockReturnValue('ruby 1.2.3\nphp 8.4.2\nnode 20.1.2'); + expect(await utils.readPHPVersion()).toBe('8.4.2'); + + existsSync.mockReturnValue(true); + readFileSync.mockReturnValue('setup-php'); + expect(await utils.readPHPVersion()).toBe('setup-php'); + + existsSync.mockReturnValueOnce(false).mockReturnValueOnce(true); + readFileSync.mockReturnValue( + '{ "platform-overrides": { "php": "7.3.25" } }' + ); + expect(await utils.readPHPVersion()).toBe('7.3.25'); + + existsSync + .mockReturnValueOnce(false) + .mockReturnValueOnce(false) + .mockReturnValueOnce(true); + readFileSync.mockReturnValue( + '{ "config": { "platform": { "php": "7.4.33" } } }' + ); + expect(await utils.readPHPVersion()).toBe('7.4.33'); + + existsSync.mockClear(); + readFileSync.mockClear(); + }); + + it('checking setVariable', async () => { + let script: string = await utils.setVariable('var', 'command', 'linux'); + expect(script).toEqual('\nvar="$(command)"\n'); + script = await utils.setVariable('var', 'command', 'darwin'); + expect(script).toEqual('\nvar="$(command)"\n'); + script = await utils.setVariable('var', 'command', 'win32'); + expect(script).toEqual('\n$var = command\n'); + }); +}); diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..7fd30b5 --- /dev/null +++ b/action.yml @@ -0,0 +1,38 @@ +name: 'Setup PHP Action' +author: 'step-security' +description: 'GitHub Action for PHP' +branding: + color: 'purple' + icon: 'play-circle' +inputs: + php-version: + description: 'Setup PHP version.' + required: false + php-version-file: + description: 'Setup PHP version from a file.' + required: false + extensions: + description: 'Setup PHP extensions.' + required: false + ini-file: + description: 'Set base ini file.' + required: false + default: 'production' + ini-values: + description: 'Add values to php.ini.' + required: false + coverage: + description: 'Setup code coverage driver.' + required: false + tools: + description: 'Setup popular tools globally.' + required: false + github-token: + description: 'GitHub token to use for authentication.' + default: ${{ github.token }} +outputs: + php-version: + description: 'PHP version in semver format' +runs: + using: 'node24' + main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..ddd1ccc --- /dev/null +++ b/dist/index.js @@ -0,0 +1,15 @@ +(()=>{var e={6472:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o/dev/null 2>&1'+a}async function addINIValuesWindows(e){const t=await s.CSVArray(e);let a="\n";await s.asyncForEach(t,(async function(e){a+=await s.addLog("$tick",e,"Added to php.ini","win32")+"\n"}));return'Add-Content "$php_dir\\php.ini" "'+t.join("\n")+'"'+a}async function addINIValues(e,t,a=false){let n="\n";switch(a){case true:n+=await s.stepLog("Add php.ini values",t)+await s.suppressOutput(t)+"\n";break;case false:default:n+=await s.stepLog("Add php.ini values",t)+"\n";break}switch(t){case"win32":return n+await addINIValuesWindows(e);case"darwin":case"linux":return n+await addINIValuesUnix(e);default:return await s.log("Platform "+t+" is not supported",t,"error")}}},5469:(e,t,a)=>{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.issueCommand=issueCommand;t.info=info;t.error=error;t.setFailed=setFailed;t.getInput=getInput;const n=a(857);function toCommandValue(e){if(e instanceof Error){return e.toString()}return e}function escapeData(e){return toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return e.replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}function issueCommand(e,t,a){let i=`::${e}`;if(t&&Object.keys(t).length>0){i+=" ";const e=Object.entries(t).filter((([,e])=>e)).map((([e,t])=>`${e}=${escapeProperty(t)}`)).join(",");i+=e}i+=`::${escapeData(a)}`;process.stdout.write(i+n.EOL)}function info(e){process.stdout.write(e+n.EOL)}function error(e){issueCommand("error",{},e)}function setFailed(e){process.exitCode=1;error(e)}function getInput(e,t=false){const a=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&!a){throw new Error(`Input required and not supplied: ${e}`)}return a.trim()}},9524:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.fetch=fetch;const a=new Set([301,302,303,307,308]);async function fetch(e,t,n=5){const i={"User-Agent":`Mozilla/5.0 (${process.platform} ${process.arch}) setup-php`};if(t){i["Authorization"]="Bearer "+t}try{const t=await globalThis.fetch(e,{headers:i,redirect:n>0?"follow":"manual"});if(t.ok){const e=await t.text();return{data:e}}else if(a.has(t.status)&&n<=0){return{error:`${t.status}: Redirect error`}}else{return{error:`${t.status}: ${t.statusText}`}}}catch(e){return{error:`Fetch error: ${e.message}`}}}},8755:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o{await run()})().catch((e=>{d.setFailed(e.message)}))},9075:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;os.compareVersions(t.version,e.version)));const i=a.find((e=>{if(e?.require?.php){return e?.require?.php.split("|").some((e=>e&&s.satisfies(t+".0",e)))}return false}));return i?i.version:null}return null}},7159:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o{if(/^\d+\.\d+\.\d+(-|$)/.test(e))return e;const t=e.match(/^(\d+\.\d+\.\d+)([A-Za-z]+[0-9A-Za-z.]+)$/);return t?`${t[1]}-${t[2]}`:e};const t=e["version_prefix"]+e["version"];const a=`https://api.github.com/repos/${e["repository"]}/git/matching-refs/tags%2F${t}.`;const n=await d.readEnv("GITHUB_TOKEN")||await d.readEnv("COMPOSER_TOKEN");const i=await l.fetch(a,n);if(i.error||i.data==="[]"){e.error=i.error??`No version found with prefix ${t}.`;return e.version}else{const e=JSON.parse(i.data);const t=e.map((e=>(e.ref?.split("/").pop()??"").replace(/^v(?=\d)/,""))).filter((e=>e.length>0));const a=new Map;const n=t.map((e=>{const t=fixSemver(e);a.set(t,e);return t}));const o=n.toSorted(((e,t)=>{try{return p.compareVersions(t,e)}catch{return t.localeCompare(e,"en",{numeric:true,sensitivity:"base"})}}));return a.get(o[0])??o[0]}}async function getLatestVersion(e){if(!e.version&&e.fetch_latest==="false"){return"latest"}if(e.fetch_latest==="true"&&!e.repository){return"latest"}const t=await l.fetch(`${e.github}/${e.repository}/releases.atom`);if(t.data){const e=[...t.data.matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+\.\d+\.\d+)"/g)].map((e=>e[2]));const a=e.toSorted(((e,t)=>e.localeCompare(t,undefined,{numeric:true})));return a.at(-1)||"latest"}return"latest"}async function getVersion(e,t){const a=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;const n=/^composer:(stable|preview|snapshot|[12])$/;const i=/[><=^~]+.*/;const o=/^\d+(\.\d+)?$/;t.version=e.replace(/v?(\d)/,"$1").replace(/\.x/,"");switch(true){case n.test(t.release):case a.test(t.version):case i.test(t.version)&&t.type==="composer":return t.version;case o.test(t.version)&&t.type==="composer":t.release=`${t.tool}:${t.version}.*`;return`${t.version}.*`;case!!t.repository&&o.test(t.version):return await getSemverVersion(t);default:return t.version.replace(/[><=^~]*/,"")}}async function getRelease(e,t){e=e.includes("/")?e.split("/")[1]:e;return e.includes(":")?[t.tool,e.split(":")[1]].join(":"):t.tool}async function filterList(e){const t=/^composer($|:.*)/;const a=/^composer:?($|preview$|snapshot$|v?\d+(\.\d+)?$|v?\d+\.\d+\.\d+[\w-]*$)/;const n=e.filter((e=>a.test(e)));let i="composer";e=e.filter((e=>!t.test(e)));switch(true){case n[0]==undefined:break;default:i=n.at(-1).replace(/v(\d\S*)/,"$1");break}e.unshift(i);return e}async function getUrl(e){const t=e.version??"latest";if(t==="latest"||t===""){return[e.domain,e.repository,e.prefix,"latest",e.verb,e.tool+e.extension].filter(Boolean).join("/")}else{return[e.domain,e.repository,e.prefix,e.verb,e.version_prefix+e.version,e.tool+e.extension].filter(Boolean).join("/")}}async function getPharUrl(e){if(e.version==="latest"){return e.domain+"/"+e.tool+".phar"}else{return e.domain+"/"+e.tool+"-"+e.version_prefix+e.version+".phar"}}async function addArchive(e){return await d.getCommand(e.os,"tool")+await d.joins(e.url,e.tool,e.version_parameter)}async function addPackage(e){const t=await d.getCommand(e.os,"composer_tool");const a=e.repository.split("/");const n=await d.joins(a[1],e.release,a[0]+"/",e.scope);return t+n}async function addBlackfirePlayer(e){switch(e.os){case"win32":return await d.addLog("$cross",e.tool,e.tool+" is not a windows tool","win32");default:if(e.version=="latest"){if(/5\.[5-6]|7\.0/.test(e.php_version)){e.version="1.9.3"}else if(/7\.[1-4]|8\.0/.test(e.php_version)){e.version="1.22.0"}}e.url=await getPharUrl(e);return addArchive(e)}}async function addCastor(e){e.tool="castor."+e.os.replace("win32","windows")+"-amd64";e.url=await getUrl(e);e.tool="castor";e.version_parameter=c.default.existsSync("castor.php")?e.version_parameter:"";return await addArchive(e)}async function addComposer(e){const t=e.version.replace("latest","stable");const a=e.github;const n=e.domain;const i="https://dl.cloudsmith.io";const o="https://artifacts.setup-php.com";const s=`composer-${e.php_version}-${t}.phar`;const r=`${a}/shivammathur/composer-cache/releases/latest/download/${s}`;const c=`${i}/public/shivammathur/composer-cache/raw/files/${s}`;const p=`${o}/composer/${s}`;const l=`${n}/download/latest-2.2.x/composer.phar`;const u=/^5\.[3-6]$|^7\.[0-1]$/.test(e.php_version);const m=`${n}/composer-${t}.phar`;const f=`${n}/download/${t}/composer.phar`;let x=`${r},${p},${c}`;let h=`${n}/composer.phar`;switch(true){case/^snapshot$/.test(t):h=u?l:h;break;case/^preview$|^2$/.test(t):h=u?l:m;break;case/^1$/.test(t):h=m;break;case/^\d+\.\d+\.\d+[\w-]*$/.test(e.version):x=`${a}/${e.repository}/releases/download/${e.version}/composer.phar`;h=f;break;default:h=u?l:m}const v=await d.readEnv("NO_TOOLS_CACHE")!=="true";e.url=v?`${x},${h}`:h;e.version_parameter=e.version;return await addArchive(e)}async function addDeployer(e){if(e.version==="latest"){e.url=e.domain+"/deployer.phar"}else{const t=await l.fetch("https://deployer.org/manifest.json");const a=JSON.parse(t.data);const n=Object.keys(a).find((t=>a[t].version===e.version));if(n){e.url=a[n].url}else{return await d.addLog("$cross","deployer","Version missing in deployer manifest",e.os)}}return await addArchive(e)}async function addDevTools(e){switch(e.os){case"linux":case"darwin":return"add_devtools "+e.tool;case"win32":return await d.addLog("$tick",e.tool,e.tool+" is not a windows tool","win32");default:return await d.log("Platform "+e.os+" is not supported",e.os,"error")}}async function addPECL(e){return await d.getCommand(e.os,"pecl")}async function addPhing(e){e.url=e.domain+"/get/phing-"+e.version+e.extension;if(e.version!="latest"){[e.prefix,e.verb]=["releases","download"];e.domain=e.github;e.extension="-"+e.version+e.extension;e.url+=","+await getUrl(e)}return await addArchive(e)}async function addPhive(e){switch(true){case/5\.[3-5]/.test(e.php_version):return await d.addLog("$cross","phive","Phive is not supported on PHP "+e.php_version,e.os);case/5\.6|7\.0/.test(e.php_version):e.version="0.12.1";break;case/7\.1/.test(e.php_version):e.version="0.13.5";break;case/7\.2/.test(e.php_version):e.version="0.14.5";break;case/7\.3|7\.4/.test(e.php_version):e.version="0.15.3";break;case/^latest$/.test(e.version):e.version=await getLatestVersion(e);break}e.extension="-"+e.version+e.extension;e.url=await getUrl(e);return await addArchive(e)}async function addPHPUnitTools(e){if(e.version==="latest"){e.version=await u.search(e.packagist,e.php_version)??"latest"}e.url=await getPharUrl(e);if(e.url.match(/-\d+/)){e.url+=","+e.url.replace(/-(\d+)\.\d+\.\d+/,"-$1")}return await addArchive(e)}async function addWPCLI(e){if(e.version==="latest"){e.uri="wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true";e.url=[e.domain,e.uri].join("/")}else{e.extension="-"+e.version+e.extension;e.url=await getUrl(e)}return await addArchive(e)}async function getData(e,t,a){const n=r.default.join(__dirname,"../src/configs/tools.json");const i=c.default.readFileSync(n,"utf8");const o=JSON.parse(i);e=e.replace(/\s+/g,"");const s=e.split(":");const p=s[0];const l=s[1];let u;if(Object.hasOwn(o,p)){u={...o[p],tool:p}}else{const e=Object.keys(o).find((e=>o[e].alias==p));if(e){u={...o[e],tool:e}}else if(p.includes("/")){u={tool:p.split("/")[1],repository:p,type:"composer"}}else{u={tool:p}}}const d="https://github.com";const m=u.domain??d;const f={tool:u.tool,version:"",url:"",os:a,php_version:t,github:d,domain:m,extension:u.extension??".phar",repository:u.repository??"",prefix:m===d?"releases":"",verb:m===d?"download":"",fetch_latest:u.fetch_latest??"false",scope:u.scope??"global",version_parameter:u.version_parameter!=null?JSON.stringify(u.version_parameter):"",version_prefix:u.version_prefix??"",release:"",packagist:u.packagist??u.repository??"",type:u.type,function:u.function,alias:u.alias};f.release=await getRelease(e,f);f.version=l?await getVersion(l,f):await getLatestVersion(f);f.url=await getUrl(f);return f}t.functionRecord={castor:addCastor,composer:addComposer,deployer:addDeployer,dev_tools:addDevTools,phive:addPhive,blackfire_player:addBlackfirePlayer,pecl:addPECL,phing:addPhing,phpunit:addPHPUnitTools,phpcpd:addPHPUnitTools,wp_cli:addWPCLI};async function addTools(e,a,n){let i="\n";if(e==="none"){return""}else{i+=await d.stepLog("Setup Tools",n)}const o=await filterList(await d.CSVArray(e));await d.asyncForEach(o,(async function(e){const o=await getData(e,a,n);i+="\n";switch(true){case o.error!==undefined:i+=await d.addLog("$cross",o.tool,o.error,o.os);break;case"phar"===o.type:i+=await addArchive(o);break;case"composer"===o.type:i+=await addPackage(o);break;case"custom-package"===o.type:i+=await d.customPackage(o.tool.split("-")[0],"tools",o.version,o.os);break;case"custom-function"===o.type:if(!o.function){i+=await d.addLog("$cross",o.tool,o.tool+" has no function defined. Please report this issue.",o.os)}else{i+=await t.functionRecord[o.function](o)}break;case/^none$/.test(o.tool):break;default:i+=await d.addLog("$cross",o.tool,"Tool "+o.tool+" is not supported",o.os);break}}));return i}},9277:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o1:return e.slice(0,3);default:return e+".0"}}}async function parseIniFile(e){switch(true){case/^(production|development|none)$/.test(e):return e;case/php\.ini-(production|development)$/.test(e):return e.split("-")[1];default:return"production"}}async function asyncForEach(e,t){for(const[a,n]of e.entries()){await t(n,a,e)}}async function color(e){switch(e){case"error":return"31";default:case"success":return"32";case"warning":return"33"}}async function log(e,t,a){switch(t){case"win32":return'printf "\\033['+await color(a)+";1m"+e+' \\033[0m"';case"linux":case"darwin":default:return'echo "\\033['+await color(a)+";1m"+e+'\\033[0m"'}}async function stepLog(e,t){switch(t){case"win32":return'Step-Log "'+e+'"';case"linux":case"darwin":return'step_log "'+e+'"';default:return await log("Platform "+t+" is not supported",t,"error")}}async function addLog(e,t,a,n){switch(n){case"win32":return'Add-Log "'+e+'" "'+t+'" "'+a+'"';case"linux":case"darwin":return'add_log "'+e+'" "'+t+'" "'+a+'"';default:return await log("Platform "+n+" is not supported",n,"error")}}async function extensionArray(e){switch(e){case"":case" ":return[];default:return[e.match(/(^|,\s?)none(\s?,|$)/)?"none":"",...e.split(",").map((function(e){e=e.trim().replace(/^\\\s*/,"");if(/.+-.+\/.+@.+/.test(e)){return e}return e.toLowerCase().replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/,"$1$3")}))].filter(Boolean)}}async function CSVArray(e){switch(e){case"":case" ":return[];default:return e.split(/,(?=(?:(?:[^"']*["']){2})*[^"']*$)/).map((function(e){return e.trim().replace(/^["']|["']$|(?<==)["']/g,"").replace(/=(((?!E_).)*[?{}|&~![()^]+((?!E_).)+)/,"='$1'").replace(/=(.*?)(=.*)/,"='$1$2'").replace(/:\s*["'](.*?)/g,":$1")})).filter(Boolean)}}async function getExtensionPrefix(e){switch(true){default:return"extension";case/xdebug([2-3])?$|opcache|ioncube|eaccelerator/.test(e):return"zend_extension"}}async function suppressOutput(e){switch(e){case"win32":return" >$null 2>&1";case"linux":case"darwin":return" >/dev/null 2>&1";default:return await log("Platform "+e+" is not supported",e,"error")}}async function getUnsupportedLog(e,t,a){return"\n"+await addLog("$cross",e,[e,"is not supported on PHP",t].join(" "),a)+"\n"}async function getCommand(e,t){switch(e){case"linux":case"darwin":return"add_"+t+" ";case"win32":return"Add-"+t.split("_").map((e=>e.charAt(0).toUpperCase()+e.slice(1))).join("")+" ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function joins(...e){return[...e].join(" ")}async function scriptExtension(e){switch(e){case"win32":return".ps1";case"linux":case"darwin":return".sh";default:return await log("Platform "+e+" is not supported",e,"error")}}async function scriptTool(e){switch(e){case"win32":return"pwsh ";case"linux":case"darwin":return"bash ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function customPackage(e,t,a,n){const i=e.replace(/\d+|(pdo|pecl)[_-]|[_-]db2/,"");const o=await scriptExtension(n);const s=c.join(__dirname,"../src/scripts/"+t+"/"+i+o);const r=await getCommand(n,i);return"\n. "+s+"\n"+r+a}async function parseExtensionSource(e,t){const a=/(\w+)-(\w+:\/\/.{1,253}(?:[.:][^:/\s]{2,63})+\/)?([\w.-]+)\/([\w.-]+)@(.+)/;const n=a.exec(e);n[2]=n[2]?n[2].slice(0,-1):"https://github.com";return await joins("\nadd_extension_from_source",...n.splice(1,n.length),t)}async function readPHPVersion(){const e=await getInput("php-version",false);if(e){return e}const t=await getInput("php-version-file",false)||".php-version";if(r.default.existsSync(t)){const e=r.default.readFileSync(t,"utf8");const a=e.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);return a?a[1]:e.trim()}else if(t!==".php-version"){throw new Error(`Could not find '${t}' file.`)}const a=await readEnv("COMPOSER_PROJECT_DIR");const n=c.join(a,"composer.lock");if(r.default.existsSync(n)){const e=JSON.parse(r.default.readFileSync(n,"utf8"));if(e["platform-overrides"]&&e["platform-overrides"]["php"]){return e["platform-overrides"]["php"]}}const i=c.join(a,"composer.json");if(r.default.existsSync(i)){const e=JSON.parse(r.default.readFileSync(i,"utf8"));if(e["config"]&&e["config"]["platform"]&&e["config"]["platform"]["php"]){return e["config"]["platform"]["php"]}}return"latest"}async function setVariable(e,t,a){switch(a){case"win32":return"\n$"+e+" = "+t+"\n";case"linux":case"darwin":default:return"\n"+e+'="$('+t+')"\n'}}},5236:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o{s+=p.write(e);if(u){u(e)}};const stdOutListener=e=>{o+=c.write(e);if(l){l(e)}};const d=Object.assign(Object.assign({},a===null||a===void 0?void 0:a.listeners),{stdout:stdOutListener,stderr:stdErrListener});const m=yield exec(e,t,Object.assign(Object.assign({},a),{listeners:d}));o+=c.end();s+=p.end();return{exitCode:m,stdout:o,stderr:s}}))}},6665:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o-1){const e=n.substring(0,i);a(e);n=n.substring(i+r.EOL.length);i=n.indexOf(r.EOL)}return n}catch(e){this._debug(`error processing line. Failed with error ${e}`);return""}}_getSpawnFileName(){if(f){if(this._isCmdFile()){return process.env["COMSPEC"]||"cmd.exe"}}return this.toolPath}_getSpawnArgs(e){if(f){if(this._isCmdFile()){let t=`/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`;for(const a of this.args){t+=" ";t+=e.windowsVerbatimArguments?a:this._windowsQuoteCmdArg(a)}t+='"';return[t]}}return this.args}_endsWith(e,t){return e.endsWith(t)}_isCmdFile(){const e=this.toolPath.toUpperCase();return this._endsWith(e,".CMD")||this._endsWith(e,".BAT")}_windowsQuoteCmdArg(e){if(!this._isCmdFile()){return this._uvQuoteCmdArg(e)}if(!e){return'""'}const t=[" ","\t","&","(",")","[","]","{","}","^","=",";","!","'","+",",","`","~","|","<",">",'"'];let a=false;for(const n of e){if(t.some((e=>e===n))){a=true;break}}if(!a){return e}let n='"';let i=true;for(let t=e.length;t>0;t--){n+=e[t-1];if(i&&e[t-1]==="\\"){n+="\\"}else if(e[t-1]==='"'){i=true;n+='"'}else{i=false}}n+='"';return n.split("").reverse().join("")}_uvQuoteCmdArg(e){if(!e){return'""'}if(!e.includes(" ")&&!e.includes("\t")&&!e.includes('"')){return e}if(!e.includes('"')&&!e.includes("\\")){return`"${e}"`}let t='"';let a=true;for(let n=e.length;n>0;n--){t+=e[n-1];if(a&&e[n-1]==="\\"){t+="\\"}else if(e[n-1]==='"'){a=true;t+="\\"}else{a=false}}t+='"';return t.split("").reverse().join("")}_cloneExecOptions(e){e=e||{};const t={cwd:e.cwd||process.cwd(),env:e.env||process.env,silent:e.silent||false,windowsVerbatimArguments:e.windowsVerbatimArguments||false,failOnStdErr:e.failOnStdErr||false,ignoreReturnCode:e.ignoreReturnCode||false,delay:e.delay||1e4};t.outStream=e.outStream||process.stdout;t.errStream=e.errStream||process.stderr;return t}_getSpawnOptions(e,t){e=e||{};const a={};a.cwd=e.cwd;a.env=e.env;a["windowsVerbatimArguments"]=e.windowsVerbatimArguments||this._isCmdFile();if(e.windowsVerbatimArguments){a.argv0=`"${t}"`}return a}exec(){return s(this,void 0,void 0,(function*(){if(!d.isRooted(this.toolPath)&&(this.toolPath.includes("/")||f&&this.toolPath.includes("\\"))){this.toolPath=l.resolve(process.cwd(),this.options.cwd||process.cwd(),this.toolPath)}this.toolPath=yield u.which(this.toolPath,true);return new Promise(((e,t)=>s(this,void 0,void 0,(function*(){this._debug(`exec tool: ${this.toolPath}`);this._debug("arguments:");for(const e of this.args){this._debug(` ${e}`)}const a=this._cloneExecOptions(this.options);if(!a.silent&&a.outStream){a.outStream.write(this._getCommandString(a)+r.EOL)}const n=new ExecState(a,this.toolPath);n.on("debug",(e=>{this._debug(e)}));if(this.options.cwd&&!(yield d.exists(this.options.cwd))){return t(new Error(`The cwd: ${this.options.cwd} does not exist!`))}const i=this._getSpawnFileName();const o=p.spawn(i,this._getSpawnArgs(a),this._getSpawnOptions(this.options,i));let s="";if(o.stdout){o.stdout.on("data",(e=>{if(this.options.listeners&&this.options.listeners.stdout){this.options.listeners.stdout(e)}if(!a.silent&&a.outStream){a.outStream.write(e)}s=this._processLineBuffer(e,s,(e=>{if(this.options.listeners&&this.options.listeners.stdline){this.options.listeners.stdline(e)}}))}))}let c="";if(o.stderr){o.stderr.on("data",(e=>{n.processStderr=true;if(this.options.listeners&&this.options.listeners.stderr){this.options.listeners.stderr(e)}if(!a.silent&&a.errStream&&a.outStream){const t=a.failOnStdErr?a.errStream:a.outStream;t.write(e)}c=this._processLineBuffer(e,c,(e=>{if(this.options.listeners&&this.options.listeners.errline){this.options.listeners.errline(e)}}))}))}o.on("error",(e=>{n.processError=e.message;n.processExited=true;n.processClosed=true;n.CheckComplete()}));o.on("exit",(e=>{n.processExitCode=e;n.processExited=true;this._debug(`Exit code ${e} received from tool '${this.toolPath}'`);n.CheckComplete()}));o.on("close",(e=>{n.processExitCode=e;n.processExited=true;n.processClosed=true;this._debug(`STDIO streams have closed for tool '${this.toolPath}'`);n.CheckComplete()}));n.on("done",((a,n)=>{if(s.length>0){this.emit("stdline",s)}if(c.length>0){this.emit("errline",c)}o.removeAllListeners();if(a){t(a)}else{e(n)}}));if(this.options.input){if(!o.stdin){throw new Error("child process missing stdin")}o.stdin.end(this.options.input)}}))))}))}}t.ToolRunner=ToolRunner;function argStringToArray(e){const t=[];let a=false;let n=false;let i="";function append(e){if(n&&e!=='"'){i+="\\"}i+=e;n=false}for(let o=0;o0){t.push(i);i=""}continue}append(s)}if(i.length>0){t.push(i.trim())}return t}class ExecState extends c.EventEmitter{constructor(e,t){super();this.processClosed=false;this.processError="";this.processExitCode=0;this.processExited=false;this.processStderr=false;this.delay=1e4;this.done=false;this.timeout=null;if(!t){throw new Error("toolPath must not be empty")}this.options=e;this.toolPath=t;if(e.delay){this.delay=e.delay}}CheckComplete(){if(this.done){return}if(this.processClosed){this._setResult()}else if(this.processExited){this.timeout=(0,m.setTimeout)(ExecState.HandleTimeout,this.delay,this)}}_debug(e){this.emit("debug",e)}_setResult(){let e;if(this.processExited){if(this.processError){e=new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`)}else if(this.processExitCode!==0&&!this.options.ignoreReturnCode){e=new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`)}else if(this.processStderr&&this.options.failOnStdErr){e=new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`)}}if(this.timeout){clearTimeout(this.timeout);this.timeout=null}this.done=true;this.emit("done",e,this.processExitCode)}static HandleTimeout(e){if(e.done){return}if(!e.processClosed&&e.processExited){const t=`The STDIO streams did not close within ${e.delay/1e3} seconds of the exit event from process '${e.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`;e._debug(t)}e._setResult()}}},5207:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;oe.toUpperCase()===t))){return e}}else{if(isUnixExecutable(n)){return e}}}const i=e;for(const o of a){e=i+o;n=undefined;try{n=yield(0,t.stat)(e)}catch(t){if(t.code!=="ENOENT"){console.log(`Unexpected error attempting to determine if executable file exists '${e}': ${t}`)}}if(n&&n.isFile()){if(t.IS_WINDOWS){try{const a=p.dirname(e);const n=p.basename(e).toUpperCase();for(const i of yield(0,t.readdir)(a)){if(n===i.toUpperCase()){e=p.join(a,i);break}}}catch(t){console.log(`Unexpected error attempting to determine the actual case of the file '${e}': ${t}`)}return e}else{if(isUnixExecutable(n)){return e}}}}return""}))}function normalizeSeparators(e){e=e||"";if(t.IS_WINDOWS){e=e.replace(/\//g,"\\");return e.replace(/\\\\+/g,"\\")}return e.replace(/\/\/+/g,"/")}function isUnixExecutable(e){return(e.mode&1)>0||(e.mode&8)>0&&process.getgid!==undefined&&e.gid===process.getgid()||(e.mode&64)>0&&process.getuid!==undefined&&e.uid===process.getuid()}function getCmdPath(){var e;return(e=process.env["COMSPEC"])!==null&&e!==void 0?e:`cmd.exe`}},4994:function(e,t,a){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){if(n===undefined)n=a;var i=Object.getOwnPropertyDescriptor(t,a);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[a]}}}Object.defineProperty(e,n,i)}:function(e,t,a,n){if(n===undefined)n=a;e[n]=t[a]});var i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var o=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))t[t.length]=a;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var a=ownKeys(e),o=0;o|]/.test(e)){throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows')}}try{yield p.rm(e,{force:true,maxRetries:3,recursive:true,retryDelay:300})}catch(e){throw new Error(`File was unable to be removed ${e}`)}}))}function mkdirP(e){return s(this,void 0,void 0,(function*(){(0,r.ok)(e,"a path argument must be provided");yield p.mkdir(e,{recursive:true})}))}function which(e,t){return s(this,void 0,void 0,(function*(){if(!e){throw new Error("parameter 'tool' is required")}if(t){const t=yield which(e,false);if(!t){if(p.IS_WINDOWS){throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`)}else{throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`)}}return t}const a=yield findInPath(e);if(a&&a.length>0){return a[0]}return""}))}function findInPath(e){return s(this,void 0,void 0,(function*(){if(!e){throw new Error("parameter 'tool' is required")}const t=[];if(p.IS_WINDOWS&&process.env["PATHEXT"]){for(const e of process.env["PATHEXT"].split(c.delimiter)){if(e){t.push(e)}}}if(p.isRooted(e)){const a=yield p.tryGetExecutablePath(e,t);if(a){return[a]}return[]}if(e.includes(c.sep)){return[]}const a=[];if(process.env.PATH){for(const e of process.env.PATH.split(c.delimiter)){if(e){a.push(e)}}}const n=[];for(const i of a){const a=yield p.tryGetExecutablePath(c.join(i,e),t);if(a){n.push(a)}}return n}))}function readCopyOptions(e){const t=e.force==null?true:e.force;const a=Boolean(e.recursive);const n=e.copySourceDirectory==null?true:Boolean(e.copySourceDirectory);return{force:t,recursive:a,copySourceDirectory:n}}function cpDirRecursive(e,t,a,n){return s(this,void 0,void 0,(function*(){if(a>=255)return;a++;yield mkdirP(t);const i=yield p.readdir(e);for(const o of i){const i=`${e}/${o}`;const s=`${t}/${o}`;const r=yield p.lstat(i);if(r.isDirectory()){yield cpDirRecursive(i,s,a,n)}else{yield copyFile(i,s,n)}}yield p.chmod(t,(yield p.stat(e)).mode)}))}function copyFile(e,t,a){return s(this,void 0,void 0,(function*(){if((yield p.lstat(e)).isSymbolicLink()){try{yield p.lstat(t);yield p.unlink(t)}catch(e){if(e.code==="EPERM"){yield p.chmod(t,"0666");yield p.unlink(t)}}const a=yield p.readlink(e);yield p.symlink(a,t,p.IS_WINDOWS?"junction":null)}else if(!(yield p.exists(t))||a){yield p.copyFile(e,t)}}))}},1324:(e,t,a)=>{e.exports={parallel:a(3857),serial:a(1054),serialOrdered:a(3961)}},4818:e=>{e.exports=abort;function abort(e){Object.keys(e.jobs).forEach(clean.bind(e));e.jobs={}}function clean(e){if(typeof this.jobs[e]=="function"){this.jobs[e]()}}},8452:(e,t,a)=>{var n=a(9200);e.exports=async;function async(e){var t=false;n((function(){t=true}));return function async_callback(a,i){if(t){e(a,i)}else{n((function nextTick_callback(){e(a,i)}))}}}},9200:e=>{e.exports=defer;function defer(e){var t=typeof setImmediate=="function"?setImmediate:typeof process=="object"&&typeof process.nextTick=="function"?process.nextTick:null;if(t){t(e)}else{setTimeout(e,0)}}},4902:(e,t,a)=>{var n=a(8452),i=a(4818);e.exports=iterate;function iterate(e,t,a,n){var o=a["keyedList"]?a["keyedList"][a.index]:a.index;a.jobs[o]=runJob(t,o,e[o],(function(e,t){if(!(o in a.jobs)){return}delete a.jobs[o];if(e){i(a)}else{a.results[o]=t}n(e,a.results)}))}function runJob(e,t,a,i){var o;if(e.length==2){o=e(a,n(i))}else{o=e(a,t,n(i))}return o}},1721:e=>{e.exports=state;function state(e,t){var a=!Array.isArray(e),n={index:0,keyedList:a||t?Object.keys(e):null,jobs:{},results:a?{}:[],size:a?Object.keys(e).length:e.length};if(t){n.keyedList.sort(a?t:function(a,n){return t(e[a],e[n])})}return n}},3351:(e,t,a)=>{var n=a(4818),i=a(8452);e.exports=terminator;function terminator(e){if(!Object.keys(this.jobs).length){return}this.index=this.size;n(this);i(e)(null,this.results)}},3857:(e,t,a)=>{var n=a(4902),i=a(1721),o=a(3351);e.exports=parallel;function parallel(e,t,a){var s=i(e);while(s.index<(s["keyedList"]||e).length){n(e,t,s,(function(e,t){if(e){a(e,t);return}if(Object.keys(s.jobs).length===0){a(null,s.results);return}}));s.index++}return o.bind(s,a)}},1054:(e,t,a)=>{var n=a(3961);e.exports=serial;function serial(e,t,a){return n(e,t,null,a)}},3961:(e,t,a)=>{var n=a(4902),i=a(1721),o=a(3351);e.exports=serialOrdered;e.exports.ascending=ascending;e.exports.descending=descending;function serialOrdered(e,t,a,s){var r=i(e,a);n(e,t,r,(function iteratorHandler(a,i){if(a){s(a,i);return}r.index++;if(r.index<(r["keyedList"]||e).length){n(e,t,r,iteratorHandler);return}s(null,r.results)}));return o.bind(r,s)}function ascending(e,t){return et?1:0}function descending(e,t){return-1*ascending(e,t)}},2639:(e,t,a)=>{"use strict";var n=a(7564);var i=a(3945);var o=a(8093);var s=a(1330);e.exports=s||n.call(o,i)},3945:e=>{"use strict";e.exports=Function.prototype.apply},8093:e=>{"use strict";e.exports=Function.prototype.call},8705:(e,t,a)=>{"use strict";var n=a(7564);var i=a(3314);var o=a(8093);var s=a(2639);e.exports=function callBindBasic(e){if(e.length<1||typeof e[0]!=="function"){throw new i("a function is required")}return s(n,o,e)}},1330:e=>{"use strict";e.exports=typeof Reflect!=="undefined"&&Reflect&&Reflect.apply},5630:(e,t,a)=>{var n=a(9023);var i=a(2203).Stream;var o=a(2710);e.exports=CombinedStream;function CombinedStream(){this.writable=false;this.readable=true;this.dataSize=0;this.maxDataSize=2*1024*1024;this.pauseStreams=true;this._released=false;this._streams=[];this._currentStream=null;this._insideLoop=false;this._pendingNext=false}n.inherits(CombinedStream,i);CombinedStream.create=function(e){var t=new this;e=e||{};for(var a in e){t[a]=e[a]}return t};CombinedStream.isStreamLike=function(e){return typeof e!=="function"&&typeof e!=="string"&&typeof e!=="boolean"&&typeof e!=="number"&&!Buffer.isBuffer(e)};CombinedStream.prototype.append=function(e){var t=CombinedStream.isStreamLike(e);if(t){if(!(e instanceof o)){var a=o.create(e,{maxDataSize:Infinity,pauseStream:this.pauseStreams});e.on("data",this._checkDataSize.bind(this));e=a}this._handleErrors(e);if(this.pauseStreams){e.pause()}}this._streams.push(e);return this};CombinedStream.prototype.pipe=function(e,t){i.prototype.pipe.call(this,e,t);this.resume();return e};CombinedStream.prototype._getNext=function(){this._currentStream=null;if(this._insideLoop){this._pendingNext=true;return}this._insideLoop=true;try{do{this._pendingNext=false;this._realGetNext()}while(this._pendingNext)}finally{this._insideLoop=false}};CombinedStream.prototype._realGetNext=function(){var e=this._streams.shift();if(typeof e=="undefined"){this.end();return}if(typeof e!=="function"){this._pipeNext(e);return}var t=e;t(function(e){var t=CombinedStream.isStreamLike(e);if(t){e.on("data",this._checkDataSize.bind(this));this._handleErrors(e)}this._pipeNext(e)}.bind(this))};CombinedStream.prototype._pipeNext=function(e){this._currentStream=e;var t=CombinedStream.isStreamLike(e);if(t){e.on("end",this._getNext.bind(this));e.pipe(this,{end:false});return}var a=e;this.write(a);this._getNext()};CombinedStream.prototype._handleErrors=function(e){var t=this;e.on("error",(function(e){t._emitError(e)}))};CombinedStream.prototype.write=function(e){this.emit("data",e)};CombinedStream.prototype.pause=function(){if(!this.pauseStreams){return}if(this.pauseStreams&&this._currentStream&&typeof this._currentStream.pause=="function")this._currentStream.pause();this.emit("pause")};CombinedStream.prototype.resume=function(){if(!this._released){this._released=true;this.writable=true;this._getNext()}if(this.pauseStreams&&this._currentStream&&typeof this._currentStream.resume=="function")this._currentStream.resume();this.emit("resume")};CombinedStream.prototype.end=function(){this._reset();this.emit("end")};CombinedStream.prototype.destroy=function(){this._reset();this.emit("close")};CombinedStream.prototype._reset=function(){this.writable=false;this._streams=[];this._currentStream=null};CombinedStream.prototype._checkDataSize=function(){this._updateDataSize();if(this.dataSize<=this.maxDataSize){return}var e="DelayedStream#maxDataSize of "+this.maxDataSize+" bytes exceeded.";this._emitError(new Error(e))};CombinedStream.prototype._updateDataSize=function(){this.dataSize=0;var e=this;this._streams.forEach((function(t){if(!t.dataSize){return}e.dataSize+=t.dataSize}));if(this._currentStream&&this._currentStream.dataSize){this.dataSize+=this._currentStream.dataSize}};CombinedStream.prototype._emitError=function(e){this._reset();this.emit("error",e)}},2026:function(e,t){(function(e,a){true?a(t):0})(this,(function(e){"use strict";const t=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;const validateAndParse=e=>{if(typeof e!=="string"){throw new TypeError("Invalid argument expected string")}const a=e.match(t);if(!a){throw new Error(`Invalid argument not valid semver ('${e}' received)`)}a.shift();return a};const isWildcard=e=>e==="*"||e==="x"||e==="X";const tryParse=e=>{const t=parseInt(e,10);return isNaN(t)?e:t};const forceType=(e,t)=>typeof e!==typeof t?[String(e),String(t)]:[e,t];const compareStrings=(e,t)=>{if(isWildcard(e)||isWildcard(t))return 0;const[a,n]=forceType(tryParse(e),tryParse(t));if(a>n)return 1;if(a{for(let a=0;a{const a=validateAndParse(e);const n=validateAndParse(t);const i=a.pop();const o=n.pop();const s=compareSegments(a,n);if(s!==0)return s;if(i&&o){return compareSegments(i.split("."),o.split("."))}else if(i||o){return i?-1:1}return 0};const compare=(e,t,n)=>{assertValidOperator(n);const i=compareVersions(e,t);return a[n].includes(i)};const a={">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1],"!=":[-1,1]};const n=Object.keys(a);const assertValidOperator=e=>{if(typeof e!=="string"){throw new TypeError(`Invalid operator type, expected string but got ${typeof e}`)}if(n.indexOf(e)===-1){throw new Error(`Invalid operator, expected one of ${n.join("|")}`)}};const satisfies=(e,t)=>{t=t.replace(/([><=]+)\s+/g,"$1");if(t.includes("||")){return t.split("||").some((t=>satisfies(e,t)))}else if(t.includes(" - ")){const[a,n]=t.split(" - ",2);return satisfies(e,`>=${a} <=${n}`)}else if(t.includes(" ")){return t.trim().replace(/\s{2,}/g," ").split(" ").every((t=>satisfies(e,t)))}const a=t.match(/^([<>=~^]+)/);const n=a?a[1]:"=";if(n!=="^"&&n!=="~")return compare(e,t,n);const[i,o,s,,r]=validateAndParse(e);const[c,p,l,,u]=validateAndParse(t);const d=[i,o,s];const m=[c,p!==null&&p!==void 0?p:"x",l!==null&&l!==void 0?l:"x"];if(u){if(!r)return false;if(compareSegments(d,m)!==0)return false;if(compareSegments(r.split("."),u.split("."))===-1)return false}const f=m.findIndex((e=>e!=="0"))+1;const x=n==="~"?2:f>1?f:1;if(compareSegments(d.slice(0,x),m.slice(0,x))!==0)return false;if(compareSegments(d.slice(x),m.slice(x))===-1)return false;return true};const validate=e=>typeof e==="string"&&/^[v\d]/.test(e)&&t.test(e);const validateStrict=e=>typeof e==="string"&&/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(e);e.compare=compare;e.compareVersions=compareVersions;e.satisfies=satisfies;e.validate=validate;e.validateStrict=validateStrict}))},6110:(e,t,a)=>{t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.storage=localstorage();t.destroy=(()=>{let e=false;return()=>{if(!e){e=true;console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}}})();t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window!=="undefined"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)){return true}if(typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)){return false}let e;return typeof document!=="undefined"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window!=="undefined"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator!=="undefined"&&navigator.userAgent&&(e=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(e[1],10)>=31||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(t){t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff);if(!this.useColors){return}const a="color: "+this.color;t.splice(1,0,a,"color: inherit");let n=0;let i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{if(e==="%%"){return}n++;if(e==="%c"){i=n}}));t.splice(i,0,a)}t.log=console.debug||console.log||(()=>{});function save(e){try{if(e){t.storage.setItem("debug",e)}else{t.storage.removeItem("debug")}}catch(e){}}function load(){let e;try{e=t.storage.getItem("debug")||t.storage.getItem("DEBUG")}catch(e){}if(!e&&typeof process!=="undefined"&&"env"in process){e=process.env.DEBUG}return e}function localstorage(){try{return localStorage}catch(e){}}e.exports=a(897)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},897:(e,t,a)=>{function setup(e){createDebug.debug=createDebug;createDebug.default=createDebug;createDebug.coerce=coerce;createDebug.disable=disable;createDebug.enable=enable;createDebug.enabled=enabled;createDebug.humanize=a(744);createDebug.destroy=destroy;Object.keys(e).forEach((t=>{createDebug[t]=e[t]}));createDebug.names=[];createDebug.skips=[];createDebug.formatters={};function selectColor(e){let t=0;for(let a=0;a{if(t==="%%"){return"%"}o++;const i=createDebug.formatters[n];if(typeof i==="function"){const n=e[o];t=i.call(a,n);e.splice(o,1);o--}return t}));createDebug.formatArgs.call(a,e);const s=a.log||createDebug.log;s.apply(a,e)}debug.namespace=e;debug.useColors=createDebug.useColors();debug.color=createDebug.selectColor(e);debug.extend=extend;debug.destroy=createDebug.destroy;Object.defineProperty(debug,"enabled",{enumerable:true,configurable:false,get:()=>{if(a!==null){return a}if(n!==createDebug.namespaces){n=createDebug.namespaces;i=createDebug.enabled(e)}return i},set:e=>{a=e}});if(typeof createDebug.init==="function"){createDebug.init(debug)}return debug}function extend(e,t){const a=createDebug(this.namespace+(typeof t==="undefined"?":":t)+e);a.log=this.log;return a}function enable(e){createDebug.save(e);createDebug.namespaces=e;createDebug.names=[];createDebug.skips=[];const t=(typeof e==="string"?e:"").trim().replace(/\s+/g,",").split(",").filter(Boolean);for(const e of t){if(e[0]==="-"){createDebug.skips.push(e.slice(1))}else{createDebug.names.push(e)}}}function matchesTemplate(e,t){let a=0;let n=0;let i=-1;let o=0;while(a"-"+e))].join(",");createDebug.enable("");return e}function enabled(e){for(const t of createDebug.skips){if(matchesTemplate(e,t)){return false}}for(const t of createDebug.names){if(matchesTemplate(e,t)){return true}}return false}function coerce(e){if(e instanceof Error){return e.stack||e.message}return e}function destroy(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}createDebug.enable(createDebug.load());return createDebug}e.exports=setup},2830:(e,t,a)=>{if(typeof process==="undefined"||process.type==="renderer"||process.browser===true||process.__nwjs){e.exports=a(6110)}else{e.exports=a(5108)}},5108:(e,t,a)=>{const n=a(2018);const i=a(9023);t.init=init;t.log=log;t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.destroy=i.deprecate((()=>{}),"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");t.colors=[6,2,3,4,5,1];try{const e=a(1450);if(e&&(e.stderr||e).level>=2){t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221]}}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const a=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let n=process.env[t];if(/^(yes|on|true|enabled)$/i.test(n)){n=true}else if(/^(no|off|false|disabled)$/i.test(n)){n=false}else if(n==="null"){n=null}else{n=Number(n)}e[a]=n;return e}),{});function useColors(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):n.isatty(process.stderr.fd)}function formatArgs(t){const{namespace:a,useColors:n}=this;if(n){const n=this.color;const i="[3"+(n<8?n:"8;5;"+n);const o=` ${i};1m${a} `;t[0]=o+t[0].split("\n").join("\n"+o);t.push(i+"m+"+e.exports.humanize(this.diff)+"")}else{t[0]=getDate()+a+" "+t[0]}}function getDate(){if(t.inspectOpts.hideDate){return""}return(new Date).toISOString()+" "}function log(...e){return process.stderr.write(i.formatWithOptions(t.inspectOpts,...e)+"\n")}function save(e){if(e){process.env.DEBUG=e}else{delete process.env.DEBUG}}function load(){return process.env.DEBUG}function init(e){e.inspectOpts={};const a=Object.keys(t.inspectOpts);for(let n=0;ne.trim())).join(" ")};o.O=function(e){this.inspectOpts.colors=this.useColors;return i.inspect(e,this.inspectOpts)}},2710:(e,t,a)=>{var n=a(2203).Stream;var i=a(9023);e.exports=DelayedStream;function DelayedStream(){this.source=null;this.dataSize=0;this.maxDataSize=1024*1024;this.pauseStream=true;this._maxDataSizeExceeded=false;this._released=false;this._bufferedEvents=[]}i.inherits(DelayedStream,n);DelayedStream.create=function(e,t){var a=new this;t=t||{};for(var n in t){a[n]=t[n]}a.source=e;var i=e.emit;e.emit=function(){a._handleEmit(arguments);return i.apply(e,arguments)};e.on("error",(function(){}));if(a.pauseStream){e.pause()}return a};Object.defineProperty(DelayedStream.prototype,"readable",{configurable:true,enumerable:true,get:function(){return this.source.readable}});DelayedStream.prototype.setEncoding=function(){return this.source.setEncoding.apply(this.source,arguments)};DelayedStream.prototype.resume=function(){if(!this._released){this.release()}this.source.resume()};DelayedStream.prototype.pause=function(){this.source.pause()};DelayedStream.prototype.release=function(){this._released=true;this._bufferedEvents.forEach(function(e){this.emit.apply(this,e)}.bind(this));this._bufferedEvents=[]};DelayedStream.prototype.pipe=function(){var e=n.prototype.pipe.apply(this,arguments);this.resume();return e};DelayedStream.prototype._handleEmit=function(e){if(this._released){this.emit.apply(this,e);return}if(e[0]==="data"){this.dataSize+=e[1].length;this._checkIfMaxDataSizeExceeded()}this._bufferedEvents.push(e)};DelayedStream.prototype._checkIfMaxDataSizeExceeded=function(){if(this._maxDataSizeExceeded){return}if(this.dataSize<=this.maxDataSize){return}this._maxDataSizeExceeded=true;var e="DelayedStream#maxDataSize of "+this.maxDataSize+" bytes exceeded.";this.emit("error",new Error(e))}},6669:(e,t,a)=>{"use strict";var n=a(8705);var i=a(3170);var o;try{o=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!=="object"||!("code"in e)||e.code!=="ERR_PROTO_ACCESS"){throw e}}var s=!!o&&i&&i(Object.prototype,"__proto__");var r=Object;var c=r.getPrototypeOf;e.exports=s&&typeof s.get==="function"?n([s.get]):typeof c==="function"?function getDunder(e){return c(e==null?e:r(e))}:false},9094:e=>{"use strict";var t=Object.defineProperty||false;if(t){try{t({},"a",{value:1})}catch(e){t=false}}e.exports=t},3056:e=>{"use strict";e.exports=EvalError},1620:e=>{"use strict";e.exports=Error},4585:e=>{"use strict";e.exports=RangeError},6905:e=>{"use strict";e.exports=ReferenceError},105:e=>{"use strict";e.exports=SyntaxError},3314:e=>{"use strict";e.exports=TypeError},2578:e=>{"use strict";e.exports=URIError},5399:e=>{"use strict";e.exports=Object},8700:(e,t,a)=>{"use strict";var n=a(470);var i=n("%Object.defineProperty%",true);var o=a(5479)();var s=a(4076);var r=a(3314);var c=o?Symbol.toStringTag:null;e.exports=function setToStringTag(e,t){var a=arguments.length>2&&!!arguments[2]&&arguments[2].force;var n=arguments.length>2&&!!arguments[2]&&arguments[2].nonConfigurable;if(typeof a!=="undefined"&&typeof a!=="boolean"||typeof n!=="undefined"&&typeof n!=="boolean"){throw new r("if provided, the `overrideIfSet` and `nonConfigurable` options must be booleans")}if(c&&(a||!s(e,c))){if(i){i(e,c,{configurable:!n,enumerable:false,value:t,writable:false})}else{e[c]=t}}}},4778:(e,t,a)=>{var n;e.exports=function(){if(!n){try{n=a(2830)("follow-redirects")}catch(e){}if(typeof n!=="function"){n=function(){}}}n.apply(null,arguments)}},1573:(e,t,a)=>{var n=a(7016);var i=n.URL;var o=a(8611);var s=a(5692);var r=a(2203).Writable;var c=a(2613);var p=a(4778);(function detectUnsupportedEnvironment(){var e=typeof process!=="undefined";var t=typeof window!=="undefined"&&typeof document!=="undefined";var a=isFunction(Error.captureStackTrace);if(!e&&(t||!a)){console.warn("The follow-redirects package should be excluded from browser builds.")}})();var l=false;try{c(new i(""))}catch(e){l=e.code==="ERR_INVALID_URL"}var u=["Authorization","Proxy-Authorization","Cookie"];var d=["auth","host","hostname","href","path","pathname","port","protocol","query","search","hash"];var m=["abort","aborted","connect","error","socket","timeout"];var f=Object.create(null);m.forEach((function(e){f[e]=function(t,a,n){this._redirectable.emit(e,t,a,n)}}));var x=createErrorType("ERR_INVALID_URL","Invalid URL",TypeError);var h=createErrorType("ERR_FR_REDIRECTION_FAILURE","Redirected request failed");var v=createErrorType("ERR_FR_TOO_MANY_REDIRECTS","Maximum number of redirects exceeded",h);var b=createErrorType("ERR_FR_MAX_BODY_LENGTH_EXCEEDED","Request body larger than maxBodyLength limit");var g=createErrorType("ERR_STREAM_WRITE_AFTER_END","write after end");var y=r.prototype.destroy||noop;function RedirectableRequest(e,t){r.call(this);this._sanitizeOptions(e);this._options=e;this._ended=false;this._ending=false;this._redirectCount=0;this._redirects=[];this._requestBodyLength=0;this._requestBodyBuffers=[];if(t){this.on("response",t)}var a=this;this._onNativeResponse=function(e){try{a._processResponse(e)}catch(e){a.emit("error",e instanceof h?e:new h({cause:e}))}};this._headerFilter=new RegExp("^(?:"+u.concat(e.sensitiveHeaders).map(escapeRegex).join("|")+")$","i");this._performRequest()}RedirectableRequest.prototype=Object.create(r.prototype);RedirectableRequest.prototype.abort=function(){destroyRequest(this._currentRequest);this._currentRequest.abort();this.emit("abort")};RedirectableRequest.prototype.destroy=function(e){destroyRequest(this._currentRequest,e);y.call(this,e);return this};RedirectableRequest.prototype.write=function(e,t,a){if(this._ending){throw new g}if(!isString(e)&&!isBuffer(e)){throw new TypeError("data should be a string, Buffer or Uint8Array")}if(isFunction(t)){a=t;t=null}if(e.length===0){if(a){a()}return}if(this._requestBodyLength+e.length<=this._options.maxBodyLength){this._requestBodyLength+=e.length;this._requestBodyBuffers.push({data:e,encoding:t});this._currentRequest.write(e,t,a)}else{this.emit("error",new b);this.abort()}};RedirectableRequest.prototype.end=function(e,t,a){if(isFunction(e)){a=e;e=t=null}else if(isFunction(t)){a=t;t=null}if(!e){this._ended=this._ending=true;this._currentRequest.end(null,null,a)}else{var n=this;var i=this._currentRequest;this.write(e,t,(function(){n._ended=true;i.end(null,null,a)}));this._ending=true}};RedirectableRequest.prototype.setHeader=function(e,t){this._options.headers[e]=t;this._currentRequest.setHeader(e,t)};RedirectableRequest.prototype.removeHeader=function(e){delete this._options.headers[e];this._currentRequest.removeHeader(e)};RedirectableRequest.prototype.setTimeout=function(e,t){var a=this;function destroyOnTimeout(t){t.setTimeout(e);t.removeListener("timeout",t.destroy);t.addListener("timeout",t.destroy)}function startTimer(t){if(a._timeout){clearTimeout(a._timeout)}a._timeout=setTimeout((function(){a.emit("timeout");clearTimer()}),e);destroyOnTimeout(t)}function clearTimer(){if(a._timeout){clearTimeout(a._timeout);a._timeout=null}a.removeListener("abort",clearTimer);a.removeListener("error",clearTimer);a.removeListener("response",clearTimer);a.removeListener("close",clearTimer);if(t){a.removeListener("timeout",t)}if(!a.socket){a._currentRequest.removeListener("socket",startTimer)}}if(t){this.on("timeout",t)}if(this.socket){startTimer(this.socket)}else{this._currentRequest.once("socket",startTimer)}this.on("socket",destroyOnTimeout);this.on("abort",clearTimer);this.on("error",clearTimer);this.on("response",clearTimer);this.on("close",clearTimer);return this};["flushHeaders","getHeader","setNoDelay","setSocketKeepAlive"].forEach((function(e){RedirectableRequest.prototype[e]=function(t,a){return this._currentRequest[e](t,a)}}));["aborted","connection","socket"].forEach((function(e){Object.defineProperty(RedirectableRequest.prototype,e,{get:function(){return this._currentRequest[e]}})}));RedirectableRequest.prototype._sanitizeOptions=function(e){if(!e.headers){e.headers={}}if(!isArray(e.sensitiveHeaders)){e.sensitiveHeaders=[]}if(e.host){if(!e.hostname){e.hostname=e.host}delete e.host}if(!e.pathname&&e.path){var t=e.path.indexOf("?");if(t<0){e.pathname=e.path}else{e.pathname=e.path.substring(0,t);e.search=e.path.substring(t)}}};RedirectableRequest.prototype._performRequest=function(){var e=this._options.protocol;var t=this._options.nativeProtocols[e];if(!t){throw new TypeError("Unsupported protocol "+e)}if(this._options.agents){var a=e.slice(0,-1);this._options.agent=this._options.agents[a]}var i=this._currentRequest=t.request(this._options,this._onNativeResponse);i._redirectable=this;for(var o of m){i.on(o,f[o])}this._currentUrl=/^\//.test(this._options.path)?n.format(this._options):this._options.path;if(this._isRedirect){var s=0;var r=this;var c=this._requestBodyBuffers;(function writeNext(e){if(i===r._currentRequest){if(e){r.emit("error",e)}else if(s=400){e.responseUrl=this._currentUrl;e.redirects=this._redirects;this.emit("response",e);this._requestBodyBuffers=[];return}destroyRequest(this._currentRequest);e.destroy();if(++this._redirectCount>this._options.maxRedirects){throw new v}var i;var o=this._options.beforeRedirect;if(o){i=Object.assign({Host:e.req.getHeader("host")},this._options.headers)}var s=this._options.method;if((t===301||t===302)&&this._options.method==="POST"||t===303&&!/^(?:GET|HEAD)$/.test(this._options.method)){this._options.method="GET";this._requestBodyBuffers=[];removeMatchingHeaders(/^content-/i,this._options.headers)}var r=removeMatchingHeaders(/^host$/i,this._options.headers);var c=parseUrl(this._currentUrl);var l=r||c.host;var u=/^\w+:/.test(a)?this._currentUrl:n.format(Object.assign(c,{host:l}));var d=resolveUrl(a,u);p("redirecting to",d.href);this._isRedirect=true;spreadUrlObject(d,this._options);if(d.protocol!==c.protocol&&d.protocol!=="https:"||d.host!==l&&!isSubdomain(d.host,l)){removeMatchingHeaders(this._headerFilter,this._options.headers)}if(isFunction(o)){var m={headers:e.headers,statusCode:t};var f={url:u,method:s,headers:i};o(this._options,m,f);this._sanitizeOptions(this._options)}this._performRequest()};function wrap(e){var t={maxRedirects:21,maxBodyLength:10*1024*1024};var a={};Object.keys(e).forEach((function(n){var i=n+":";var o=a[i]=e[n];var s=t[n]=Object.create(o);function request(e,n,o){if(isURL(e)){e=spreadUrlObject(e)}else if(isString(e)){e=spreadUrlObject(parseUrl(e))}else{o=n;n=validateUrl(e);e={protocol:i}}if(isFunction(n)){o=n;n=null}n=Object.assign({maxRedirects:t.maxRedirects,maxBodyLength:t.maxBodyLength},e,n);n.nativeProtocols=a;if(!isString(n.host)&&!isString(n.hostname)){n.hostname="::1"}c.equal(n.protocol,i,"protocol mismatch");p("options",n);return new RedirectableRequest(n,o)}function get(e,t,a){var n=s.request(e,t,a);n.end();return n}Object.defineProperties(s,{request:{value:request,configurable:true,enumerable:true,writable:true},get:{value:get,configurable:true,enumerable:true,writable:true}})}));return t}function noop(){}function parseUrl(e){var t;if(l){t=new i(e)}else{t=validateUrl(n.parse(e));if(!isString(t.protocol)){throw new x({input:e})}}return t}function resolveUrl(e,t){return l?new i(e,t):parseUrl(n.resolve(t,e))}function validateUrl(e){if(/^\[/.test(e.hostname)&&!/^\[[:0-9a-f]+\]$/i.test(e.hostname)){throw new x({input:e.href||e})}if(/^\[/.test(e.host)&&!/^\[[:0-9a-f]+\](:\d+)?$/i.test(e.host)){throw new x({input:e.href||e})}return e}function spreadUrlObject(e,t){var a=t||{};for(var n of d){a[n]=e[n]}if(a.hostname.startsWith("[")){a.hostname=a.hostname.slice(1,-1)}if(a.port!==""){a.port=Number(a.port)}a.path=a.search?a.pathname+a.search:a.pathname;return a}function removeMatchingHeaders(e,t){var a;for(var n in t){if(e.test(n)){a=t[n];delete t[n]}}return a===null||typeof a==="undefined"?undefined:String(a).trim()}function createErrorType(e,t,a){function CustomError(a){if(isFunction(Error.captureStackTrace)){Error.captureStackTrace(this,this.constructor)}Object.assign(this,a||{});this.code=e;this.message=this.cause?t+": "+this.cause.message:t}CustomError.prototype=new(a||Error);Object.defineProperties(CustomError.prototype,{constructor:{value:CustomError,enumerable:false},name:{value:"Error ["+e+"]",enumerable:false}});return CustomError}function destroyRequest(e,t){for(var a of m){e.removeListener(a,f[a])}e.on("error",noop);e.destroy(t)}function isSubdomain(e,t){c(isString(e)&&isString(t));var a=e.length-t.length-1;return a>0&&e[a]==="."&&e.endsWith(t)}function isArray(e){return e instanceof Array}function isString(e){return typeof e==="string"||e instanceof String}function isFunction(e){return typeof e==="function"}function isBuffer(e){return typeof e==="object"&&"length"in e}function isURL(e){return i&&e instanceof i}function escapeRegex(e){return e.replace(/[\]\\/()*+?.$]/g,"\\$&")}e.exports=wrap({http:o,https:s});e.exports.wrap=wrap},6454:(e,t,a)=>{"use strict";var n=a(5630);var i=a(9023);var o=a(6928);var s=a(8611);var r=a(5692);var c=a(7016).parse;var p=a(9896);var l=a(2203).Stream;var u=a(6982);var d=a(4096);var m=a(1324);var f=a(8700);var x=a(4076);var h=a(1835);function FormData(e){if(!(this instanceof FormData)){return new FormData(e)}this._overheadLength=0;this._valueLength=0;this._valuesToMeasure=[];n.call(this);e=e||{};for(var t in e){this[t]=e[t]}}i.inherits(FormData,n);FormData.LINE_BREAK="\r\n";FormData.DEFAULT_CONTENT_TYPE="application/octet-stream";FormData.prototype.append=function(e,t,a){a=a||{};if(typeof a==="string"){a={filename:a}}var i=n.prototype.append.bind(this);if(typeof t==="number"||t==null){t=String(t)}if(Array.isArray(t)){this._error(new Error("Arrays are not supported."));return}var o=this._multiPartHeader(e,t,a);var s=this._multiPartFooter();i(o);i(t);i(s);this._trackLength(o,t,a)};FormData.prototype._trackLength=function(e,t,a){var n=0;if(a.knownLength!=null){n+=Number(a.knownLength)}else if(Buffer.isBuffer(t)){n=t.length}else if(typeof t==="string"){n=Buffer.byteLength(t)}this._valueLength+=n;this._overheadLength+=Buffer.byteLength(e)+FormData.LINE_BREAK.length;if(!t||!t.path&&!(t.readable&&x(t,"httpVersion"))&&!(t instanceof l)){return}if(!a.knownLength){this._valuesToMeasure.push(t)}};FormData.prototype._lengthRetriever=function(e,t){if(x(e,"fd")){if(e.end!=undefined&&e.end!=Infinity&&e.start!=undefined){t(null,e.end+1-(e.start?e.start:0))}else{p.stat(e.path,(function(a,n){if(a){t(a);return}var i=n.size-(e.start?e.start:0);t(null,i)}))}}else if(x(e,"httpVersion")){t(null,Number(e.headers["content-length"]))}else if(x(e,"httpModule")){e.on("response",(function(a){e.pause();t(null,Number(a.headers["content-length"]))}));e.resume()}else{t("Unknown stream")}};FormData.prototype._multiPartHeader=function(e,t,a){if(typeof a.header==="string"){return a.header}var n=this._getContentDisposition(t,a);var i=this._getContentType(t,a);var o="";var s={"Content-Disposition":["form-data",'name="'+e+'"'].concat(n||[]),"Content-Type":[].concat(i||[])};if(typeof a.header==="object"){h(s,a.header)}var r;for(var c in s){if(x(s,c)){r=s[c];if(r==null){continue}if(!Array.isArray(r)){r=[r]}if(r.length){o+=c+": "+r.join("; ")+FormData.LINE_BREAK}}}return"--"+this.getBoundary()+FormData.LINE_BREAK+o+FormData.LINE_BREAK};FormData.prototype._getContentDisposition=function(e,t){var a;if(typeof t.filepath==="string"){a=o.normalize(t.filepath).replace(/\\/g,"/")}else if(t.filename||e&&(e.name||e.path)){a=o.basename(t.filename||e&&(e.name||e.path))}else if(e&&e.readable&&x(e,"httpVersion")){a=o.basename(e.client._httpMessage.path||"")}if(a){return'filename="'+a+'"'}};FormData.prototype._getContentType=function(e,t){var a=t.contentType;if(!a&&e&&e.name){a=d.lookup(e.name)}if(!a&&e&&e.path){a=d.lookup(e.path)}if(!a&&e&&e.readable&&x(e,"httpVersion")){a=e.headers["content-type"]}if(!a&&(t.filepath||t.filename)){a=d.lookup(t.filepath||t.filename)}if(!a&&e&&typeof e==="object"){a=FormData.DEFAULT_CONTENT_TYPE}return a};FormData.prototype._multiPartFooter=function(){return function(e){var t=FormData.LINE_BREAK;var a=this._streams.length===0;if(a){t+=this._lastBoundary()}e(t)}.bind(this)};FormData.prototype._lastBoundary=function(){return"--"+this.getBoundary()+"--"+FormData.LINE_BREAK};FormData.prototype.getHeaders=function(e){var t;var a={"content-type":"multipart/form-data; boundary="+this.getBoundary()};for(t in e){if(x(e,t)){a[t.toLowerCase()]=e[t]}}return a};FormData.prototype.setBoundary=function(e){if(typeof e!=="string"){throw new TypeError("FormData boundary must be a string")}this._boundary=e};FormData.prototype.getBoundary=function(){if(!this._boundary){this._generateBoundary()}return this._boundary};FormData.prototype.getBuffer=function(){var e=new Buffer.alloc(0);var t=this.getBoundary();for(var a=0,n=this._streams.length;a{"use strict";e.exports=function(e,t){Object.keys(t).forEach((function(a){e[a]=e[a]||t[a]}));return e}},9808:e=>{"use strict";var t="Function.prototype.bind called on incompatible ";var a=Object.prototype.toString;var n=Math.max;var i="[object Function]";var o=function concatty(e,t){var a=[];for(var n=0;n{"use strict";var n=a(9808);e.exports=Function.prototype.bind||n},470:(e,t,a)=>{"use strict";var n;var i=a(5399);var o=a(1620);var s=a(3056);var r=a(4585);var c=a(6905);var p=a(105);var l=a(3314);var u=a(2578);var d=a(5641);var m=a(6171);var f=a(7147);var x=a(1017);var h=a(6947);var v=a(2621);var b=a(156);var g=Function;var getEvalledConstructor=function(e){try{return g('"use strict"; return ('+e+").constructor;")()}catch(e){}};var y=a(3170);var w=a(9094);var throwTypeError=function(){throw new l};var _=y?function(){try{arguments.callee;return throwTypeError}catch(e){try{return y(arguments,"callee").get}catch(e){return throwTypeError}}}():throwTypeError;var E=a(3336)();var j=a(1967);var k=a(1311);var O=a(8681);var A=a(3945);var S=a(8093);var C={};var R=typeof Uint8Array==="undefined"||!j?n:j(Uint8Array);var P={__proto__:null,"%AggregateError%":typeof AggregateError==="undefined"?n:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer==="undefined"?n:ArrayBuffer,"%ArrayIteratorPrototype%":E&&j?j([][Symbol.iterator]()):n,"%AsyncFromSyncIteratorPrototype%":n,"%AsyncFunction%":C,"%AsyncGenerator%":C,"%AsyncGeneratorFunction%":C,"%AsyncIteratorPrototype%":C,"%Atomics%":typeof Atomics==="undefined"?n:Atomics,"%BigInt%":typeof BigInt==="undefined"?n:BigInt,"%BigInt64Array%":typeof BigInt64Array==="undefined"?n:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array==="undefined"?n:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView==="undefined"?n:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":o,"%eval%":eval,"%EvalError%":s,"%Float16Array%":typeof Float16Array==="undefined"?n:Float16Array,"%Float32Array%":typeof Float32Array==="undefined"?n:Float32Array,"%Float64Array%":typeof Float64Array==="undefined"?n:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry==="undefined"?n:FinalizationRegistry,"%Function%":g,"%GeneratorFunction%":C,"%Int8Array%":typeof Int8Array==="undefined"?n:Int8Array,"%Int16Array%":typeof Int16Array==="undefined"?n:Int16Array,"%Int32Array%":typeof Int32Array==="undefined"?n:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":E&&j?j(j([][Symbol.iterator]())):n,"%JSON%":typeof JSON==="object"?JSON:n,"%Map%":typeof Map==="undefined"?n:Map,"%MapIteratorPrototype%":typeof Map==="undefined"||!E||!j?n:j((new Map)[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":i,"%Object.getOwnPropertyDescriptor%":y,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise==="undefined"?n:Promise,"%Proxy%":typeof Proxy==="undefined"?n:Proxy,"%RangeError%":r,"%ReferenceError%":c,"%Reflect%":typeof Reflect==="undefined"?n:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set==="undefined"?n:Set,"%SetIteratorPrototype%":typeof Set==="undefined"||!E||!j?n:j((new Set)[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer==="undefined"?n:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":E&&j?j(""[Symbol.iterator]()):n,"%Symbol%":E?Symbol:n,"%SyntaxError%":p,"%ThrowTypeError%":_,"%TypedArray%":R,"%TypeError%":l,"%Uint8Array%":typeof Uint8Array==="undefined"?n:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray==="undefined"?n:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array==="undefined"?n:Uint16Array,"%Uint32Array%":typeof Uint32Array==="undefined"?n:Uint32Array,"%URIError%":u,"%WeakMap%":typeof WeakMap==="undefined"?n:WeakMap,"%WeakRef%":typeof WeakRef==="undefined"?n:WeakRef,"%WeakSet%":typeof WeakSet==="undefined"?n:WeakSet,"%Function.prototype.call%":S,"%Function.prototype.apply%":A,"%Object.defineProperty%":w,"%Object.getPrototypeOf%":k,"%Math.abs%":d,"%Math.floor%":m,"%Math.max%":f,"%Math.min%":x,"%Math.pow%":h,"%Math.round%":v,"%Math.sign%":b,"%Reflect.getPrototypeOf%":O};if(j){try{null.error}catch(e){var T=j(j(e));P["%Error.prototype%"]=T}}var D=function doEval(e){var t;if(e==="%AsyncFunction%"){t=getEvalledConstructor("async function () {}")}else if(e==="%GeneratorFunction%"){t=getEvalledConstructor("function* () {}")}else if(e==="%AsyncGeneratorFunction%"){t=getEvalledConstructor("async function* () {}")}else if(e==="%AsyncGenerator%"){var a=doEval("%AsyncGeneratorFunction%");if(a){t=a.prototype}}else if(e==="%AsyncIteratorPrototype%"){var n=doEval("%AsyncGenerator%");if(n&&j){t=j(n.prototype)}}P[e]=t;return t};var F={__proto__:null,"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]};var L=a(7564);var U=a(4076);var N=L.call(S,Array.prototype.concat);var I=L.call(A,Array.prototype.splice);var z=L.call(S,String.prototype.replace);var B=L.call(S,String.prototype.slice);var q=L.call(S,RegExp.prototype.exec);var $=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g;var M=/\\(\\)?/g;var H=function stringToPath(e){var t=B(e,0,1);var a=B(e,-1);if(t==="%"&&a!=="%"){throw new p("invalid intrinsic syntax, expected closing `%`")}else if(a==="%"&&t!=="%"){throw new p("invalid intrinsic syntax, expected opening `%`")}var n=[];z(e,$,(function(e,t,a,i){n[n.length]=a?z(i,M,"$1"):t||e}));return n};var V=function getBaseIntrinsic(e,t){var a=e;var n;if(U(F,a)){n=F[a];a="%"+n[0]+"%"}if(U(P,a)){var i=P[a];if(i===C){i=D(a)}if(typeof i==="undefined"&&!t){throw new l("intrinsic "+e+" exists, but is not available. Please file an issue!")}return{alias:n,name:a,value:i}}throw new p("intrinsic "+e+" does not exist!")};e.exports=function GetIntrinsic(e,t){if(typeof e!=="string"||e.length===0){throw new l("intrinsic name must be a non-empty string")}if(arguments.length>1&&typeof t!=="boolean"){throw new l('"allowMissing" argument must be a boolean')}if(q(/^%?[^%]*%?$/,e)===null){throw new p("`%` may not be present anywhere but at the beginning and end of the intrinsic name")}var a=H(e);var i=a.length>0?a[0]:"";var o=V("%"+i+"%",t);var s=o.name;var r=o.value;var c=false;var u=o.alias;if(u){i=u[0];I(a,N([0,1],u))}for(var d=1,m=true;d=a.length){var v=y(r,f);m=!!v;if(m&&"get"in v&&!("originalValue"in v.get)){r=v.get}else{r=r[f]}}else{m=U(r,f);r=r[f]}if(m&&!c){P[s]=r}}}return r}},1311:(e,t,a)=>{"use strict";var n=a(5399);e.exports=n.getPrototypeOf||null},8681:e=>{"use strict";e.exports=typeof Reflect!=="undefined"&&Reflect.getPrototypeOf||null},1967:(e,t,a)=>{"use strict";var n=a(8681);var i=a(1311);var o=a(6669);e.exports=n?function getProto(e){return n(e)}:i?function getProto(e){if(!e||typeof e!=="object"&&typeof e!=="function"){throw new TypeError("getProto: not an object")}return i(e)}:o?function getProto(e){return o(e)}:null},1174:e=>{"use strict";e.exports=Object.getOwnPropertyDescriptor},3170:(e,t,a)=>{"use strict";var n=a(1174);if(n){try{n([],"length")}catch(e){n=null}}e.exports=n},3813:e=>{"use strict";e.exports=(e,t=process.argv)=>{const a=e.startsWith("-")?"":e.length===1?"-":"--";const n=t.indexOf(a+e);const i=t.indexOf("--");return n!==-1&&(i===-1||n{"use strict";var n=typeof Symbol!=="undefined"&&Symbol;var i=a(1114);e.exports=function hasNativeSymbols(){if(typeof n!=="function"){return false}if(typeof Symbol!=="function"){return false}if(typeof n("foo")!=="symbol"){return false}if(typeof Symbol("bar")!=="symbol"){return false}return i()}},1114:e=>{"use strict";e.exports=function hasSymbols(){if(typeof Symbol!=="function"||typeof Object.getOwnPropertySymbols!=="function"){return false}if(typeof Symbol.iterator==="symbol"){return true}var e={};var t=Symbol("test");var a=Object(t);if(typeof t==="string"){return false}if(Object.prototype.toString.call(t)!=="[object Symbol]"){return false}if(Object.prototype.toString.call(a)!=="[object Symbol]"){return false}var n=42;e[t]=n;for(var i in e){return false}if(typeof Object.keys==="function"&&Object.keys(e).length!==0){return false}if(typeof Object.getOwnPropertyNames==="function"&&Object.getOwnPropertyNames(e).length!==0){return false}var o=Object.getOwnPropertySymbols(e);if(o.length!==1||o[0]!==t){return false}if(!Object.prototype.propertyIsEnumerable.call(e,t)){return false}if(typeof Object.getOwnPropertyDescriptor==="function"){var s=Object.getOwnPropertyDescriptor(e,t);if(s.value!==n||s.enumerable!==true){return false}}return true}},5479:(e,t,a)=>{"use strict";var n=a(1114);e.exports=function hasToStringTagShams(){return n()&&!!Symbol.toStringTag}},4076:(e,t,a)=>{"use strict";var n=Function.prototype.call;var i=Object.prototype.hasOwnProperty;var o=a(7564);e.exports=o.call(n,i)},5641:e=>{"use strict";e.exports=Math.abs},6171:e=>{"use strict";e.exports=Math.floor},7044:e=>{"use strict";e.exports=Number.isNaN||function isNaN(e){return e!==e}},7147:e=>{"use strict";e.exports=Math.max},1017:e=>{"use strict";e.exports=Math.min},6947:e=>{"use strict";e.exports=Math.pow},2621:e=>{"use strict";e.exports=Math.round},156:(e,t,a)=>{"use strict";var n=a(7044);e.exports=function sign(e){if(n(e)||e===0){return e}return e<0?-1:+1}},9829:(e,t,a)=>{ +/*! + * mime-db + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2015-2022 Douglas Christopher Wilson + * MIT Licensed + */ +e.exports=a(1813)},4096:(e,t,a)=>{"use strict"; +/*! + * mime-types + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */var n=a(9829);var i=a(6928).extname;var o=/^\s*([^;\s]*)(?:;|\s|$)/;var s=/^text\//i;t.charset=charset;t.charsets={lookup:charset};t.contentType=contentType;t.extension=extension;t.extensions=Object.create(null);t.lookup=lookup;t.types=Object.create(null);populateMaps(t.extensions,t.types);function charset(e){if(!e||typeof e!=="string"){return false}var t=o.exec(e);var a=t&&n[t[1].toLowerCase()];if(a&&a.charset){return a.charset}if(t&&s.test(t[1])){return"UTF-8"}return false}function contentType(e){if(!e||typeof e!=="string"){return false}var a=e.indexOf("/")===-1?t.lookup(e):e;if(!a){return false}if(a.indexOf("charset")===-1){var n=t.charset(a);if(n)a+="; charset="+n.toLowerCase()}return a}function extension(e){if(!e||typeof e!=="string"){return false}var a=o.exec(e);var n=a&&t.extensions[a[1].toLowerCase()];if(!n||!n.length){return false}return n[0]}function lookup(e){if(!e||typeof e!=="string"){return false}var a=i("x."+e).toLowerCase().substr(1);if(!a){return false}return t.types[a]||false}function populateMaps(e,t){var a=["nginx","apache",undefined,"iana"];Object.keys(n).forEach((function forEachMimeType(i){var o=n[i];var s=o.extensions;if(!s||!s.length){return}e[i]=s;for(var r=0;rl||p===l&&t[c].substr(0,12)==="application/")){continue}}t[c]=i}}))}},744:e=>{var t=1e3;var a=t*60;var n=a*60;var i=n*24;var o=i*7;var s=i*365.25;e.exports=function(e,t){t=t||{};var a=typeof e;if(a==="string"&&e.length>0){return parse(e)}else if(a==="number"&&isFinite(e)){return t.long?fmtLong(e):fmtShort(e)}throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function parse(e){e=String(e);if(e.length>100){return}var r=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!r){return}var c=parseFloat(r[1]);var p=(r[2]||"ms").toLowerCase();switch(p){case"years":case"year":case"yrs":case"yr":case"y":return c*s;case"weeks":case"week":case"w":return c*o;case"days":case"day":case"d":return c*i;case"hours":case"hour":case"hrs":case"hr":case"h":return c*n;case"minutes":case"minute":case"mins":case"min":case"m":return c*a;case"seconds":case"second":case"secs":case"sec":case"s":return c*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return undefined}}function fmtShort(e){var o=Math.abs(e);if(o>=i){return Math.round(e/i)+"d"}if(o>=n){return Math.round(e/n)+"h"}if(o>=a){return Math.round(e/a)+"m"}if(o>=t){return Math.round(e/t)+"s"}return e+"ms"}function fmtLong(e){var o=Math.abs(e);if(o>=i){return plural(e,o,i,"day")}if(o>=n){return plural(e,o,n,"hour")}if(o>=a){return plural(e,o,a,"minute")}if(o>=t){return plural(e,o,t,"second")}return e+" ms"}function plural(e,t,a,n){var i=t>=a*1.5;return Math.round(e/a)+" "+n+(i?"s":"")}},1450:(e,t,a)=>{"use strict";const n=a(857);const i=a(2018);const o=a(3813);const{env:s}=process;let r;if(o("no-color")||o("no-colors")||o("color=false")||o("color=never")){r=0}else if(o("color")||o("colors")||o("color=true")||o("color=always")){r=1}if("FORCE_COLOR"in s){if(s.FORCE_COLOR==="true"){r=1}else if(s.FORCE_COLOR==="false"){r=0}else{r=s.FORCE_COLOR.length===0?1:Math.min(parseInt(s.FORCE_COLOR,10),3)}}function translateLevel(e){if(e===0){return false}return{level:e,hasBasic:true,has256:e>=2,has16m:e>=3}}function supportsColor(e,t){if(r===0){return 0}if(o("color=16m")||o("color=full")||o("color=truecolor")){return 3}if(o("color=256")){return 2}if(e&&!t&&r===undefined){return 0}const a=r||0;if(s.TERM==="dumb"){return a}if(process.platform==="win32"){const e=n.release().split(".");if(Number(e[0])>=10&&Number(e[2])>=10586){return Number(e[2])>=14931?3:2}return 1}if("CI"in s){if(["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some((e=>e in s))||s.CI_NAME==="codeship"){return 1}return a}if("TEAMCITY_VERSION"in s){return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(s.TEAMCITY_VERSION)?1:0}if(s.COLORTERM==="truecolor"){return 3}if("TERM_PROGRAM"in s){const e=parseInt((s.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(s.TERM_PROGRAM){case"iTerm.app":return e>=3?3:2;case"Apple_Terminal":return 2}}if(/-256(color)?$/i.test(s.TERM)){return 2}if(/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(s.TERM)){return 1}if("COLORTERM"in s){return 1}return a}function getSupportLevel(e){const t=supportsColor(e,e&&e.isTTY);return translateLevel(t)}e.exports={supportsColor:getSupportLevel,stdout:translateLevel(supportsColor(true,i.isatty(1))),stderr:translateLevel(supportsColor(true,i.isatty(2)))}},2613:e=>{"use strict";e.exports=require("assert")},5317:e=>{"use strict";e.exports=require("child_process")},6982:e=>{"use strict";e.exports=require("crypto")},4434:e=>{"use strict";e.exports=require("events")},9896:e=>{"use strict";e.exports=require("fs")},8611:e=>{"use strict";e.exports=require("http")},5675:e=>{"use strict";e.exports=require("http2")},5692:e=>{"use strict";e.exports=require("https")},857:e=>{"use strict";e.exports=require("os")},6928:e=>{"use strict";e.exports=require("path")},2203:e=>{"use strict";e.exports=require("stream")},3193:e=>{"use strict";e.exports=require("string_decoder")},3557:e=>{"use strict";e.exports=require("timers")},2018:e=>{"use strict";e.exports=require("tty")},7016:e=>{"use strict";e.exports=require("url")},9023:e=>{"use strict";e.exports=require("util")},3106:e=>{"use strict";e.exports=require("zlib")},7269:(e,t,a)=>{"use strict"; +/*! Axios v1.16.0 Copyright (c) 2026 Matt Zabriskie and contributors */var n=a(6454);var i=a(6982);var o=a(7016);var s=a(8611);var r=a(5692);var c=a(5675);var p=a(9023);var l=a(6928);var u=a(1573);var d=a(3106);var m=a(2203);var f=a(4434);function bind(e,t){return function wrap(){return e.apply(t,arguments)}}const{toString:x}=Object.prototype;const{getPrototypeOf:h}=Object;const{iterator:v,toStringTag:b}=Symbol;const g=(e=>t=>{const a=x.call(t);return e[a]||(e[a]=a.slice(8,-1).toLowerCase())})(Object.create(null));const kindOfTest=e=>{e=e.toLowerCase();return t=>g(t)===e};const typeOfTest=e=>t=>typeof t===e;const{isArray:y}=Array;const w=typeOfTest("undefined");function isBuffer(e){return e!==null&&!w(e)&&e.constructor!==null&&!w(e.constructor)&&j(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const _=kindOfTest("ArrayBuffer");function isArrayBufferView(e){let t;if(typeof ArrayBuffer!=="undefined"&&ArrayBuffer.isView){t=ArrayBuffer.isView(e)}else{t=e&&e.buffer&&_(e.buffer)}return t}const E=typeOfTest("string");const j=typeOfTest("function");const k=typeOfTest("number");const isObject=e=>e!==null&&typeof e==="object";const isBoolean=e=>e===true||e===false;const isPlainObject=e=>{if(g(e)!=="object"){return false}const t=h(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(b in e)&&!(v in e)};const isEmptyObject=e=>{if(!isObject(e)||isBuffer(e)){return false}try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch(e){return false}};const O=kindOfTest("Date");const A=kindOfTest("File");const isReactNativeBlob=e=>!!(e&&typeof e.uri!=="undefined");const isReactNative=e=>e&&typeof e.getParts!=="undefined";const S=kindOfTest("Blob");const C=kindOfTest("FileList");const isStream=e=>isObject(e)&&j(e.pipe);function getGlobal(){if(typeof globalThis!=="undefined")return globalThis;if(typeof self!=="undefined")return self;if(typeof window!=="undefined")return window;if(typeof global!=="undefined")return global;return{}}const R=getGlobal();const P=typeof R.FormData!=="undefined"?R.FormData:undefined;const isFormData=e=>{if(!e)return false;if(P&&e instanceof P)return true;const t=h(e);if(!t||t===Object.prototype)return false;if(!j(e.append))return false;const a=g(e);return a==="formdata"||a==="object"&&j(e.toString)&&e.toString()==="[object FormData]"};const T=kindOfTest("URLSearchParams");const[D,F,L,U]=["ReadableStream","Request","Response","Headers"].map(kindOfTest);const trim=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function forEach(e,t,{allOwnKeys:a=false}={}){if(e===null||typeof e==="undefined"){return}let n;let i;if(typeof e!=="object"){e=[e]}if(y(e)){for(n=0,i=e.length;n0){i=a[n];if(t===i.toLowerCase()){return i}}return null}const N=(()=>{if(typeof globalThis!=="undefined")return globalThis;return typeof self!=="undefined"?self:typeof window!=="undefined"?window:global})();const isContextDefined=e=>!w(e)&&e!==N;function merge(...e){const{caseless:t,skipUndefined:a}=isContextDefined(this)&&this||{};const n={};const assignValue=(e,i)=>{if(i==="__proto__"||i==="constructor"||i==="prototype"){return}const o=t&&findKey(n,i)||i;const s=B(n,o)?n[o]:undefined;if(isPlainObject(s)&&isPlainObject(e)){n[o]=merge(s,e)}else if(isPlainObject(e)){n[o]=merge({},e)}else if(y(e)){n[o]=e.slice()}else if(!a||!w(e)){n[o]=e}};for(let t=0,a=e.length;t{forEach(t,((t,n)=>{if(a&&j(t)){Object.defineProperty(e,n,{__proto__:null,value:bind(t,a),writable:true,enumerable:true,configurable:true})}else{Object.defineProperty(e,n,{__proto__:null,value:t,writable:true,enumerable:true,configurable:true})}}),{allOwnKeys:n});return e};const stripBOM=e=>{if(e.charCodeAt(0)===65279){e=e.slice(1)}return e};const inherits=(e,t,a,n)=>{e.prototype=Object.create(t.prototype,n);Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:true,enumerable:false,configurable:true});Object.defineProperty(e,"super",{__proto__:null,value:t.prototype});a&&Object.assign(e.prototype,a)};const toFlatObject=(e,t,a,n)=>{let i;let o;let s;const r={};t=t||{};if(e==null)return t;do{i=Object.getOwnPropertyNames(e);o=i.length;while(o-- >0){s=i[o];if((!n||n(s,e,t))&&!r[s]){t[s]=e[s];r[s]=true}}e=a!==false&&h(e)}while(e&&(!a||a(e,t))&&e!==Object.prototype);return t};const endsWith=(e,t,a)=>{e=String(e);if(a===undefined||a>e.length){a=e.length}a-=t.length;const n=e.indexOf(t,a);return n!==-1&&n===a};const toArray=e=>{if(!e)return null;if(y(e))return e;let t=e.length;if(!k(t))return null;const a=new Array(t);while(t-- >0){a[t]=e[t]}return a};const I=(e=>t=>e&&t instanceof e)(typeof Uint8Array!=="undefined"&&h(Uint8Array));const forEachEntry=(e,t)=>{const a=e&&e[v];const n=a.call(e);let i;while((i=n.next())&&!i.done){const a=i.value;t.call(e,a[0],a[1])}};const matchAll=(e,t)=>{let a;const n=[];while((a=e.exec(t))!==null){n.push(a)}return n};const z=kindOfTest("HTMLFormElement");const toCamelCase=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,(function replacer(e,t,a){return t.toUpperCase()+a}));const B=(({hasOwnProperty:e})=>(t,a)=>e.call(t,a))(Object.prototype);const q=kindOfTest("RegExp");const reduceDescriptors=(e,t)=>{const a=Object.getOwnPropertyDescriptors(e);const n={};forEach(a,((a,i)=>{let o;if((o=t(a,i,e))!==false){n[i]=o||a}}));Object.defineProperties(e,n)};const freezeMethods=e=>{reduceDescriptors(e,((t,a)=>{if(j(e)&&["arguments","caller","callee"].includes(a)){return false}const n=e[a];if(!j(n))return;t.enumerable=false;if("writable"in t){t.writable=false;return}if(!t.set){t.set=()=>{throw Error("Can not rewrite read-only method '"+a+"'")}}}))};const toObjectSet=(e,t)=>{const a={};const define=e=>{e.forEach((e=>{a[e]=true}))};y(e)?define(e):define(String(e).split(t));return a};const noop=()=>{};const toFiniteNumber=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function isSpecCompliantForm(e){return!!(e&&j(e.append)&&e[b]==="FormData"&&e[v])}const toJSONObject=e=>{const t=new Array(10);const visit=(e,a)=>{if(isObject(e)){if(t.indexOf(e)>=0){return}if(isBuffer(e)){return e}if(!("toJSON"in e)){t[a]=e;const n=y(e)?[]:{};forEach(e,((e,t)=>{const i=visit(e,a+1);!w(i)&&(n[t]=i)}));t[a]=undefined;return n}}return e};return visit(e,0)};const $=kindOfTest("AsyncFunction");const isThenable=e=>e&&(isObject(e)||j(e))&&j(e.then)&&j(e.catch);const M=((e,t)=>{if(e){return setImmediate}return t?((e,t)=>{N.addEventListener("message",(({source:a,data:n})=>{if(a===N&&n===e){t.length&&t.shift()()}}),false);return a=>{t.push(a);N.postMessage(e,"*")}})(`axios@${Math.random()}`,[]):e=>setTimeout(e)})(typeof setImmediate==="function",j(N.postMessage));const H=typeof queueMicrotask!=="undefined"?queueMicrotask.bind(N):typeof process!=="undefined"&&process.nextTick||M;const isIterable=e=>e!=null&&j(e[v]);var V={isArray:y,isArrayBuffer:_,isBuffer:isBuffer,isFormData:isFormData,isArrayBufferView:isArrayBufferView,isString:E,isNumber:k,isBoolean:isBoolean,isObject:isObject,isPlainObject:isPlainObject,isEmptyObject:isEmptyObject,isReadableStream:D,isRequest:F,isResponse:L,isHeaders:U,isUndefined:w,isDate:O,isFile:A,isReactNativeBlob:isReactNativeBlob,isReactNative:isReactNative,isBlob:S,isRegExp:q,isFunction:j,isStream:isStream,isURLSearchParams:T,isTypedArray:I,isFileList:C,forEach:forEach,merge:merge,extend:extend,trim:trim,stripBOM:stripBOM,inherits:inherits,toFlatObject:toFlatObject,kindOf:g,kindOfTest:kindOfTest,endsWith:endsWith,toArray:toArray,forEachEntry:forEachEntry,matchAll:matchAll,isHTMLForm:z,hasOwnProperty:B,hasOwnProp:B,reduceDescriptors:reduceDescriptors,freezeMethods:freezeMethods,toObjectSet:toObjectSet,toCamelCase:toCamelCase,noop:noop,toFiniteNumber:toFiniteNumber,findKey:findKey,global:N,isContextDefined:isContextDefined,isSpecCompliantForm:isSpecCompliantForm,toJSONObject:toJSONObject,isAsyncFn:$,isThenable:isThenable,setImmediate:M,asap:H,isIterable:isIterable};const W=V.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]);var parseHeaders=e=>{const t={};let a;let n;let i;e&&e.split("\n").forEach((function parser(e){i=e.indexOf(":");a=e.substring(0,i).trim().toLowerCase();n=e.substring(i+1).trim();if(!a||t[a]&&W[a]){return}if(a==="set-cookie"){if(t[a]){t[a].push(n)}else{t[a]=[n]}}else{t[a]=t[a]?t[a]+", "+n:n}}));return t};const G=Symbol("internals");const J=/[^\x09\x20-\x7E\x80-\xFF]/g;function trimSPorHTAB(e){let t=0;let a=e.length;while(tt){const t=e.charCodeAt(a-1);if(t!==9&&t!==32){break}a-=1}return t===0&&a===e.length?e:e.slice(t,a)}function normalizeHeader(e){return e&&String(e).trim().toLowerCase()}function sanitizeHeaderValue(e){return trimSPorHTAB(e.replace(J,""))}function normalizeValue(e){if(e===false||e==null){return e}return V.isArray(e)?e.map(normalizeValue):sanitizeHeaderValue(String(e))}function parseTokens(e){const t=Object.create(null);const a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let n;while(n=a.exec(e)){t[n[1]]=n[2]}return t}const isValidHeaderName=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function matchHeaderValue(e,t,a,n,i){if(V.isFunction(n)){return n.call(this,t,a)}if(i){t=a}if(!V.isString(t))return;if(V.isString(n)){return t.indexOf(n)!==-1}if(V.isRegExp(n)){return n.test(t)}}function formatHeader(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,((e,t,a)=>t.toUpperCase()+a))}function buildAccessors(e,t){const a=V.toCamelCase(" "+t);["get","set","has"].forEach((n=>{Object.defineProperty(e,n+a,{__proto__:null,value:function(e,a,i){return this[n].call(this,t,e,a,i)},configurable:true})}))}class AxiosHeaders{constructor(e){e&&this.set(e)}set(e,t,a){const n=this;function setHeader(e,t,a){const i=normalizeHeader(t);if(!i){throw new Error("header name must be a non-empty string")}const o=V.findKey(n,i);if(!o||n[o]===undefined||a===true||a===undefined&&n[o]!==false){n[o||t]=normalizeValue(e)}}const setHeaders=(e,t)=>V.forEach(e,((e,a)=>setHeader(e,a,t)));if(V.isPlainObject(e)||e instanceof this.constructor){setHeaders(e,t)}else if(V.isString(e)&&(e=e.trim())&&!isValidHeaderName(e)){setHeaders(parseHeaders(e),t)}else if(V.isObject(e)&&V.isIterable(e)){let a={},n,i;for(const t of e){if(!V.isArray(t)){throw TypeError("Object iterator must return a key-value pair")}a[i=t[0]]=(n=a[i])?V.isArray(n)?[...n,t[1]]:[n,t[1]]:t[1]}setHeaders(a,t)}else{e!=null&&setHeader(t,e,a)}return this}get(e,t){e=normalizeHeader(e);if(e){const a=V.findKey(this,e);if(a){const e=this[a];if(!t){return e}if(t===true){return parseTokens(e)}if(V.isFunction(t)){return t.call(this,e,a)}if(V.isRegExp(t)){return t.exec(e)}throw new TypeError("parser must be boolean|regexp|function")}}}has(e,t){e=normalizeHeader(e);if(e){const a=V.findKey(this,e);return!!(a&&this[a]!==undefined&&(!t||matchHeaderValue(this,this[a],a,t)))}return false}delete(e,t){const a=this;let n=false;function deleteHeader(e){e=normalizeHeader(e);if(e){const i=V.findKey(a,e);if(i&&(!t||matchHeaderValue(a,a[i],i,t))){delete a[i];n=true}}}if(V.isArray(e)){e.forEach(deleteHeader)}else{deleteHeader(e)}return n}clear(e){const t=Object.keys(this);let a=t.length;let n=false;while(a--){const i=t[a];if(!e||matchHeaderValue(this,this[i],i,e,true)){delete this[i];n=true}}return n}normalize(e){const t=this;const a={};V.forEach(this,((n,i)=>{const o=V.findKey(a,i);if(o){t[o]=normalizeValue(n);delete t[i];return}const s=e?formatHeader(i):String(i).trim();if(s!==i){delete t[i]}t[s]=normalizeValue(n);a[s]=true}));return this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const t=Object.create(null);V.forEach(this,((a,n)=>{a!=null&&a!==false&&(t[n]=e&&V.isArray(a)?a.join(", "):a)}));return t}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map((([e,t])=>e+": "+t)).join("\n")}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...t){const a=new this(e);t.forEach((e=>a.set(e)));return a}static accessor(e){const t=this[G]=this[G]={accessors:{}};const a=t.accessors;const n=this.prototype;function defineAccessor(e){const t=normalizeHeader(e);if(!a[t]){buildAccessors(n,e);a[t]=true}}V.isArray(e)?e.forEach(defineAccessor):defineAccessor(e);return this}}AxiosHeaders.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);V.reduceDescriptors(AxiosHeaders.prototype,(({value:e},t)=>{let a=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(e){this[a]=e}}}));V.freezeMethods(AxiosHeaders);const K="[REDACTED ****]";function hasOwnOrPrototypeToJSON(e){if(V.hasOwnProp(e,"toJSON")){return true}let t=Object.getPrototypeOf(e);while(t&&t!==Object.prototype){if(V.hasOwnProp(t,"toJSON")){return true}t=Object.getPrototypeOf(t)}return false}function redactConfig(e,t){const a=new Set(t.map((e=>String(e).toLowerCase())));const n=[];const visit=e=>{if(e===null||typeof e!=="object")return e;if(V.isBuffer(e))return e;if(n.indexOf(e)!==-1)return undefined;if(e instanceof AxiosHeaders){e=e.toJSON()}n.push(e);let t;if(V.isArray(e)){t=[];e.forEach(((e,a)=>{const n=visit(e);if(!V.isUndefined(n)){t[a]=n}}))}else{if(!V.isPlainObject(e)&&hasOwnOrPrototypeToJSON(e)){n.pop();return e}t=Object.create(null);for(const[n,i]of Object.entries(e)){const e=a.has(n.toLowerCase())?K:visit(i);if(!V.isUndefined(e)){t[n]=e}}}n.pop();return t};return visit(e)}class AxiosError extends Error{static from(e,t,a,n,i,o){const s=new AxiosError(e.message,t||e.code,a,n,i);s.cause=e;s.name=e.name;if(e.status!=null&&s.status==null){s.status=e.status}o&&Object.assign(s,o);return s}constructor(e,t,a,n,i){super(e);Object.defineProperty(this,"message",{__proto__:null,value:e,enumerable:true,writable:true,configurable:true});this.name="AxiosError";this.isAxiosError=true;t&&(this.code=t);a&&(this.config=a);n&&(this.request=n);if(i){this.response=i;this.status=i.status}}toJSON(){const e=this.config;const t=e&&V.hasOwnProp(e,"redact")?e.redact:undefined;const a=V.isArray(t)&&t.length>0?redactConfig(e,t):V.toJSONObject(e);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:a,code:this.code,status:this.status}}}AxiosError.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";AxiosError.ERR_BAD_OPTION="ERR_BAD_OPTION";AxiosError.ECONNABORTED="ECONNABORTED";AxiosError.ETIMEDOUT="ETIMEDOUT";AxiosError.ECONNREFUSED="ECONNREFUSED";AxiosError.ERR_NETWORK="ERR_NETWORK";AxiosError.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";AxiosError.ERR_DEPRECATED="ERR_DEPRECATED";AxiosError.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";AxiosError.ERR_BAD_REQUEST="ERR_BAD_REQUEST";AxiosError.ERR_CANCELED="ERR_CANCELED";AxiosError.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";AxiosError.ERR_INVALID_URL="ERR_INVALID_URL";AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";function isVisitable(e){return V.isPlainObject(e)||V.isArray(e)}function removeBrackets(e){return V.endsWith(e,"[]")?e.slice(0,-2):e}function renderKey(e,t,a){if(!e)return t;return e.concat(t).map((function each(e,t){e=removeBrackets(e);return!a&&t?"["+e+"]":e})).join(a?".":"")}function isFlatArray(e){return V.isArray(e)&&!e.some(isVisitable)}const X=V.toFlatObject(V,{},null,(function filter(e){return/^is[A-Z]/.test(e)}));function toFormData(e,t,a){if(!V.isObject(e)){throw new TypeError("target must be an object")}t=t||new(n||FormData);a=V.toFlatObject(a,{metaTokens:true,dots:false,indexes:false},false,(function defined(e,t){return!V.isUndefined(t[e])}));const i=a.metaTokens;const o=a.visitor||defaultVisitor;const s=a.dots;const r=a.indexes;const c=a.Blob||typeof Blob!=="undefined"&&Blob;const p=a.maxDepth===undefined?100:a.maxDepth;const l=c&&V.isSpecCompliantForm(t);if(!V.isFunction(o)){throw new TypeError("visitor must be a function")}function convertValue(e){if(e===null)return"";if(V.isDate(e)){return e.toISOString()}if(V.isBoolean(e)){return e.toString()}if(!l&&V.isBlob(e)){throw new AxiosError("Blob is not supported. Use a Buffer instead.")}if(V.isArrayBuffer(e)||V.isTypedArray(e)){return l&&typeof Blob==="function"?new Blob([e]):Buffer.from(e)}return e}function defaultVisitor(e,a,n){let o=e;if(V.isReactNative(t)&&V.isReactNativeBlob(e)){t.append(renderKey(n,a,s),convertValue(e));return false}if(e&&!n&&typeof e==="object"){if(V.endsWith(a,"{}")){a=i?a:a.slice(0,-2);e=JSON.stringify(e)}else if(V.isArray(e)&&isFlatArray(e)||(V.isFileList(e)||V.endsWith(a,"[]"))&&(o=V.toArray(e))){a=removeBrackets(a);o.forEach((function each(e,n){!(V.isUndefined(e)||e===null)&&t.append(r===true?renderKey([a],n,s):r===null?a:a+"[]",convertValue(e))}));return false}}if(isVisitable(e)){return true}t.append(renderKey(n,a,s),convertValue(e));return false}const u=[];const d=Object.assign(X,{defaultVisitor:defaultVisitor,convertValue:convertValue,isVisitable:isVisitable});function build(e,a,n=0){if(V.isUndefined(e))return;if(n>p){throw new AxiosError("Object is too deeply nested ("+n+" levels). Max depth: "+p,AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED)}if(u.indexOf(e)!==-1){throw Error("Circular reference detected in "+a.join("."))}u.push(e);V.forEach(e,(function each(e,i){const s=!(V.isUndefined(e)||e===null)&&o.call(t,e,V.isString(i)?i.trim():i,a,d);if(s===true){build(e,a?a.concat(i):[i],n+1)}}));u.pop()}if(!V.isObject(e)){throw new TypeError("data must be an object")}build(e);return t}function encode$1(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,(function replacer(e){return t[e]}))}function AxiosURLSearchParams(e,t){this._pairs=[];e&&toFormData(e,this,t)}const Z=AxiosURLSearchParams.prototype;Z.append=function append(e,t){this._pairs.push([e,t])};Z.toString=function toString(e){const t=e?function(t){return e.call(this,t,encode$1)}:encode$1;return this._pairs.map((function each(e){return t(e[0])+"="+t(e[1])}),"").join("&")};function encode(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function buildURL(e,t,a){if(!t){return e}const n=a&&a.encode||encode;const i=V.isFunction(a)?{serialize:a}:a;const o=i&&i.serialize;let s;if(o){s=o(t,i)}else{s=V.isURLSearchParams(t)?t.toString():new AxiosURLSearchParams(t,i).toString(n)}if(s){const t=e.indexOf("#");if(t!==-1){e=e.slice(0,t)}e+=(e.indexOf("?")===-1?"?":"&")+s}return e}class InterceptorManager{constructor(){this.handlers=[]}use(e,t,a){this.handlers.push({fulfilled:e,rejected:t,synchronous:a?a.synchronous:false,runWhen:a?a.runWhen:null});return this.handlers.length-1}eject(e){if(this.handlers[e]){this.handlers[e]=null}}clear(){if(this.handlers){this.handlers=[]}}forEach(e){V.forEach(this.handlers,(function forEachHandler(t){if(t!==null){e(t)}}))}}var Y={silentJSONParsing:true,forcedJSONParsing:true,clarifyTimeoutError:false,legacyInterceptorReqResOrdering:true};var Q=o.URLSearchParams;const ee="abcdefghijklmnopqrstuvwxyz";const te="0123456789";const ae={DIGIT:te,ALPHA:ee,ALPHA_DIGIT:ee+ee.toUpperCase()+te};const generateString=(e=16,t=ae.ALPHA_DIGIT)=>{let a="";const{length:n}=t;const o=new Uint32Array(e);i.randomFillSync(o);for(let i=0;itypeof WorkerGlobalScope!=="undefined"&&self instanceof WorkerGlobalScope&&typeof self.importScripts==="function")();const ce=ie&&window.location.href||"http://localhost";var pe=Object.freeze({__proto__:null,hasBrowserEnv:ie,hasStandardBrowserEnv:se,hasStandardBrowserWebWorkerEnv:re,navigator:oe,origin:ce});var le={...pe,...ne};function toURLEncodedForm(e,t){return toFormData(e,new le.classes.URLSearchParams,{visitor:function(e,t,a,n){if(le.isNode&&V.isBuffer(e)){this.append(t,e.toString("base64"));return false}return n.defaultVisitor.apply(this,arguments)},...t})}function parsePropPath(e){return V.matchAll(/\w+|\[(\w*)]/g,e).map((e=>e[0]==="[]"?"":e[1]||e[0]))}function arrayToObject(e){const t={};const a=Object.keys(e);let n;const i=a.length;let o;for(n=0;n=e.length;i=!i&&V.isArray(a)?a.length:i;if(s){if(V.hasOwnProp(a,i)){a[i]=V.isArray(a[i])?a[i].concat(t):[a[i],t]}else{a[i]=t}return!o}if(!a[i]||!V.isObject(a[i])){a[i]=[]}const r=buildPath(e,t,a[i],n);if(r&&V.isArray(a[i])){a[i]=arrayToObject(a[i])}return!o}if(V.isFormData(e)&&V.isFunction(e.entries)){const t={};V.forEachEntry(e,((e,a)=>{buildPath(parsePropPath(e),a,t,0)}));return t}return null}const own=(e,t)=>e!=null&&V.hasOwnProp(e,t)?e[t]:undefined;function stringifySafely(e,t,a){if(V.isString(e)){try{(t||JSON.parse)(e);return V.trim(e)}catch(e){if(e.name!=="SyntaxError"){throw e}}}return(a||JSON.stringify)(e)}const ue={transitional:Y,adapter:["xhr","http","fetch"],transformRequest:[function transformRequest(e,t){const a=t.getContentType()||"";const n=a.indexOf("application/json")>-1;const i=V.isObject(e);if(i&&V.isHTMLForm(e)){e=new FormData(e)}const o=V.isFormData(e);if(o){return n?JSON.stringify(formDataToJSON(e)):e}if(V.isArrayBuffer(e)||V.isBuffer(e)||V.isStream(e)||V.isFile(e)||V.isBlob(e)||V.isReadableStream(e)){return e}if(V.isArrayBufferView(e)){return e.buffer}if(V.isURLSearchParams(e)){t.setContentType("application/x-www-form-urlencoded;charset=utf-8",false);return e.toString()}let s;if(i){const t=own(this,"formSerializer");if(a.indexOf("application/x-www-form-urlencoded")>-1){return toURLEncodedForm(e,t).toString()}if((s=V.isFileList(e))||a.indexOf("multipart/form-data")>-1){const a=own(this,"env");const n=a&&a.FormData;return toFormData(s?{"files[]":e}:e,n&&new n,t)}}if(i||n){t.setContentType("application/json",false);return stringifySafely(e)}return e}],transformResponse:[function transformResponse(e){const t=own(this,"transitional")||ue.transitional;const a=t&&t.forcedJSONParsing;const n=own(this,"responseType");const i=n==="json";if(V.isResponse(e)||V.isReadableStream(e)){return e}if(e&&V.isString(e)&&(a&&!n||i)){const a=t&&t.silentJSONParsing;const n=!a&&i;try{return JSON.parse(e,own(this,"parseReviver"))}catch(e){if(n){if(e.name==="SyntaxError"){throw AxiosError.from(e,AxiosError.ERR_BAD_RESPONSE,this,null,own(this,"response"))}throw e}}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:le.classes.FormData,Blob:le.classes.Blob},validateStatus:function validateStatus(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":undefined}}};V.forEach(["delete","get","head","post","put","patch","query"],(e=>{ue.headers[e]={}}));function transformData(e,t){const a=this||ue;const n=t||a;const i=AxiosHeaders.from(n.headers);let o=n.data;V.forEach(e,(function transform(e){o=e.call(a,o,i.normalize(),t?t.status:undefined)}));i.normalize();return o}function isCancel(e){return!!(e&&e.__CANCEL__)}class CanceledError extends AxiosError{constructor(e,t,a){super(e==null?"canceled":e,AxiosError.ERR_CANCELED,t,a);this.name="CanceledError";this.__CANCEL__=true}}function settle(e,t,a){const n=a.config.validateStatus;if(!a.status||!n||n(a.status)){e(a)}else{t(new AxiosError("Request failed with status code "+a.status,a.status>=400&&a.status<500?AxiosError.ERR_BAD_REQUEST:AxiosError.ERR_BAD_RESPONSE,a.config,a.request,a))}}function isAbsoluteURL(e){if(typeof e!=="string"){return false}return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function combineURLs(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function buildFullPath(e,t,a){let n=!isAbsoluteURL(t);if(e&&(n||a===false)){return combineURLs(e,t)}return t}var de={ftp:21,gopher:70,http:80,https:443,ws:80,wss:443};function parseUrl(e){try{return new URL(e)}catch{return null}}function getProxyForUrl(e){var t=(typeof e==="string"?parseUrl(e):e)||{};var a=t.protocol;var n=t.host;var i=t.port;if(typeof n!=="string"||!n||typeof a!=="string"){return""}a=a.split(":",1)[0];n=n.replace(/:\d*$/,"");i=parseInt(i)||de[a]||0;if(!shouldProxy(n,i)){return""}var o=getEnv(a+"_proxy")||getEnv("all_proxy");if(o&&o.indexOf("://")===-1){o=a+"://"+o}return o}function shouldProxy(e,t){var a=getEnv("no_proxy").toLowerCase();if(!a){return true}if(a==="*"){return false}return a.split(/[,\s]/).every((function(a){if(!a){return true}var n=a.match(/^(.+):(\d+)$/);var i=n?n[1]:a;var o=n?parseInt(n[2]):0;if(o&&o!==t){return true}if(!/^[.*]/.test(i)){return e!==i}if(i.charAt(0)==="*"){i=i.slice(1)}return!e.endsWith(i)}))}function getEnv(e){return process.env[e.toLowerCase()]||process.env[e.toUpperCase()]||""}const me="1.16.0";function parseProtocol(e){const t=/^([-+\w]{1,25}):(?:\/\/)?/.exec(e);return t&&t[1]||""}const fe=/^(?:([^;]+);)?(?:[^;]+;)?(base64|),([\s\S]*)$/;function fromDataURI(e,t,a){const n=a&&a.Blob||le.classes.Blob;const i=parseProtocol(e);if(t===undefined&&n){t=true}if(i==="data"){e=i.length?e.slice(i.length+1):e;const a=fe.exec(e);if(!a){throw new AxiosError("Invalid URL",AxiosError.ERR_INVALID_URL)}const o=a[1];const s=a[2];const r=a[3];const c=Buffer.from(decodeURIComponent(r),s?"base64":"utf8");if(t){if(!n){throw new AxiosError("Blob is not supported",AxiosError.ERR_NOT_SUPPORT)}return new n([c],{type:o})}return c}throw new AxiosError("Unsupported protocol "+i,AxiosError.ERR_NOT_SUPPORT)}const xe=Symbol("internals");class AxiosTransformStream extends m.Transform{constructor(e){e=V.toFlatObject(e,{maxRate:0,chunkSize:64*1024,minChunkSize:100,timeWindow:500,ticksRate:2,samplesCount:15},null,((e,t)=>!V.isUndefined(t[e])));super({readableHighWaterMark:e.chunkSize});const t=this[xe]={timeWindow:e.timeWindow,chunkSize:e.chunkSize,maxRate:e.maxRate,minChunkSize:e.minChunkSize,bytesSeen:0,isCaptured:false,notifiedBytesLoaded:0,ts:Date.now(),bytes:0,onReadCallback:null};this.on("newListener",(e=>{if(e==="progress"){if(!t.isCaptured){t.isCaptured=true}}}))}_read(e){const t=this[xe];if(t.onReadCallback){t.onReadCallback()}return super._read(e)}_transform(e,t,a){const n=this[xe];const i=n.maxRate;const o=this.readableHighWaterMark;const s=n.timeWindow;const r=1e3/s;const c=i/r;const p=n.minChunkSize!==false?Math.max(n.minChunkSize,c*.01):0;const pushChunk=(e,t)=>{const a=Buffer.byteLength(e);n.bytesSeen+=a;n.bytes+=a;n.isCaptured&&this.emit("progress",n.bytesSeen);if(this.push(e)){process.nextTick(t)}else{n.onReadCallback=()=>{n.onReadCallback=null;process.nextTick(t)}}};const transformChunk=(e,t)=>{const a=Buffer.byteLength(e);let r=null;let l=o;let u;let d=0;if(i){const e=Date.now();if(!n.ts||(d=e-n.ts)>=s){n.ts=e;u=c-n.bytes;n.bytes=u<0?-u:0;d=0}u=c-n.bytes}if(i){if(u<=0){return setTimeout((()=>{t(null,e)}),s-d)}if(ul&&a-l>p){r=e.subarray(l);e=e.subarray(0,l)}pushChunk(e,r?()=>{process.nextTick(t,null,r)}:t)};transformChunk(e,(function transformNextChunk(e,t){if(e){return a(e)}if(t){transformChunk(t,transformNextChunk)}else{a(null)}}))}}const{asyncIterator:he}=Symbol;const readBlob=async function*(e){if(e.stream){yield*e.stream()}else if(e.arrayBuffer){yield await e.arrayBuffer()}else if(e[he]){yield*e[he]()}else{yield e}};const ve=le.ALPHABET.ALPHA_DIGIT+"-_";const be=typeof TextEncoder==="function"?new TextEncoder:new p.TextEncoder;const ge="\r\n";const ye=be.encode(ge);const we=2;class FormDataPart{constructor(e,t){const{escapeName:a}=this.constructor;const n=V.isString(t);let i=`Content-Disposition: form-data; name="${a(e)}"${!n&&t.name?`; filename="${a(t.name)}"`:""}${ge}`;if(n){t=be.encode(String(t).replace(/\r?\n|\r\n?/g,ge))}else{const e=String(t.type||"application/octet-stream").replace(/[\r\n]/g,"");i+=`Content-Type: ${e}${ge}`}this.headers=be.encode(i+ge);this.contentLength=n?t.byteLength:t.size;this.size=this.headers.byteLength+this.contentLength+we;this.name=e;this.value=t}async*encode(){yield this.headers;const{value:e}=this;if(V.isTypedArray(e)){yield e}else{yield*readBlob(e)}yield ye}static escapeName(e){return String(e).replace(/[\r\n"]/g,(e=>({"\r":"%0D","\n":"%0A",'"':"%22"}[e])))}}const formDataToStream=(e,t,a)=>{const{tag:n="form-data-boundary",size:i=25,boundary:o=n+"-"+le.generateString(i,ve)}=a||{};if(!V.isFormData(e)){throw TypeError("FormData instance required")}if(o.length<1||o.length>70){throw Error("boundary must be 1-70 characters long")}const s=be.encode("--"+o+ge);const r=be.encode("--"+o+"--"+ge);let c=r.byteLength;const p=Array.from(e.entries()).map((([e,t])=>{const a=new FormDataPart(e,t);c+=a.size;return a}));c+=s.byteLength*p.length;c=V.toFiniteNumber(c);const l={"Content-Type":`multipart/form-data; boundary=${o}`};if(Number.isFinite(c)){l["Content-Length"]=c}t&&t(l);return m.Readable.from(async function*(){for(const e of p){yield s;yield*e.encode()}yield r}())};class ZlibHeaderTransformStream extends m.Transform{__transform(e,t,a){this.push(e);a()}_transform(e,t,a){if(e.length!==0){this._transform=this.__transform;if(e[0]!==120){const e=Buffer.alloc(2);e[0]=120;e[1]=156;this.push(e,t)}}this.__transform(e,t,a)}}const callbackify=(e,t)=>V.isAsyncFn(e)?function(...a){const n=a.pop();e.apply(this,a).then((e=>{try{t?n(null,...t(e)):n(null,e)}catch(e){n(e)}}),n)}:e;const _e=new Set(["localhost"]);const isIPv4Loopback=e=>{const t=e.split(".");if(t.length!==4)return false;if(t[0]!=="127")return false;return t.every((e=>/^\d+$/.test(e)&&Number(e)>=0&&Number(e)<=255))};const isIPv6Loopback=e=>{if(e==="::1")return true;const t=e.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);if(t)return isIPv4Loopback(t[1]);const a=e.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);if(a){const e=parseInt(a[1],16);return e>=32512&&e<=32767}const n=e.split(":");if(n.length===8){for(let e=0;e<7;e++){if(!/^0+$/.test(n[e]))return false}return/^0*1$/.test(n[7])}return false};const isLoopback=e=>{if(!e)return false;if(_e.has(e))return true;if(isIPv4Loopback(e))return true;return isIPv6Loopback(e)};const Ee={http:80,https:443,ws:80,wss:443,ftp:21};const parseNoProxyEntry=e=>{let t=e;let a=0;if(t.charAt(0)==="["){const e=t.indexOf("]");if(e!==-1){const n=t.slice(1,e);const i=t.slice(e+1);if(i.charAt(0)===":"&&/^\d+$/.test(i.slice(1))){a=Number.parseInt(i.slice(1),10)}return[n,a]}}const n=t.indexOf(":");const i=t.lastIndexOf(":");if(n!==-1&&n===i&&/^\d+$/.test(t.slice(i+1))){a=Number.parseInt(t.slice(i+1),10);t=t.slice(0,i)}return[t,a]};const je=/^(?:::|(?:0{1,4}:){1,4}:|(?:0{1,4}:){5})ffff:(\d+\.\d+\.\d+\.\d+)$/i;const ke=/^(?:::|(?:0{1,4}:){1,4}:|(?:0{1,4}:){5})ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;const unmapIPv4MappedIPv6=e=>{if(typeof e!=="string"||e.indexOf(":")===-1)return e;const t=e.match(je);if(t)return t[1];const a=e.match(ke);if(a){const e=parseInt(a[1],16);const t=parseInt(a[2],16);return`${e>>8}.${e&255}.${t>>8}.${t&255}`}return e};const normalizeNoProxyHost=e=>{if(!e){return e}if(e.charAt(0)==="["&&e.charAt(e.length-1)==="]"){e=e.slice(1,-1)}return unmapIPv4MappedIPv6(e.replace(/\.+$/,""))};function shouldBypassProxy(e){let t;try{t=new URL(e)}catch(e){return false}const a=(process.env.no_proxy||process.env.NO_PROXY||"").toLowerCase();if(!a){return false}if(a==="*"){return true}const n=Number.parseInt(t.port,10)||Ee[t.protocol.split(":",1)[0]]||0;const i=normalizeNoProxyHost(t.hostname.toLowerCase());return a.split(/[\s,]+/).some((e=>{if(!e){return false}let[t,a]=parseNoProxyEntry(e);t=normalizeNoProxyHost(t);if(!t){return false}if(a&&a!==n){return false}if(t.charAt(0)==="*"){t=t.slice(1)}if(t.charAt(0)==="."){return i.endsWith(t)}return i===t||isLoopback(i)&&isLoopback(t)}))}function speedometer(e,t){e=e||10;const a=new Array(e);const n=new Array(e);let i=0;let o=0;let s;t=t!==undefined?t:1e3;return function push(r){const c=Date.now();const p=n[o];if(!s){s=c}a[i]=r;n[i]=c;let l=o;let u=0;while(l!==i){u+=a[l++];l=l%e}i=(i+1)%e;if(i===o){o=(o+1)%e}if(c-s{a=n;i=null;if(o){clearTimeout(o);o=null}e(...t)};const throttled=(...e)=>{const t=Date.now();const s=t-a;if(s>=n){invoke(e,t)}else{i=e;if(!o){o=setTimeout((()=>{o=null;invoke(i)}),n-s)}}};const flush=()=>i&&invoke(i);return[throttled,flush]}const progressEventReducer=(e,t,a=3)=>{let n=0;const i=speedometer(50,250);return throttle((a=>{const o=a.loaded;const s=a.lengthComputable?a.total:undefined;const r=s!=null?Math.min(o,s):o;const c=Math.max(0,r-n);const p=i(c);n=Math.max(n,r);const l={loaded:r,total:s,progress:s?r/s:undefined,bytes:c,rate:p?p:undefined,estimated:p&&s?(s-r)/p:undefined,event:a,lengthComputable:s!=null,[t?"download":"upload"]:true};e(l)}),a)};const progressEventDecorator=(e,t)=>{const a=e!=null;return[n=>t[0]({lengthComputable:a,total:e,loaded:n}),t[1]]};const asyncDecorator=e=>(...t)=>V.asap((()=>e(...t)));function estimateDataURLDecodedBytes(e){if(!e||typeof e!=="string")return 0;if(!e.startsWith("data:"))return 0;const t=e.indexOf(",");if(t<0)return 0;const a=e.slice(5,t);const n=e.slice(t+1);const i=/;base64/i.test(a);if(i){let e=n.length;const t=n.length;for(let a=0;a=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102)&&(i>=48&&i<=57||i>=65&&i<=70||i>=97&&i<=102);if(o){e-=2;a+=2}}}let a=0;let i=t-1;const tailIsPct3D=e=>e>=2&&n.charCodeAt(e-2)===37&&n.charCodeAt(e-1)===51&&(n.charCodeAt(e)===68||n.charCodeAt(e)===100);if(i>=0){if(n.charCodeAt(i)===61){a++;i--}else if(tailIsPct3D(i)){a++;i-=3}}if(a===1&&i>=0){if(n.charCodeAt(i)===61){a++}else if(tailIsPct3D(i)){a++}}const o=Math.floor(e/4);const s=o*3-(a||0);return s>0?s:0}if(typeof Buffer!=="undefined"&&typeof Buffer.byteLength==="function"){return Buffer.byteLength(n,"utf8")}let o=0;for(let e=0,t=n.length;e=55296&&a<=56319&&e+1=56320&&t<=57343){o+=4;e++}else{o+=3}}else{o+=3}}return o}const Oe={flush:d.constants.Z_SYNC_FLUSH,finishFlush:d.constants.Z_SYNC_FLUSH};const Ae={flush:d.constants.BROTLI_OPERATION_FLUSH,finishFlush:d.constants.BROTLI_OPERATION_FLUSH};const Se=V.isFunction(d.createBrotliDecompress);const{http:Ce,https:Re}=u;const Pe=/https:?/;const Te=["content-type","content-length"];function setFormDataHeaders$1(e,t,a){if(a!=="content-only"){e.set(t);return}Object.entries(t).forEach((([t,a])=>{if(Te.includes(t.toLowerCase())){e.set(t,a)}}))}const De=Symbol("axios.http.socketListener");const Fe=Symbol("axios.http.currentReq");const Le=le.protocols.map((e=>e+":"));const decodeURIComponentSafe=e=>{if(!V.isString(e)){return e}try{return decodeURIComponent(e)}catch(t){return e}};const flushOnFinish=(e,[t,a])=>{e.on("end",a).on("error",a);return t};class Http2Sessions{constructor(){this.sessions=Object.create(null)}getSession(e,t){t=Object.assign({sessionTimeout:1e3},t);let a=this.sessions[e];if(a){let e=a.length;for(let n=0;n{if(i){return}i=true;let t=a,o=t.length,s=o;while(s--){if(t[s][0]===n){if(o===1){delete this.sessions[e]}else{t.splice(s,1)}if(!n.closed){n.close()}return}}};const o=n.request;const{sessionTimeout:s}=t;if(s!=null){let e;let t=0;n.request=function(){const a=o.apply(this,arguments);t++;if(e){clearTimeout(e);e=null}a.once("close",(()=>{if(! --t){e=setTimeout((()=>{e=null;removeSession()}),s)}}));return a}}n.once("close",removeSession);let r=[n,t];a?a.push(r):a=this.sessions[e]=[r];return n}}const Ue=new Http2Sessions;function dispatchBeforeRedirect(e,t,a){if(e.beforeRedirects.proxy){e.beforeRedirects.proxy(e)}if(e.beforeRedirects.config){e.beforeRedirects.config(e,t,a)}}function setProxy(e,t,a,n){let i=t;if(!i&&i!==false){const e=getProxyForUrl(a);if(e){if(!shouldBypassProxy(a)){i=new URL(e)}}}if(n&&e.headers){for(const t of Object.keys(e.headers)){if(t.toLowerCase()==="proxy-authorization"){delete e.headers[t]}}}if(i){const t=i instanceof URL;const readProxyField=e=>t||V.hasOwnProp(i,e)?i[e]:undefined;const n=readProxyField("username");const o=readProxyField("password");let s=V.hasOwnProp(i,"auth")?i.auth:undefined;if(n){s=(n||"")+":"+(o||"")}if(s){const t=typeof s==="object";const a=t&&V.hasOwnProp(s,"username")?s.username:undefined;const n=t&&V.hasOwnProp(s,"password")?s.password:undefined;const o=Boolean(a||n);if(o){s=(a||"")+":"+(n||"")}else if(t){throw new AxiosError("Invalid proxy authorization",AxiosError.ERR_BAD_OPTION,{proxy:i})}const r=Buffer.from(s,"utf8").toString("base64");e.headers["Proxy-Authorization"]="Basic "+r}let r=false;for(const t of Object.keys(e.headers)){if(t.toLowerCase()==="host"){r=true;break}}if(!r){e.headers.host=e.hostname+(e.port?":"+e.port:"")}const c=readProxyField("hostname")||readProxyField("host");e.hostname=c;e.host=c;e.port=readProxyField("port");e.path=a;const p=readProxyField("protocol");if(p){e.protocol=p.includes(":")?p:`${p}:`}}e.beforeRedirects.proxy=function beforeRedirect(e){setProxy(e,t,e.href,true)}}const Ne=typeof process!=="undefined"&&V.kindOf(process)==="process";const wrapAsync=e=>new Promise(((t,a)=>{let n;let i;const done=(e,t)=>{if(i)return;i=true;n&&n(e,t)};const _resolve=e=>{done(e);t(e)};const _reject=e=>{done(e,true);a(e)};e(_resolve,_reject,(e=>n=e)).catch(_reject)}));const resolveFamily=({address:e,family:t})=>{if(!V.isString(e)){throw TypeError("address must be a string")}return{address:e,family:t||(e.indexOf(".")<0?6:4)}};const buildAddressEntry=(e,t)=>resolveFamily(V.isObject(e)?e:{address:e,family:t});const Ie={request(e,t){const a=e.protocol+"//"+e.hostname+":"+(e.port||(e.protocol==="https:"?443:80));const{http2Options:n,headers:i}=e;const o=Ue.getSession(a,n);const{HTTP2_HEADER_SCHEME:s,HTTP2_HEADER_METHOD:r,HTTP2_HEADER_PATH:p,HTTP2_HEADER_STATUS:l}=c.constants;const u={[s]:e.protocol.replace(":",""),[r]:e.method,[p]:e.path};V.forEach(i,((e,t)=>{t.charAt(0)!==":"&&(u[t]=e)}));const d=o.request(u);d.once("response",(e=>{const a=d;e=Object.assign({},e);const n=e[l];delete e[l];a.headers=e;a.statusCode=+n;t(a)}));return d}};var ze=Ne&&function httpAdapter(e){return wrapAsync((async function dispatchHttpRequest(t,a,n){const own=t=>V.hasOwnProp(e,t)?e[t]:undefined;let i=own("data");let o=own("lookup");let c=own("family");let u=own("httpVersion");if(u===undefined)u=1;let x=own("http2Options");const h=own("responseType");const v=own("responseEncoding");const b=e.method.toUpperCase();let g;let y=false;let w;let _;u=+u;if(Number.isNaN(u)){throw TypeError(`Invalid protocol version: '${e.httpVersion}' is not a number`)}if(u!==1&&u!==2){throw TypeError(`Unsupported protocol version '${u}'`)}const E=u===2;if(o){const e=callbackify(o,(e=>V.isArray(e)?e:[e]));o=(t,a,n)=>{e(t,a,((e,t,i)=>{if(e){return n(e)}const o=V.isArray(t)?t.map((e=>buildAddressEntry(e))):[buildAddressEntry(t,i)];a.all?n(e,o):n(e,o[0].address,o[0].family)}))}}const j=new f.EventEmitter;function abort(t){try{j.emit("abort",!t||t.type?new CanceledError(null,e,w):t)}catch(e){console.warn("emit error",e)}}function clearConnectPhaseTimer(){if(_){clearTimeout(_);_=null}}function createTimeoutError(){let t=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded";const a=e.transitional||Y;if(e.timeoutErrorMessage){t=e.timeoutErrorMessage}return new AxiosError(t,a.clarifyTimeoutError?AxiosError.ETIMEDOUT:AxiosError.ECONNABORTED,e,w)}j.once("abort",a);const onFinished=()=>{clearConnectPhaseTimer();if(e.cancelToken){e.cancelToken.unsubscribe(abort)}if(e.signal){e.signal.removeEventListener("abort",abort)}j.removeAllListeners()};if(e.cancelToken||e.signal){e.cancelToken&&e.cancelToken.subscribe(abort);if(e.signal){e.signal.aborted?abort():e.signal.addEventListener("abort",abort)}}n(((e,t)=>{g=true;clearConnectPhaseTimer();if(t){y=true;onFinished();return}const{data:a}=e;if(a instanceof m.Readable||a instanceof m.Duplex){const e=m.finished(a,(()=>{e();onFinished()}))}else{onFinished()}}));const k=buildFullPath(e.baseURL,e.url,e.allowAbsoluteUrls);const O=new URL(k,le.hasBrowserEnv?le.origin:undefined);const A=O.protocol||Le[0];if(A==="data:"){if(e.maxContentLength>-1){const t=String(e.url||k||"");const n=estimateDataURLDecodedBytes(t);if(n>e.maxContentLength){return a(new AxiosError("maxContentLength size of "+e.maxContentLength+" exceeded",AxiosError.ERR_BAD_RESPONSE,e))}}let n;if(b!=="GET"){return settle(t,a,{status:405,statusText:"method not allowed",headers:{},config:e})}try{n=fromDataURI(e.url,h==="blob",{Blob:e.env&&e.env.Blob})}catch(t){throw AxiosError.from(t,AxiosError.ERR_BAD_REQUEST,e)}if(h==="text"){n=n.toString(v);if(!v||v==="utf8"){n=V.stripBOM(n)}}else if(h==="stream"){n=m.Readable.from(n)}return settle(t,a,{data:n,status:200,statusText:"OK",headers:new AxiosHeaders,config:e})}if(Le.indexOf(A)===-1){return a(new AxiosError("Unsupported protocol "+A,AxiosError.ERR_BAD_REQUEST,e))}const S=AxiosHeaders.from(e.headers).normalize();S.set("User-Agent","axios/"+me,false);const{onUploadProgress:C,onDownloadProgress:R}=e;const P=e.maxRate;let T=undefined;let D=undefined;if(V.isSpecCompliantForm(i)){const e=S.getContentType(/boundary=([-_\w\d]{10,70})/i);i=formDataToStream(i,(e=>{S.set(e)}),{tag:`axios-${me}-boundary`,boundary:e&&e[1]||undefined})}else if(V.isFormData(i)&&V.isFunction(i.getHeaders)&&i.getHeaders!==Object.prototype.getHeaders){setFormDataHeaders$1(S,i.getHeaders(),own("formDataHeaderPolicy"));if(!S.hasContentLength()){try{const e=await p.promisify(i.getLength).call(i);Number.isFinite(e)&&e>=0&&S.setContentLength(e)}catch(e){}}}else if(V.isBlob(i)||V.isFile(i)){i.size&&S.setContentType(i.type||"application/octet-stream");S.setContentLength(i.size||0);i=m.Readable.from(readBlob(i))}else if(i&&!V.isStream(i)){if(Buffer.isBuffer(i));else if(V.isArrayBuffer(i)){i=Buffer.from(new Uint8Array(i))}else if(V.isString(i)){i=Buffer.from(i,"utf-8")}else{return a(new AxiosError("Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream",AxiosError.ERR_BAD_REQUEST,e))}S.setContentLength(i.length,false);if(e.maxBodyLength>-1&&i.length>e.maxBodyLength){return a(new AxiosError("Request body larger than maxBodyLength limit",AxiosError.ERR_BAD_REQUEST,e))}}const F=V.toFiniteNumber(S.getContentLength());if(V.isArray(P)){T=P[0];D=P[1]}else{T=D=P}if(i&&(C||T)){if(!V.isStream(i)){i=m.Readable.from(i,{objectMode:false})}i=m.pipeline([i,new AxiosTransformStream({maxRate:V.toFiniteNumber(T)})],V.noop);C&&i.on("progress",flushOnFinish(i,progressEventDecorator(F,progressEventReducer(asyncDecorator(C),false,3))))}let L=undefined;const U=own("auth");if(U){const e=U.username||"";const t=U.password||"";L=e+":"+t}if(!L&&O.username){const e=decodeURIComponentSafe(O.username);const t=decodeURIComponentSafe(O.password);L=e+":"+t}L&&S.delete("authorization");let N;try{N=buildURL(O.pathname+O.search,e.params,e.paramsSerializer).replace(/^\?/,"")}catch(t){const n=new Error(t.message);n.config=e;n.url=e.url;n.exists=true;return a(n)}S.set("Accept-Encoding","gzip, compress, deflate"+(Se?", br":""),false);const I=Object.assign(Object.create(null),{path:N,method:b,headers:S.toJSON(),agents:{http:e.httpAgent,https:e.httpsAgent},auth:L,protocol:A,family:c,beforeRedirect:dispatchBeforeRedirect,beforeRedirects:Object.create(null),http2Options:x});!V.isUndefined(o)&&(I.lookup=o);if(e.socketPath){if(typeof e.socketPath!=="string"){return a(new AxiosError("socketPath must be a string",AxiosError.ERR_BAD_OPTION_VALUE,e))}if(e.allowedSocketPaths!=null){const t=Array.isArray(e.allowedSocketPaths)?e.allowedSocketPaths:[e.allowedSocketPaths];const n=l.resolve(e.socketPath);const i=t.some((e=>typeof e==="string"&&l.resolve(e)===n));if(!i){return a(new AxiosError(`socketPath "${e.socketPath}" is not permitted by allowedSocketPaths`,AxiosError.ERR_BAD_OPTION_VALUE,e))}}I.socketPath=e.socketPath}else{I.hostname=O.hostname.startsWith("[")?O.hostname.slice(1,-1):O.hostname;I.port=O.port;setProxy(I,e.proxy,A+"//"+O.hostname+(O.port?":"+O.port:"")+I.path)}let z;let B=false;const q=Pe.test(I.protocol);I.agent=q?e.httpsAgent:e.httpAgent;if(E){z=Ie}else{const t=own("transport");if(t){z=t}else if(e.maxRedirects===0){z=q?r:s;B=true}else{if(e.maxRedirects){I.maxRedirects=e.maxRedirects}const t=own("beforeRedirect");if(t){I.beforeRedirects.config=t}z=q?Re:Ce}}if(e.maxBodyLength>-1){I.maxBodyLength=e.maxBodyLength}else{I.maxBodyLength=Infinity}I.insecureHTTPParser=Boolean(own("insecureHTTPParser"));w=z.request(I,(function handleResponse(n){clearConnectPhaseTimer();if(w.destroyed)return;const i=[n];const o=V.toFiniteNumber(n.headers["content-length"]);if(R||D){const p=new AxiosTransformStream({maxRate:V.toFiniteNumber(D)});R&&p.on("progress",flushOnFinish(p,progressEventDecorator(o,progressEventReducer(asyncDecorator(R),true,3))));i.push(p)}let s=n;const r=n.req||w;if(e.decompress!==false&&n.headers["content-encoding"]){if(b==="HEAD"||n.statusCode===204){delete n.headers["content-encoding"]}switch((n.headers["content-encoding"]||"").toLowerCase()){case"gzip":case"x-gzip":case"compress":case"x-compress":i.push(d.createUnzip(Oe));delete n.headers["content-encoding"];break;case"deflate":i.push(new ZlibHeaderTransformStream);i.push(d.createUnzip(Oe));delete n.headers["content-encoding"];break;case"br":if(Se){i.push(d.createBrotliDecompress(Ae));delete n.headers["content-encoding"]}}}s=i.length>1?m.pipeline(i,V.noop):i[0];const c={status:n.statusCode,statusText:n.statusMessage,headers:new AxiosHeaders(n.headers),config:e,request:r};if(h==="stream"){if(e.maxContentLength>-1){const l=e.maxContentLength;const u=s;async function*enforceMaxContentLength(){let t=0;for await(const a of u){t+=a.length;if(t>l){throw new AxiosError("maxContentLength size of "+l+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,r)}yield a}}s=m.Readable.from(enforceMaxContentLength(),{objectMode:false})}c.data=s;settle(t,a,c)}else{const f=[];let x=0;s.on("data",(function handleStreamData(t){f.push(t);x+=t.length;if(e.maxContentLength>-1&&x>e.maxContentLength){y=true;s.destroy();abort(new AxiosError("maxContentLength size of "+e.maxContentLength+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,r))}}));s.on("aborted",(function handlerStreamAborted(){if(y){return}const t=new AxiosError("stream has been aborted",AxiosError.ERR_BAD_RESPONSE,e,r,c);s.destroy(t);a(t)}));s.on("error",(function handleStreamError(t){if(y)return;a(AxiosError.from(t,null,e,r,c))}));s.on("end",(function handleStreamEnd(){try{let e=f.length===1?f[0]:Buffer.concat(f);if(h!=="arraybuffer"){e=e.toString(v);if(!v||v==="utf8"){e=V.stripBOM(e)}}c.data=e}catch(t){return a(AxiosError.from(t,null,e,c.request,c))}settle(t,a,c)}))}j.once("abort",(e=>{if(!s.destroyed){s.emit("error",e);s.destroy()}}))}));j.once("abort",(e=>{if(w.close){w.close()}else{w.destroy(e)}}));w.on("error",(function handleRequestError(t){a(AxiosError.from(t,null,e,w))}));const $=new Set;w.on("socket",(function handleRequestSocket(e){e.setKeepAlive(true,1e3*60);if(!e[De]){e.on("error",(function handleSocketError(t){const a=e[Fe];if(a&&!a.destroyed){a.destroy(t)}}));e[De]=true}e[Fe]=w;$.add(e)}));w.once("close",(function clearCurrentReq(){clearConnectPhaseTimer();for(const e of $){if(e[Fe]===w){e[Fe]=null}}$.clear()}));if(e.timeout){const t=parseInt(e.timeout,10);if(Number.isNaN(t)){abort(new AxiosError("error trying to parse `config.timeout` to int",AxiosError.ERR_BAD_OPTION_VALUE,e,w));return}const a=function handleTimeout(){if(g)return;abort(createTimeoutError())};if(B&&t>0){_=setTimeout(a,t)}w.setTimeout(t,a)}else{w.setTimeout(0)}if(V.isStream(i)){let t=false;let a=false;i.on("end",(()=>{t=true}));i.once("error",(e=>{a=true;w.destroy(e)}));i.on("close",(()=>{if(!t&&!a){abort(new CanceledError("Request stream has been aborted",e,w))}}));let n=i;if(e.maxBodyLength>-1&&e.maxRedirects===0){const t=e.maxBodyLength;let a=0;n=m.pipeline([i,new m.Transform({transform(n,i,o){a+=n.length;if(a>t){return o(new AxiosError("Request body larger than maxBodyLength limit",AxiosError.ERR_BAD_REQUEST,e,w))}o(null,n)}})],V.noop);n.on("error",(e=>{if(!w.destroyed)w.destroy(e)}))}n.pipe(w)}else{i&&w.write(i);w.end()}}))};var Be=le.hasStandardBrowserEnv?((e,t)=>a=>{a=new URL(a,le.origin);return e.protocol===a.protocol&&e.host===a.host&&(t||e.port===a.port)})(new URL(le.origin),le.navigator&&/(msie|trident)/i.test(le.navigator.userAgent)):()=>true;var qe=le.hasStandardBrowserEnv?{write(e,t,a,n,i,o,s){if(typeof document==="undefined")return;const r=[`${e}=${encodeURIComponent(t)}`];if(V.isNumber(a)){r.push(`expires=${new Date(a).toUTCString()}`)}if(V.isString(n)){r.push(`path=${n}`)}if(V.isString(i)){r.push(`domain=${i}`)}if(o===true){r.push("secure")}if(V.isString(s)){r.push(`SameSite=${s}`)}document.cookie=r.join("; ")},read(e){if(typeof document==="undefined")return null;const t=document.cookie.split(";");for(let a=0;ae instanceof AxiosHeaders?{...e}:e;function mergeConfig(e,t){t=t||{};const a=Object.create(null);Object.defineProperty(a,"hasOwnProperty",{__proto__:null,value:Object.prototype.hasOwnProperty,enumerable:false,writable:true,configurable:true});function getMergedValue(e,t,a,n){if(V.isPlainObject(e)&&V.isPlainObject(t)){return V.merge.call({caseless:n},e,t)}else if(V.isPlainObject(t)){return V.merge({},t)}else if(V.isArray(t)){return t.slice()}return t}function mergeDeepProperties(e,t,a,n){if(!V.isUndefined(t)){return getMergedValue(e,t,a,n)}else if(!V.isUndefined(e)){return getMergedValue(undefined,e,a,n)}}function valueFromConfig2(e,t){if(!V.isUndefined(t)){return getMergedValue(undefined,t)}}function defaultToConfig2(e,t){if(!V.isUndefined(t)){return getMergedValue(undefined,t)}else if(!V.isUndefined(e)){return getMergedValue(undefined,e)}}function mergeDirectKeys(a,n,i){if(V.hasOwnProp(t,i)){return getMergedValue(a,n)}else if(V.hasOwnProp(e,i)){return getMergedValue(undefined,a)}}const n={url:valueFromConfig2,method:valueFromConfig2,data:valueFromConfig2,baseURL:defaultToConfig2,transformRequest:defaultToConfig2,transformResponse:defaultToConfig2,paramsSerializer:defaultToConfig2,timeout:defaultToConfig2,timeoutMessage:defaultToConfig2,withCredentials:defaultToConfig2,withXSRFToken:defaultToConfig2,adapter:defaultToConfig2,responseType:defaultToConfig2,xsrfCookieName:defaultToConfig2,xsrfHeaderName:defaultToConfig2,onUploadProgress:defaultToConfig2,onDownloadProgress:defaultToConfig2,decompress:defaultToConfig2,maxContentLength:defaultToConfig2,maxBodyLength:defaultToConfig2,beforeRedirect:defaultToConfig2,transport:defaultToConfig2,httpAgent:defaultToConfig2,httpsAgent:defaultToConfig2,cancelToken:defaultToConfig2,socketPath:defaultToConfig2,allowedSocketPaths:defaultToConfig2,responseEncoding:defaultToConfig2,validateStatus:mergeDirectKeys,headers:(e,t,a)=>mergeDeepProperties(headersToObject(e),headersToObject(t),a,true)};V.forEach(Object.keys({...e,...t}),(function computeConfigValue(i){if(i==="__proto__"||i==="constructor"||i==="prototype")return;const o=V.hasOwnProp(n,i)?n[i]:mergeDeepProperties;const s=V.hasOwnProp(e,i)?e[i]:undefined;const r=V.hasOwnProp(t,i)?t[i]:undefined;const c=o(s,r,i);V.isUndefined(c)&&o!==mergeDirectKeys||(a[i]=c)}));return a}const $e=["content-type","content-length"];function setFormDataHeaders(e,t,a){if(a!=="content-only"){e.set(t);return}Object.entries(t).forEach((([t,a])=>{if($e.includes(t.toLowerCase())){e.set(t,a)}}))}const encodeUTF8=e=>encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,((e,t)=>String.fromCharCode(parseInt(t,16))));var resolveConfig=e=>{const t=mergeConfig({},e);const own=e=>V.hasOwnProp(t,e)?t[e]:undefined;const a=own("data");let n=own("withXSRFToken");const i=own("xsrfHeaderName");const o=own("xsrfCookieName");let s=own("headers");const r=own("auth");const c=own("baseURL");const p=own("allowAbsoluteUrls");const l=own("url");t.headers=s=AxiosHeaders.from(s);t.url=buildURL(buildFullPath(c,l,p),e.params,e.paramsSerializer);if(r){s.set("Authorization","Basic "+btoa((r.username||"")+":"+(r.password?encodeUTF8(r.password):"")))}if(V.isFormData(a)){if(le.hasStandardBrowserEnv||le.hasStandardBrowserWebWorkerEnv){s.setContentType(undefined)}else if(V.isFunction(a.getHeaders)){setFormDataHeaders(s,a.getHeaders(),own("formDataHeaderPolicy"))}}if(le.hasStandardBrowserEnv){if(V.isFunction(n)){n=n(t)}const e=n===true||n==null&&Be(t.url);if(e){const e=i&&o&&qe.read(o);if(e){s.set(i,e)}}}return t};const Me=typeof XMLHttpRequest!=="undefined";var He=Me&&function(e){return new Promise((function dispatchXhrRequest(t,a){const n=resolveConfig(e);let i=n.data;const o=AxiosHeaders.from(n.headers).normalize();let{responseType:s,onUploadProgress:r,onDownloadProgress:c}=n;let p;let l,u;let d,m;function done(){d&&d();m&&m();n.cancelToken&&n.cancelToken.unsubscribe(p);n.signal&&n.signal.removeEventListener("abort",p)}let f=new XMLHttpRequest;f.open(n.method.toUpperCase(),n.url,true);f.timeout=n.timeout;function onloadend(){if(!f){return}const n=AxiosHeaders.from("getAllResponseHeaders"in f&&f.getAllResponseHeaders());const i=!s||s==="text"||s==="json"?f.responseText:f.response;const o={data:i,status:f.status,statusText:f.statusText,headers:n,config:e,request:f};settle((function _resolve(e){t(e);done()}),(function _reject(e){a(e);done()}),o);f=null}if("onloadend"in f){f.onloadend=onloadend}else{f.onreadystatechange=function handleLoad(){if(!f||f.readyState!==4){return}if(f.status===0&&!(f.responseURL&&f.responseURL.startsWith("file:"))){return}setTimeout(onloadend)}}f.onabort=function handleAbort(){if(!f){return}a(new AxiosError("Request aborted",AxiosError.ECONNABORTED,e,f));done();f=null};f.onerror=function handleError(t){const n=t&&t.message?t.message:"Network Error";const i=new AxiosError(n,AxiosError.ERR_NETWORK,e,f);i.event=t||null;a(i);done();f=null};f.ontimeout=function handleTimeout(){let t=n.timeout?"timeout of "+n.timeout+"ms exceeded":"timeout exceeded";const i=n.transitional||Y;if(n.timeoutErrorMessage){t=n.timeoutErrorMessage}a(new AxiosError(t,i.clarifyTimeoutError?AxiosError.ETIMEDOUT:AxiosError.ECONNABORTED,e,f));done();f=null};i===undefined&&o.setContentType(null);if("setRequestHeader"in f){V.forEach(o.toJSON(),(function setRequestHeader(e,t){f.setRequestHeader(t,e)}))}if(!V.isUndefined(n.withCredentials)){f.withCredentials=!!n.withCredentials}if(s&&s!=="json"){f.responseType=n.responseType}if(c){[u,m]=progressEventReducer(c,true);f.addEventListener("progress",u)}if(r&&f.upload){[l,d]=progressEventReducer(r);f.upload.addEventListener("progress",l);f.upload.addEventListener("loadend",d)}if(n.cancelToken||n.signal){p=t=>{if(!f){return}a(!t||t.type?new CanceledError(null,e,f):t);f.abort();done();f=null};n.cancelToken&&n.cancelToken.subscribe(p);if(n.signal){n.signal.aborted?p():n.signal.addEventListener("abort",p)}}const x=parseProtocol(n.url);if(x&&!le.protocols.includes(x)){a(new AxiosError("Unsupported protocol "+x+":",AxiosError.ERR_BAD_REQUEST,e));return}f.send(i||null)}))};const composeSignals=(e,t)=>{const{length:a}=e=e?e.filter(Boolean):[];if(t||a){let a=new AbortController;let n;const onabort=function(e){if(!n){n=true;unsubscribe();const t=e instanceof Error?e:this.reason;a.abort(t instanceof AxiosError?t:new CanceledError(t instanceof Error?t.message:t))}};let i=t&&setTimeout((()=>{i=null;onabort(new AxiosError(`timeout of ${t}ms exceeded`,AxiosError.ETIMEDOUT))}),t);const unsubscribe=()=>{if(e){i&&clearTimeout(i);i=null;e.forEach((e=>{e.unsubscribe?e.unsubscribe(onabort):e.removeEventListener("abort",onabort)}));e=null}};e.forEach((e=>e.addEventListener("abort",onabort)));const{signal:o}=a;o.unsubscribe=()=>V.asap(unsubscribe);return o}};const streamChunk=function*(e,t){let a=e.byteLength;if(a{const i=readBytes(e,t);let o=0;let s;let _onFinish=e=>{if(!s){s=true;n&&n(e)}};return new ReadableStream({async pull(e){try{const{done:t,value:n}=await i.next();if(t){_onFinish();e.close();return}let s=n.byteLength;if(a){let e=o+=s;a(e)}e.enqueue(new Uint8Array(n))}catch(e){_onFinish(e);throw e}},cancel(e){_onFinish(e);return i.return()}},{highWaterMark:2})};const Ve=64*1024;const{isFunction:We}=V;const test=(e,...t)=>{try{return!!e(...t)}catch(e){return false}};const factory=e=>{var t;const a=(t=V.global)!==null&&t!==void 0?t:globalThis;const{ReadableStream:n,TextEncoder:i}=a;e=V.merge.call({skipUndefined:true},{Request:a.Request,Response:a.Response},e);const{fetch:o,Request:s,Response:r}=e;const c=o?We(o):typeof fetch==="function";const p=We(s);const l=We(r);if(!c){return false}const u=c&&We(n);const d=c&&(typeof i==="function"?(e=>t=>e.encode(t))(new i):async e=>new Uint8Array(await new s(e).arrayBuffer()));const m=p&&u&&test((()=>{let e=false;const t=new s(le.origin,{body:new n,method:"POST",get duplex(){e=true;return"half"}});const a=t.headers.has("Content-Type");if(t.body!=null){t.body.cancel()}return e&&!a}));const f=l&&u&&test((()=>V.isReadableStream(new r("").body)));const x={stream:f&&(e=>e.body)};c&&(()=>{["text","arrayBuffer","blob","formData","stream"].forEach((e=>{!x[e]&&(x[e]=(t,a)=>{let n=t&&t[e];if(n){return n.call(t)}throw new AxiosError(`Response type '${e}' is not supported`,AxiosError.ERR_NOT_SUPPORT,a)})}))})();const getBodyLength=async e=>{if(e==null){return 0}if(V.isBlob(e)){return e.size}if(V.isSpecCompliantForm(e)){const t=new s(le.origin,{method:"POST",body:e});return(await t.arrayBuffer()).byteLength}if(V.isArrayBufferView(e)||V.isArrayBuffer(e)){return e.byteLength}if(V.isURLSearchParams(e)){e=e+""}if(V.isString(e)){return(await d(e)).byteLength}};const resolveBodyLength=async(e,t)=>{const a=V.toFiniteNumber(e.getContentLength());return a==null?getBodyLength(t):a};return async e=>{let{url:t,method:a,data:n,signal:c,cancelToken:l,timeout:u,onDownloadProgress:d,onUploadProgress:h,responseType:v,headers:b,withCredentials:g="same-origin",fetchOptions:y,maxContentLength:w,maxBodyLength:_}=resolveConfig(e);const E=V.isNumber(w)&&w>-1;const j=V.isNumber(_)&&_>-1;let k=o||fetch;v=v?(v+"").toLowerCase():"text";let O=composeSignals([c,l&&l.toAbortSignal()],u);let A=null;const S=O&&O.unsubscribe&&(()=>{O.unsubscribe()});let C;try{if(E&&typeof t==="string"&&t.startsWith("data:")){const a=estimateDataURLDecodedBytes(t);if(a>w){throw new AxiosError("maxContentLength size of "+w+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,A)}}if(j&&a!=="get"&&a!=="head"){const t=await resolveBodyLength(b,n);if(typeof t==="number"&&isFinite(t)&&t>_){throw new AxiosError("Request body larger than maxBodyLength limit",AxiosError.ERR_BAD_REQUEST,e,A)}}if(h&&m&&a!=="get"&&a!=="head"&&(C=await resolveBodyLength(b,n))!==0){let e=new s(t,{method:"POST",body:n,duplex:"half"});let a;if(V.isFormData(n)&&(a=e.headers.get("content-type"))){b.setContentType(a)}if(e.body){const[t,a]=progressEventDecorator(C,progressEventReducer(asyncDecorator(h)));n=trackStream(e.body,Ve,t,a)}}if(!V.isString(g)){g=g?"include":"omit"}const o=p&&"credentials"in s.prototype;if(V.isFormData(n)){const e=b.getContentType();if(e&&/^multipart\/form-data/i.test(e)&&!/boundary=/i.test(e)){b.delete("content-type")}}b.set("User-Agent","axios/"+me,false);const c={...y,signal:O,method:a.toUpperCase(),headers:b.normalize().toJSON(),body:n,duplex:"half",credentials:o?g:undefined};A=p&&new s(t,c);let l=await(p?k(A,y):k(t,c));if(E){const t=V.toFiniteNumber(l.headers.get("content-length"));if(t!=null&&t>w){throw new AxiosError("maxContentLength size of "+w+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,A)}}const u=f&&(v==="stream"||v==="response");if(f&&l.body&&(d||E||u&&S)){const t={};["status","statusText","headers"].forEach((e=>{t[e]=l[e]}));const a=V.toFiniteNumber(l.headers.get("content-length"));const[n,i]=d&&progressEventDecorator(a,progressEventReducer(asyncDecorator(d),true))||[];let o=0;const onChunkProgress=t=>{if(E){o=t;if(o>w){throw new AxiosError("maxContentLength size of "+w+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,A)}}n&&n(t)};l=new r(trackStream(l.body,Ve,onChunkProgress,(()=>{i&&i();S&&S()})),t)}v=v||"text";let R=await x[V.findKey(x,v)||"text"](l,e);if(E&&!f&&!u){let t;if(R!=null){if(typeof R.byteLength==="number"){t=R.byteLength}else if(typeof R.size==="number"){t=R.size}else if(typeof R==="string"){t=typeof i==="function"?(new i).encode(R).byteLength:R.length}}if(typeof t==="number"&&t>w){throw new AxiosError("maxContentLength size of "+w+" exceeded",AxiosError.ERR_BAD_RESPONSE,e,A)}}!u&&S&&S();return await new Promise(((t,a)=>{settle(t,a,{data:R,headers:AxiosHeaders.from(l.headers),status:l.status,statusText:l.statusText,config:e,request:A})}))}catch(t){S&&S();if(O&&O.aborted&&O.reason instanceof AxiosError){const a=O.reason;a.config=e;A&&(a.request=A);t!==a&&(a.cause=t);throw a}if(t&&t.name==="TypeError"&&/Load failed|fetch/i.test(t.message)){throw Object.assign(new AxiosError("Network Error",AxiosError.ERR_NETWORK,e,A,t&&t.response),{cause:t.cause||t})}throw AxiosError.from(t,t&&t.code,e,A,t&&t.response)}}};const Ge=new Map;const getFetch=e=>{let t=e&&e.env||{};const{fetch:a,Request:n,Response:i}=t;const o=[n,i,a];let s=o.length,r=s,c,p,l=Ge;while(r--){c=o[r];p=l.get(c);p===undefined&&l.set(c,p=r?new Map:factory(t));l=p}return p};getFetch();const Je={http:ze,xhr:He,fetch:{get:getFetch}};V.forEach(Je,((e,t)=>{if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch(e){}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}}));const renderReason=e=>`- ${e}`;const isResolvedHandle=e=>V.isFunction(e)||e===null||e===false;function getAdapter(e,t){e=V.isArray(e)?e:[e];const{length:a}=e;let n;let i;const o={};for(let s=0;s`adapter ${e} `+(t===false?"is not supported by the environment":"is not available in the build")));let t=a?e.length>1?"since :\n"+e.map(renderReason).join("\n"):" "+renderReason(e[0]):"as no adapter specified";throw new AxiosError(`There is no suitable adapter to dispatch the request `+t,"ERR_NOT_SUPPORT")}return i}var Ke={getAdapter:getAdapter,adapters:Je};function throwIfCancellationRequested(e){if(e.cancelToken){e.cancelToken.throwIfRequested()}if(e.signal&&e.signal.aborted){throw new CanceledError(null,e)}}function dispatchRequest(e){throwIfCancellationRequested(e);e.headers=AxiosHeaders.from(e.headers);e.data=transformData.call(e,e.transformRequest);if(["post","put","patch"].indexOf(e.method)!==-1){e.headers.setContentType("application/x-www-form-urlencoded",false)}const t=Ke.getAdapter(e.adapter||ue.adapter,e);return t(e).then((function onAdapterResolution(t){throwIfCancellationRequested(e);e.response=t;try{t.data=transformData.call(e,e.transformResponse,t)}finally{delete e.response}t.headers=AxiosHeaders.from(t.headers);return t}),(function onAdapterRejection(t){if(!isCancel(t)){throwIfCancellationRequested(e);if(t&&t.response){e.response=t.response;try{t.response.data=transformData.call(e,e.transformResponse,t.response)}finally{delete e.response}t.response.headers=AxiosHeaders.from(t.response.headers)}}return Promise.reject(t)}))}const Xe={};["object","boolean","number","function","string","symbol"].forEach(((e,t)=>{Xe[e]=function validator(a){return typeof a===e||"a"+(t<1?"n ":" ")+e}}));const Ze={};Xe.transitional=function transitional(e,t,a){function formatMessage(e,t){return"[Axios v"+me+"] Transitional option '"+e+"'"+t+(a?". "+a:"")}return(a,n,i)=>{if(e===false){throw new AxiosError(formatMessage(n," has been removed"+(t?" in "+t:"")),AxiosError.ERR_DEPRECATED)}if(t&&!Ze[n]){Ze[n]=true;console.warn(formatMessage(n," has been deprecated since v"+t+" and will be removed in the near future"))}return e?e(a,n,i):true}};Xe.spelling=function spelling(e){return(t,a)=>{console.warn(`${a} is likely a misspelling of ${e}`);return true}};function assertOptions(e,t,a){if(typeof e!=="object"){throw new AxiosError("options must be an object",AxiosError.ERR_BAD_OPTION_VALUE)}const n=Object.keys(e);let i=n.length;while(i-- >0){const o=n[i];const s=Object.prototype.hasOwnProperty.call(t,o)?t[o]:undefined;if(s){const t=e[o];const a=t===undefined||s(t,o,e);if(a!==true){throw new AxiosError("option "+o+" must be "+a,AxiosError.ERR_BAD_OPTION_VALUE)}continue}if(a!==true){throw new AxiosError("Unknown option "+o,AxiosError.ERR_BAD_OPTION)}}}var Ye={assertOptions:assertOptions,validators:Xe};const Qe=Ye.validators;class Axios{constructor(e){this.defaults=e||{};this.interceptors={request:new InterceptorManager,response:new InterceptorManager}}async request(e,t){try{return await this._request(e,t)}catch(e){if(e instanceof Error){let t={};Error.captureStackTrace?Error.captureStackTrace(t):t=new Error;const a=(()=>{if(!t.stack){return""}const e=t.stack.indexOf("\n");return e===-1?"":t.stack.slice(e+1)})();try{if(!e.stack){e.stack=a}else if(a){const t=a.indexOf("\n");const n=t===-1?-1:a.indexOf("\n",t+1);const i=n===-1?"":a.slice(n+1);if(!String(e.stack).endsWith(i)){e.stack+="\n"+a}}}catch(e){}}throw e}}_request(e,t){if(typeof e==="string"){t=t||{};t.url=e}else{t=e||{}}t=mergeConfig(this.defaults,t);const{transitional:a,paramsSerializer:n,headers:i}=t;if(a!==undefined){Ye.assertOptions(a,{silentJSONParsing:Qe.transitional(Qe.boolean),forcedJSONParsing:Qe.transitional(Qe.boolean),clarifyTimeoutError:Qe.transitional(Qe.boolean),legacyInterceptorReqResOrdering:Qe.transitional(Qe.boolean)},false)}if(n!=null){if(V.isFunction(n)){t.paramsSerializer={serialize:n}}else{Ye.assertOptions(n,{encode:Qe.function,serialize:Qe.function},true)}}if(t.allowAbsoluteUrls!==undefined);else if(this.defaults.allowAbsoluteUrls!==undefined){t.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls}else{t.allowAbsoluteUrls=true}Ye.assertOptions(t,{baseUrl:Qe.spelling("baseURL"),withXsrfToken:Qe.spelling("withXSRFToken")},true);t.method=(t.method||this.defaults.method||"get").toLowerCase();let o=i&&V.merge(i.common,i[t.method]);i&&V.forEach(["delete","get","head","post","put","patch","query","common"],(e=>{delete i[e]}));t.headers=AxiosHeaders.concat(o,i);const s=[];let r=true;this.interceptors.request.forEach((function unshiftRequestInterceptors(e){if(typeof e.runWhen==="function"&&e.runWhen(t)===false){return}r=r&&e.synchronous;const a=t.transitional||Y;const n=a&&a.legacyInterceptorReqResOrdering;if(n){s.unshift(e.fulfilled,e.rejected)}else{s.push(e.fulfilled,e.rejected)}}));const c=[];this.interceptors.response.forEach((function pushResponseInterceptors(e){c.push(e.fulfilled,e.rejected)}));let p;let l=0;let u;if(!r){const e=[dispatchRequest.bind(this),undefined];e.unshift(...s);e.push(...c);u=e.length;p=Promise.resolve(t);while(l{if(!a._listeners)return;let t=a._listeners.length;while(t-- >0){a._listeners[t](e)}a._listeners=null}));this.promise.then=e=>{let t;const n=new Promise((e=>{a.subscribe(e);t=e})).then(e);n.cancel=function reject(){a.unsubscribe(t)};return n};e((function cancel(e,n,i){if(a.reason){return}a.reason=new CanceledError(e,n,i);t(a.reason)}))}throwIfRequested(){if(this.reason){throw this.reason}}subscribe(e){if(this.reason){e(this.reason);return}if(this._listeners){this._listeners.push(e)}else{this._listeners=[e]}}unsubscribe(e){if(!this._listeners){return}const t=this._listeners.indexOf(e);if(t!==-1){this._listeners.splice(t,1)}}toAbortSignal(){const e=new AbortController;const abort=t=>{e.abort(t)};this.subscribe(abort);e.signal.unsubscribe=()=>this.unsubscribe(abort);return e.signal}static source(){let e;const t=new CancelToken((function executor(t){e=t}));return{token:t,cancel:e}}}function spread(e){return function wrap(t){return e.apply(null,t)}}function isAxiosError(e){return V.isObject(e)&&e.isAxiosError===true}const et={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(et).forEach((([e,t])=>{et[t]=e}));function createInstance(e){const t=new Axios(e);const a=bind(Axios.prototype.request,t);V.extend(a,Axios.prototype,t,{allOwnKeys:true});V.extend(a,t,null,{allOwnKeys:true});a.create=function create(t){return createInstance(mergeConfig(e,t))};return a}const tt=createInstance(ue);tt.Axios=Axios;tt.CanceledError=CanceledError;tt.CancelToken=CancelToken;tt.isCancel=isCancel;tt.VERSION=me;tt.toFormData=toFormData;tt.AxiosError=AxiosError;tt.Cancel=tt.CanceledError;tt.all=function all(e){return Promise.all(e)};tt.spread=spread;tt.isAxiosError=isAxiosError;tt.mergeConfig=mergeConfig;tt.AxiosHeaders=AxiosHeaders;tt.formToJSON=e=>formDataToJSON(V.isHTMLForm(e)?new FormData(e):e);tt.getAdapter=Ke.getAdapter;tt.HttpStatusCode=et;tt.default=tt;e.exports=tt},1813:e=>{"use strict";e.exports=JSON.parse('{"application/1d-interleaved-parityfec":{"source":"iana"},"application/3gpdash-qoe-report+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/3gpp-ims+xml":{"source":"iana","compressible":true},"application/3gpphal+json":{"source":"iana","compressible":true},"application/3gpphalforms+json":{"source":"iana","compressible":true},"application/a2l":{"source":"iana"},"application/ace+cbor":{"source":"iana"},"application/activemessage":{"source":"iana"},"application/activity+json":{"source":"iana","compressible":true},"application/alto-costmap+json":{"source":"iana","compressible":true},"application/alto-costmapfilter+json":{"source":"iana","compressible":true},"application/alto-directory+json":{"source":"iana","compressible":true},"application/alto-endpointcost+json":{"source":"iana","compressible":true},"application/alto-endpointcostparams+json":{"source":"iana","compressible":true},"application/alto-endpointprop+json":{"source":"iana","compressible":true},"application/alto-endpointpropparams+json":{"source":"iana","compressible":true},"application/alto-error+json":{"source":"iana","compressible":true},"application/alto-networkmap+json":{"source":"iana","compressible":true},"application/alto-networkmapfilter+json":{"source":"iana","compressible":true},"application/alto-updatestreamcontrol+json":{"source":"iana","compressible":true},"application/alto-updatestreamparams+json":{"source":"iana","compressible":true},"application/aml":{"source":"iana"},"application/andrew-inset":{"source":"iana","extensions":["ez"]},"application/applefile":{"source":"iana"},"application/applixware":{"source":"apache","extensions":["aw"]},"application/at+jwt":{"source":"iana"},"application/atf":{"source":"iana"},"application/atfx":{"source":"iana"},"application/atom+xml":{"source":"iana","compressible":true,"extensions":["atom"]},"application/atomcat+xml":{"source":"iana","compressible":true,"extensions":["atomcat"]},"application/atomdeleted+xml":{"source":"iana","compressible":true,"extensions":["atomdeleted"]},"application/atomicmail":{"source":"iana"},"application/atomsvc+xml":{"source":"iana","compressible":true,"extensions":["atomsvc"]},"application/atsc-dwd+xml":{"source":"iana","compressible":true,"extensions":["dwd"]},"application/atsc-dynamic-event-message":{"source":"iana"},"application/atsc-held+xml":{"source":"iana","compressible":true,"extensions":["held"]},"application/atsc-rdt+json":{"source":"iana","compressible":true},"application/atsc-rsat+xml":{"source":"iana","compressible":true,"extensions":["rsat"]},"application/atxml":{"source":"iana"},"application/auth-policy+xml":{"source":"iana","compressible":true},"application/bacnet-xdd+zip":{"source":"iana","compressible":false},"application/batch-smtp":{"source":"iana"},"application/bdoc":{"compressible":false,"extensions":["bdoc"]},"application/beep+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/calendar+json":{"source":"iana","compressible":true},"application/calendar+xml":{"source":"iana","compressible":true,"extensions":["xcs"]},"application/call-completion":{"source":"iana"},"application/cals-1840":{"source":"iana"},"application/captive+json":{"source":"iana","compressible":true},"application/cbor":{"source":"iana"},"application/cbor-seq":{"source":"iana"},"application/cccex":{"source":"iana"},"application/ccmp+xml":{"source":"iana","compressible":true},"application/ccxml+xml":{"source":"iana","compressible":true,"extensions":["ccxml"]},"application/cdfx+xml":{"source":"iana","compressible":true,"extensions":["cdfx"]},"application/cdmi-capability":{"source":"iana","extensions":["cdmia"]},"application/cdmi-container":{"source":"iana","extensions":["cdmic"]},"application/cdmi-domain":{"source":"iana","extensions":["cdmid"]},"application/cdmi-object":{"source":"iana","extensions":["cdmio"]},"application/cdmi-queue":{"source":"iana","extensions":["cdmiq"]},"application/cdni":{"source":"iana"},"application/cea":{"source":"iana"},"application/cea-2018+xml":{"source":"iana","compressible":true},"application/cellml+xml":{"source":"iana","compressible":true},"application/cfw":{"source":"iana"},"application/city+json":{"source":"iana","compressible":true},"application/clr":{"source":"iana"},"application/clue+xml":{"source":"iana","compressible":true},"application/clue_info+xml":{"source":"iana","compressible":true},"application/cms":{"source":"iana"},"application/cnrp+xml":{"source":"iana","compressible":true},"application/coap-group+json":{"source":"iana","compressible":true},"application/coap-payload":{"source":"iana"},"application/commonground":{"source":"iana"},"application/conference-info+xml":{"source":"iana","compressible":true},"application/cose":{"source":"iana"},"application/cose-key":{"source":"iana"},"application/cose-key-set":{"source":"iana"},"application/cpl+xml":{"source":"iana","compressible":true,"extensions":["cpl"]},"application/csrattrs":{"source":"iana"},"application/csta+xml":{"source":"iana","compressible":true},"application/cstadata+xml":{"source":"iana","compressible":true},"application/csvm+json":{"source":"iana","compressible":true},"application/cu-seeme":{"source":"apache","extensions":["cu"]},"application/cwt":{"source":"iana"},"application/cybercash":{"source":"iana"},"application/dart":{"compressible":true},"application/dash+xml":{"source":"iana","compressible":true,"extensions":["mpd"]},"application/dash-patch+xml":{"source":"iana","compressible":true,"extensions":["mpp"]},"application/dashdelta":{"source":"iana"},"application/davmount+xml":{"source":"iana","compressible":true,"extensions":["davmount"]},"application/dca-rft":{"source":"iana"},"application/dcd":{"source":"iana"},"application/dec-dx":{"source":"iana"},"application/dialog-info+xml":{"source":"iana","compressible":true},"application/dicom":{"source":"iana"},"application/dicom+json":{"source":"iana","compressible":true},"application/dicom+xml":{"source":"iana","compressible":true},"application/dii":{"source":"iana"},"application/dit":{"source":"iana"},"application/dns":{"source":"iana"},"application/dns+json":{"source":"iana","compressible":true},"application/dns-message":{"source":"iana"},"application/docbook+xml":{"source":"apache","compressible":true,"extensions":["dbk"]},"application/dots+cbor":{"source":"iana"},"application/dskpp+xml":{"source":"iana","compressible":true},"application/dssc+der":{"source":"iana","extensions":["dssc"]},"application/dssc+xml":{"source":"iana","compressible":true,"extensions":["xdssc"]},"application/dvcs":{"source":"iana"},"application/ecmascript":{"source":"iana","compressible":true,"extensions":["es","ecma"]},"application/edi-consent":{"source":"iana"},"application/edi-x12":{"source":"iana","compressible":false},"application/edifact":{"source":"iana","compressible":false},"application/efi":{"source":"iana"},"application/elm+json":{"source":"iana","charset":"UTF-8","compressible":true},"application/elm+xml":{"source":"iana","compressible":true},"application/emergencycalldata.cap+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/emergencycalldata.comment+xml":{"source":"iana","compressible":true},"application/emergencycalldata.control+xml":{"source":"iana","compressible":true},"application/emergencycalldata.deviceinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.ecall.msd":{"source":"iana"},"application/emergencycalldata.providerinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.serviceinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.subscriberinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.veds+xml":{"source":"iana","compressible":true},"application/emma+xml":{"source":"iana","compressible":true,"extensions":["emma"]},"application/emotionml+xml":{"source":"iana","compressible":true,"extensions":["emotionml"]},"application/encaprtp":{"source":"iana"},"application/epp+xml":{"source":"iana","compressible":true},"application/epub+zip":{"source":"iana","compressible":false,"extensions":["epub"]},"application/eshop":{"source":"iana"},"application/exi":{"source":"iana","extensions":["exi"]},"application/expect-ct-report+json":{"source":"iana","compressible":true},"application/express":{"source":"iana","extensions":["exp"]},"application/fastinfoset":{"source":"iana"},"application/fastsoap":{"source":"iana"},"application/fdt+xml":{"source":"iana","compressible":true,"extensions":["fdt"]},"application/fhir+json":{"source":"iana","charset":"UTF-8","compressible":true},"application/fhir+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/fido.trusted-apps+json":{"compressible":true},"application/fits":{"source":"iana"},"application/flexfec":{"source":"iana"},"application/font-sfnt":{"source":"iana"},"application/font-tdpfr":{"source":"iana","extensions":["pfr"]},"application/font-woff":{"source":"iana","compressible":false},"application/framework-attributes+xml":{"source":"iana","compressible":true},"application/geo+json":{"source":"iana","compressible":true,"extensions":["geojson"]},"application/geo+json-seq":{"source":"iana"},"application/geopackage+sqlite3":{"source":"iana"},"application/geoxacml+xml":{"source":"iana","compressible":true},"application/gltf-buffer":{"source":"iana"},"application/gml+xml":{"source":"iana","compressible":true,"extensions":["gml"]},"application/gpx+xml":{"source":"apache","compressible":true,"extensions":["gpx"]},"application/gxf":{"source":"apache","extensions":["gxf"]},"application/gzip":{"source":"iana","compressible":false,"extensions":["gz"]},"application/h224":{"source":"iana"},"application/held+xml":{"source":"iana","compressible":true},"application/hjson":{"extensions":["hjson"]},"application/http":{"source":"iana"},"application/hyperstudio":{"source":"iana","extensions":["stk"]},"application/ibe-key-request+xml":{"source":"iana","compressible":true},"application/ibe-pkg-reply+xml":{"source":"iana","compressible":true},"application/ibe-pp-data":{"source":"iana"},"application/iges":{"source":"iana"},"application/im-iscomposing+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/index":{"source":"iana"},"application/index.cmd":{"source":"iana"},"application/index.obj":{"source":"iana"},"application/index.response":{"source":"iana"},"application/index.vnd":{"source":"iana"},"application/inkml+xml":{"source":"iana","compressible":true,"extensions":["ink","inkml"]},"application/iotp":{"source":"iana"},"application/ipfix":{"source":"iana","extensions":["ipfix"]},"application/ipp":{"source":"iana"},"application/isup":{"source":"iana"},"application/its+xml":{"source":"iana","compressible":true,"extensions":["its"]},"application/java-archive":{"source":"apache","compressible":false,"extensions":["jar","war","ear"]},"application/java-serialized-object":{"source":"apache","compressible":false,"extensions":["ser"]},"application/java-vm":{"source":"apache","compressible":false,"extensions":["class"]},"application/javascript":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["js","mjs"]},"application/jf2feed+json":{"source":"iana","compressible":true},"application/jose":{"source":"iana"},"application/jose+json":{"source":"iana","compressible":true},"application/jrd+json":{"source":"iana","compressible":true},"application/jscalendar+json":{"source":"iana","compressible":true},"application/json":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["json","map"]},"application/json-patch+json":{"source":"iana","compressible":true},"application/json-seq":{"source":"iana"},"application/json5":{"extensions":["json5"]},"application/jsonml+json":{"source":"apache","compressible":true,"extensions":["jsonml"]},"application/jwk+json":{"source":"iana","compressible":true},"application/jwk-set+json":{"source":"iana","compressible":true},"application/jwt":{"source":"iana"},"application/kpml-request+xml":{"source":"iana","compressible":true},"application/kpml-response+xml":{"source":"iana","compressible":true},"application/ld+json":{"source":"iana","compressible":true,"extensions":["jsonld"]},"application/lgr+xml":{"source":"iana","compressible":true,"extensions":["lgr"]},"application/link-format":{"source":"iana"},"application/load-control+xml":{"source":"iana","compressible":true},"application/lost+xml":{"source":"iana","compressible":true,"extensions":["lostxml"]},"application/lostsync+xml":{"source":"iana","compressible":true},"application/lpf+zip":{"source":"iana","compressible":false},"application/lxf":{"source":"iana"},"application/mac-binhex40":{"source":"iana","extensions":["hqx"]},"application/mac-compactpro":{"source":"apache","extensions":["cpt"]},"application/macwriteii":{"source":"iana"},"application/mads+xml":{"source":"iana","compressible":true,"extensions":["mads"]},"application/manifest+json":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["webmanifest"]},"application/marc":{"source":"iana","extensions":["mrc"]},"application/marcxml+xml":{"source":"iana","compressible":true,"extensions":["mrcx"]},"application/mathematica":{"source":"iana","extensions":["ma","nb","mb"]},"application/mathml+xml":{"source":"iana","compressible":true,"extensions":["mathml"]},"application/mathml-content+xml":{"source":"iana","compressible":true},"application/mathml-presentation+xml":{"source":"iana","compressible":true},"application/mbms-associated-procedure-description+xml":{"source":"iana","compressible":true},"application/mbms-deregister+xml":{"source":"iana","compressible":true},"application/mbms-envelope+xml":{"source":"iana","compressible":true},"application/mbms-msk+xml":{"source":"iana","compressible":true},"application/mbms-msk-response+xml":{"source":"iana","compressible":true},"application/mbms-protection-description+xml":{"source":"iana","compressible":true},"application/mbms-reception-report+xml":{"source":"iana","compressible":true},"application/mbms-register+xml":{"source":"iana","compressible":true},"application/mbms-register-response+xml":{"source":"iana","compressible":true},"application/mbms-schedule+xml":{"source":"iana","compressible":true},"application/mbms-user-service-description+xml":{"source":"iana","compressible":true},"application/mbox":{"source":"iana","extensions":["mbox"]},"application/media-policy-dataset+xml":{"source":"iana","compressible":true,"extensions":["mpf"]},"application/media_control+xml":{"source":"iana","compressible":true},"application/mediaservercontrol+xml":{"source":"iana","compressible":true,"extensions":["mscml"]},"application/merge-patch+json":{"source":"iana","compressible":true},"application/metalink+xml":{"source":"apache","compressible":true,"extensions":["metalink"]},"application/metalink4+xml":{"source":"iana","compressible":true,"extensions":["meta4"]},"application/mets+xml":{"source":"iana","compressible":true,"extensions":["mets"]},"application/mf4":{"source":"iana"},"application/mikey":{"source":"iana"},"application/mipc":{"source":"iana"},"application/missing-blocks+cbor-seq":{"source":"iana"},"application/mmt-aei+xml":{"source":"iana","compressible":true,"extensions":["maei"]},"application/mmt-usd+xml":{"source":"iana","compressible":true,"extensions":["musd"]},"application/mods+xml":{"source":"iana","compressible":true,"extensions":["mods"]},"application/moss-keys":{"source":"iana"},"application/moss-signature":{"source":"iana"},"application/mosskey-data":{"source":"iana"},"application/mosskey-request":{"source":"iana"},"application/mp21":{"source":"iana","extensions":["m21","mp21"]},"application/mp4":{"source":"iana","extensions":["mp4s","m4p"]},"application/mpeg4-generic":{"source":"iana"},"application/mpeg4-iod":{"source":"iana"},"application/mpeg4-iod-xmt":{"source":"iana"},"application/mrb-consumer+xml":{"source":"iana","compressible":true},"application/mrb-publish+xml":{"source":"iana","compressible":true},"application/msc-ivr+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/msc-mixer+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/msword":{"source":"iana","compressible":false,"extensions":["doc","dot"]},"application/mud+json":{"source":"iana","compressible":true},"application/multipart-core":{"source":"iana"},"application/mxf":{"source":"iana","extensions":["mxf"]},"application/n-quads":{"source":"iana","extensions":["nq"]},"application/n-triples":{"source":"iana","extensions":["nt"]},"application/nasdata":{"source":"iana"},"application/news-checkgroups":{"source":"iana","charset":"US-ASCII"},"application/news-groupinfo":{"source":"iana","charset":"US-ASCII"},"application/news-transmission":{"source":"iana"},"application/nlsml+xml":{"source":"iana","compressible":true},"application/node":{"source":"iana","extensions":["cjs"]},"application/nss":{"source":"iana"},"application/oauth-authz-req+jwt":{"source":"iana"},"application/oblivious-dns-message":{"source":"iana"},"application/ocsp-request":{"source":"iana"},"application/ocsp-response":{"source":"iana"},"application/octet-stream":{"source":"iana","compressible":false,"extensions":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]},"application/oda":{"source":"iana","extensions":["oda"]},"application/odm+xml":{"source":"iana","compressible":true},"application/odx":{"source":"iana"},"application/oebps-package+xml":{"source":"iana","compressible":true,"extensions":["opf"]},"application/ogg":{"source":"iana","compressible":false,"extensions":["ogx"]},"application/omdoc+xml":{"source":"apache","compressible":true,"extensions":["omdoc"]},"application/onenote":{"source":"apache","extensions":["onetoc","onetoc2","onetmp","onepkg"]},"application/opc-nodeset+xml":{"source":"iana","compressible":true},"application/oscore":{"source":"iana"},"application/oxps":{"source":"iana","extensions":["oxps"]},"application/p21":{"source":"iana"},"application/p21+zip":{"source":"iana","compressible":false},"application/p2p-overlay+xml":{"source":"iana","compressible":true,"extensions":["relo"]},"application/parityfec":{"source":"iana"},"application/passport":{"source":"iana"},"application/patch-ops-error+xml":{"source":"iana","compressible":true,"extensions":["xer"]},"application/pdf":{"source":"iana","compressible":false,"extensions":["pdf"]},"application/pdx":{"source":"iana"},"application/pem-certificate-chain":{"source":"iana"},"application/pgp-encrypted":{"source":"iana","compressible":false,"extensions":["pgp"]},"application/pgp-keys":{"source":"iana","extensions":["asc"]},"application/pgp-signature":{"source":"iana","extensions":["asc","sig"]},"application/pics-rules":{"source":"apache","extensions":["prf"]},"application/pidf+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/pidf-diff+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/pkcs10":{"source":"iana","extensions":["p10"]},"application/pkcs12":{"source":"iana"},"application/pkcs7-mime":{"source":"iana","extensions":["p7m","p7c"]},"application/pkcs7-signature":{"source":"iana","extensions":["p7s"]},"application/pkcs8":{"source":"iana","extensions":["p8"]},"application/pkcs8-encrypted":{"source":"iana"},"application/pkix-attr-cert":{"source":"iana","extensions":["ac"]},"application/pkix-cert":{"source":"iana","extensions":["cer"]},"application/pkix-crl":{"source":"iana","extensions":["crl"]},"application/pkix-pkipath":{"source":"iana","extensions":["pkipath"]},"application/pkixcmp":{"source":"iana","extensions":["pki"]},"application/pls+xml":{"source":"iana","compressible":true,"extensions":["pls"]},"application/poc-settings+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/postscript":{"source":"iana","compressible":true,"extensions":["ai","eps","ps"]},"application/ppsp-tracker+json":{"source":"iana","compressible":true},"application/problem+json":{"source":"iana","compressible":true},"application/problem+xml":{"source":"iana","compressible":true},"application/provenance+xml":{"source":"iana","compressible":true,"extensions":["provx"]},"application/prs.alvestrand.titrax-sheet":{"source":"iana"},"application/prs.cww":{"source":"iana","extensions":["cww"]},"application/prs.cyn":{"source":"iana","charset":"7-BIT"},"application/prs.hpub+zip":{"source":"iana","compressible":false},"application/prs.nprend":{"source":"iana"},"application/prs.plucker":{"source":"iana"},"application/prs.rdf-xml-crypt":{"source":"iana"},"application/prs.xsf+xml":{"source":"iana","compressible":true},"application/pskc+xml":{"source":"iana","compressible":true,"extensions":["pskcxml"]},"application/pvd+json":{"source":"iana","compressible":true},"application/qsig":{"source":"iana"},"application/raml+yaml":{"compressible":true,"extensions":["raml"]},"application/raptorfec":{"source":"iana"},"application/rdap+json":{"source":"iana","compressible":true},"application/rdf+xml":{"source":"iana","compressible":true,"extensions":["rdf","owl"]},"application/reginfo+xml":{"source":"iana","compressible":true,"extensions":["rif"]},"application/relax-ng-compact-syntax":{"source":"iana","extensions":["rnc"]},"application/remote-printing":{"source":"iana"},"application/reputon+json":{"source":"iana","compressible":true},"application/resource-lists+xml":{"source":"iana","compressible":true,"extensions":["rl"]},"application/resource-lists-diff+xml":{"source":"iana","compressible":true,"extensions":["rld"]},"application/rfc+xml":{"source":"iana","compressible":true},"application/riscos":{"source":"iana"},"application/rlmi+xml":{"source":"iana","compressible":true},"application/rls-services+xml":{"source":"iana","compressible":true,"extensions":["rs"]},"application/route-apd+xml":{"source":"iana","compressible":true,"extensions":["rapd"]},"application/route-s-tsid+xml":{"source":"iana","compressible":true,"extensions":["sls"]},"application/route-usd+xml":{"source":"iana","compressible":true,"extensions":["rusd"]},"application/rpki-ghostbusters":{"source":"iana","extensions":["gbr"]},"application/rpki-manifest":{"source":"iana","extensions":["mft"]},"application/rpki-publication":{"source":"iana"},"application/rpki-roa":{"source":"iana","extensions":["roa"]},"application/rpki-updown":{"source":"iana"},"application/rsd+xml":{"source":"apache","compressible":true,"extensions":["rsd"]},"application/rss+xml":{"source":"apache","compressible":true,"extensions":["rss"]},"application/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"application/rtploopback":{"source":"iana"},"application/rtx":{"source":"iana"},"application/samlassertion+xml":{"source":"iana","compressible":true},"application/samlmetadata+xml":{"source":"iana","compressible":true},"application/sarif+json":{"source":"iana","compressible":true},"application/sarif-external-properties+json":{"source":"iana","compressible":true},"application/sbe":{"source":"iana"},"application/sbml+xml":{"source":"iana","compressible":true,"extensions":["sbml"]},"application/scaip+xml":{"source":"iana","compressible":true},"application/scim+json":{"source":"iana","compressible":true},"application/scvp-cv-request":{"source":"iana","extensions":["scq"]},"application/scvp-cv-response":{"source":"iana","extensions":["scs"]},"application/scvp-vp-request":{"source":"iana","extensions":["spq"]},"application/scvp-vp-response":{"source":"iana","extensions":["spp"]},"application/sdp":{"source":"iana","extensions":["sdp"]},"application/secevent+jwt":{"source":"iana"},"application/senml+cbor":{"source":"iana"},"application/senml+json":{"source":"iana","compressible":true},"application/senml+xml":{"source":"iana","compressible":true,"extensions":["senmlx"]},"application/senml-etch+cbor":{"source":"iana"},"application/senml-etch+json":{"source":"iana","compressible":true},"application/senml-exi":{"source":"iana"},"application/sensml+cbor":{"source":"iana"},"application/sensml+json":{"source":"iana","compressible":true},"application/sensml+xml":{"source":"iana","compressible":true,"extensions":["sensmlx"]},"application/sensml-exi":{"source":"iana"},"application/sep+xml":{"source":"iana","compressible":true},"application/sep-exi":{"source":"iana"},"application/session-info":{"source":"iana"},"application/set-payment":{"source":"iana"},"application/set-payment-initiation":{"source":"iana","extensions":["setpay"]},"application/set-registration":{"source":"iana"},"application/set-registration-initiation":{"source":"iana","extensions":["setreg"]},"application/sgml":{"source":"iana"},"application/sgml-open-catalog":{"source":"iana"},"application/shf+xml":{"source":"iana","compressible":true,"extensions":["shf"]},"application/sieve":{"source":"iana","extensions":["siv","sieve"]},"application/simple-filter+xml":{"source":"iana","compressible":true},"application/simple-message-summary":{"source":"iana"},"application/simplesymbolcontainer":{"source":"iana"},"application/sipc":{"source":"iana"},"application/slate":{"source":"iana"},"application/smil":{"source":"iana"},"application/smil+xml":{"source":"iana","compressible":true,"extensions":["smi","smil"]},"application/smpte336m":{"source":"iana"},"application/soap+fastinfoset":{"source":"iana"},"application/soap+xml":{"source":"iana","compressible":true},"application/sparql-query":{"source":"iana","extensions":["rq"]},"application/sparql-results+xml":{"source":"iana","compressible":true,"extensions":["srx"]},"application/spdx+json":{"source":"iana","compressible":true},"application/spirits-event+xml":{"source":"iana","compressible":true},"application/sql":{"source":"iana"},"application/srgs":{"source":"iana","extensions":["gram"]},"application/srgs+xml":{"source":"iana","compressible":true,"extensions":["grxml"]},"application/sru+xml":{"source":"iana","compressible":true,"extensions":["sru"]},"application/ssdl+xml":{"source":"apache","compressible":true,"extensions":["ssdl"]},"application/ssml+xml":{"source":"iana","compressible":true,"extensions":["ssml"]},"application/stix+json":{"source":"iana","compressible":true},"application/swid+xml":{"source":"iana","compressible":true,"extensions":["swidtag"]},"application/tamp-apex-update":{"source":"iana"},"application/tamp-apex-update-confirm":{"source":"iana"},"application/tamp-community-update":{"source":"iana"},"application/tamp-community-update-confirm":{"source":"iana"},"application/tamp-error":{"source":"iana"},"application/tamp-sequence-adjust":{"source":"iana"},"application/tamp-sequence-adjust-confirm":{"source":"iana"},"application/tamp-status-query":{"source":"iana"},"application/tamp-status-response":{"source":"iana"},"application/tamp-update":{"source":"iana"},"application/tamp-update-confirm":{"source":"iana"},"application/tar":{"compressible":true},"application/taxii+json":{"source":"iana","compressible":true},"application/td+json":{"source":"iana","compressible":true},"application/tei+xml":{"source":"iana","compressible":true,"extensions":["tei","teicorpus"]},"application/tetra_isi":{"source":"iana"},"application/thraud+xml":{"source":"iana","compressible":true,"extensions":["tfi"]},"application/timestamp-query":{"source":"iana"},"application/timestamp-reply":{"source":"iana"},"application/timestamped-data":{"source":"iana","extensions":["tsd"]},"application/tlsrpt+gzip":{"source":"iana"},"application/tlsrpt+json":{"source":"iana","compressible":true},"application/tnauthlist":{"source":"iana"},"application/token-introspection+jwt":{"source":"iana"},"application/toml":{"compressible":true,"extensions":["toml"]},"application/trickle-ice-sdpfrag":{"source":"iana"},"application/trig":{"source":"iana","extensions":["trig"]},"application/ttml+xml":{"source":"iana","compressible":true,"extensions":["ttml"]},"application/tve-trigger":{"source":"iana"},"application/tzif":{"source":"iana"},"application/tzif-leap":{"source":"iana"},"application/ubjson":{"compressible":false,"extensions":["ubj"]},"application/ulpfec":{"source":"iana"},"application/urc-grpsheet+xml":{"source":"iana","compressible":true},"application/urc-ressheet+xml":{"source":"iana","compressible":true,"extensions":["rsheet"]},"application/urc-targetdesc+xml":{"source":"iana","compressible":true,"extensions":["td"]},"application/urc-uisocketdesc+xml":{"source":"iana","compressible":true},"application/vcard+json":{"source":"iana","compressible":true},"application/vcard+xml":{"source":"iana","compressible":true},"application/vemmi":{"source":"iana"},"application/vividence.scriptfile":{"source":"apache"},"application/vnd.1000minds.decision-model+xml":{"source":"iana","compressible":true,"extensions":["1km"]},"application/vnd.3gpp-prose+xml":{"source":"iana","compressible":true},"application/vnd.3gpp-prose-pc3ch+xml":{"source":"iana","compressible":true},"application/vnd.3gpp-v2x-local-service-information":{"source":"iana"},"application/vnd.3gpp.5gnas":{"source":"iana"},"application/vnd.3gpp.access-transfer-events+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.bsf+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.gmop+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.gtpc":{"source":"iana"},"application/vnd.3gpp.interworking-data":{"source":"iana"},"application/vnd.3gpp.lpp":{"source":"iana"},"application/vnd.3gpp.mc-signalling-ear":{"source":"iana"},"application/vnd.3gpp.mcdata-affiliation-command+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcdata-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcdata-payload":{"source":"iana"},"application/vnd.3gpp.mcdata-service-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcdata-signalling":{"source":"iana"},"application/vnd.3gpp.mcdata-ue-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcdata-user-profile+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-affiliation-command+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-floor-request+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-location-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-mbms-usage-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-service-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-signed+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-ue-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-ue-init-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-user-profile+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-affiliation-command+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-affiliation-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-location-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-mbms-usage-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-service-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-transmission-request+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-ue-config+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcvideo-user-profile+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mid-call+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.ngap":{"source":"iana"},"application/vnd.3gpp.pfcp":{"source":"iana"},"application/vnd.3gpp.pic-bw-large":{"source":"iana","extensions":["plb"]},"application/vnd.3gpp.pic-bw-small":{"source":"iana","extensions":["psb"]},"application/vnd.3gpp.pic-bw-var":{"source":"iana","extensions":["pvb"]},"application/vnd.3gpp.s1ap":{"source":"iana"},"application/vnd.3gpp.sms":{"source":"iana"},"application/vnd.3gpp.sms+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.srvcc-ext+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.srvcc-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.state-and-event-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.ussd+xml":{"source":"iana","compressible":true},"application/vnd.3gpp2.bcmcsinfo+xml":{"source":"iana","compressible":true},"application/vnd.3gpp2.sms":{"source":"iana"},"application/vnd.3gpp2.tcap":{"source":"iana","extensions":["tcap"]},"application/vnd.3lightssoftware.imagescal":{"source":"iana"},"application/vnd.3m.post-it-notes":{"source":"iana","extensions":["pwn"]},"application/vnd.accpac.simply.aso":{"source":"iana","extensions":["aso"]},"application/vnd.accpac.simply.imp":{"source":"iana","extensions":["imp"]},"application/vnd.acucobol":{"source":"iana","extensions":["acu"]},"application/vnd.acucorp":{"source":"iana","extensions":["atc","acutc"]},"application/vnd.adobe.air-application-installer-package+zip":{"source":"apache","compressible":false,"extensions":["air"]},"application/vnd.adobe.flash.movie":{"source":"iana"},"application/vnd.adobe.formscentral.fcdt":{"source":"iana","extensions":["fcdt"]},"application/vnd.adobe.fxp":{"source":"iana","extensions":["fxp","fxpl"]},"application/vnd.adobe.partial-upload":{"source":"iana"},"application/vnd.adobe.xdp+xml":{"source":"iana","compressible":true,"extensions":["xdp"]},"application/vnd.adobe.xfdf":{"source":"iana","extensions":["xfdf"]},"application/vnd.aether.imp":{"source":"iana"},"application/vnd.afpc.afplinedata":{"source":"iana"},"application/vnd.afpc.afplinedata-pagedef":{"source":"iana"},"application/vnd.afpc.cmoca-cmresource":{"source":"iana"},"application/vnd.afpc.foca-charset":{"source":"iana"},"application/vnd.afpc.foca-codedfont":{"source":"iana"},"application/vnd.afpc.foca-codepage":{"source":"iana"},"application/vnd.afpc.modca":{"source":"iana"},"application/vnd.afpc.modca-cmtable":{"source":"iana"},"application/vnd.afpc.modca-formdef":{"source":"iana"},"application/vnd.afpc.modca-mediummap":{"source":"iana"},"application/vnd.afpc.modca-objectcontainer":{"source":"iana"},"application/vnd.afpc.modca-overlay":{"source":"iana"},"application/vnd.afpc.modca-pagesegment":{"source":"iana"},"application/vnd.age":{"source":"iana","extensions":["age"]},"application/vnd.ah-barcode":{"source":"iana"},"application/vnd.ahead.space":{"source":"iana","extensions":["ahead"]},"application/vnd.airzip.filesecure.azf":{"source":"iana","extensions":["azf"]},"application/vnd.airzip.filesecure.azs":{"source":"iana","extensions":["azs"]},"application/vnd.amadeus+json":{"source":"iana","compressible":true},"application/vnd.amazon.ebook":{"source":"apache","extensions":["azw"]},"application/vnd.amazon.mobi8-ebook":{"source":"iana"},"application/vnd.americandynamics.acc":{"source":"iana","extensions":["acc"]},"application/vnd.amiga.ami":{"source":"iana","extensions":["ami"]},"application/vnd.amundsen.maze+xml":{"source":"iana","compressible":true},"application/vnd.android.ota":{"source":"iana"},"application/vnd.android.package-archive":{"source":"apache","compressible":false,"extensions":["apk"]},"application/vnd.anki":{"source":"iana"},"application/vnd.anser-web-certificate-issue-initiation":{"source":"iana","extensions":["cii"]},"application/vnd.anser-web-funds-transfer-initiation":{"source":"apache","extensions":["fti"]},"application/vnd.antix.game-component":{"source":"iana","extensions":["atx"]},"application/vnd.apache.arrow.file":{"source":"iana"},"application/vnd.apache.arrow.stream":{"source":"iana"},"application/vnd.apache.thrift.binary":{"source":"iana"},"application/vnd.apache.thrift.compact":{"source":"iana"},"application/vnd.apache.thrift.json":{"source":"iana"},"application/vnd.api+json":{"source":"iana","compressible":true},"application/vnd.aplextor.warrp+json":{"source":"iana","compressible":true},"application/vnd.apothekende.reservation+json":{"source":"iana","compressible":true},"application/vnd.apple.installer+xml":{"source":"iana","compressible":true,"extensions":["mpkg"]},"application/vnd.apple.keynote":{"source":"iana","extensions":["key"]},"application/vnd.apple.mpegurl":{"source":"iana","extensions":["m3u8"]},"application/vnd.apple.numbers":{"source":"iana","extensions":["numbers"]},"application/vnd.apple.pages":{"source":"iana","extensions":["pages"]},"application/vnd.apple.pkpass":{"compressible":false,"extensions":["pkpass"]},"application/vnd.arastra.swi":{"source":"iana"},"application/vnd.aristanetworks.swi":{"source":"iana","extensions":["swi"]},"application/vnd.artisan+json":{"source":"iana","compressible":true},"application/vnd.artsquare":{"source":"iana"},"application/vnd.astraea-software.iota":{"source":"iana","extensions":["iota"]},"application/vnd.audiograph":{"source":"iana","extensions":["aep"]},"application/vnd.autopackage":{"source":"iana"},"application/vnd.avalon+json":{"source":"iana","compressible":true},"application/vnd.avistar+xml":{"source":"iana","compressible":true},"application/vnd.balsamiq.bmml+xml":{"source":"iana","compressible":true,"extensions":["bmml"]},"application/vnd.balsamiq.bmpr":{"source":"iana"},"application/vnd.banana-accounting":{"source":"iana"},"application/vnd.bbf.usp.error":{"source":"iana"},"application/vnd.bbf.usp.msg":{"source":"iana"},"application/vnd.bbf.usp.msg+json":{"source":"iana","compressible":true},"application/vnd.bekitzur-stech+json":{"source":"iana","compressible":true},"application/vnd.bint.med-content":{"source":"iana"},"application/vnd.biopax.rdf+xml":{"source":"iana","compressible":true},"application/vnd.blink-idb-value-wrapper":{"source":"iana"},"application/vnd.blueice.multipass":{"source":"iana","extensions":["mpm"]},"application/vnd.bluetooth.ep.oob":{"source":"iana"},"application/vnd.bluetooth.le.oob":{"source":"iana"},"application/vnd.bmi":{"source":"iana","extensions":["bmi"]},"application/vnd.bpf":{"source":"iana"},"application/vnd.bpf3":{"source":"iana"},"application/vnd.businessobjects":{"source":"iana","extensions":["rep"]},"application/vnd.byu.uapi+json":{"source":"iana","compressible":true},"application/vnd.cab-jscript":{"source":"iana"},"application/vnd.canon-cpdl":{"source":"iana"},"application/vnd.canon-lips":{"source":"iana"},"application/vnd.capasystems-pg+json":{"source":"iana","compressible":true},"application/vnd.cendio.thinlinc.clientconf":{"source":"iana"},"application/vnd.century-systems.tcp_stream":{"source":"iana"},"application/vnd.chemdraw+xml":{"source":"iana","compressible":true,"extensions":["cdxml"]},"application/vnd.chess-pgn":{"source":"iana"},"application/vnd.chipnuts.karaoke-mmd":{"source":"iana","extensions":["mmd"]},"application/vnd.ciedi":{"source":"iana"},"application/vnd.cinderella":{"source":"iana","extensions":["cdy"]},"application/vnd.cirpack.isdn-ext":{"source":"iana"},"application/vnd.citationstyles.style+xml":{"source":"iana","compressible":true,"extensions":["csl"]},"application/vnd.claymore":{"source":"iana","extensions":["cla"]},"application/vnd.cloanto.rp9":{"source":"iana","extensions":["rp9"]},"application/vnd.clonk.c4group":{"source":"iana","extensions":["c4g","c4d","c4f","c4p","c4u"]},"application/vnd.cluetrust.cartomobile-config":{"source":"iana","extensions":["c11amc"]},"application/vnd.cluetrust.cartomobile-config-pkg":{"source":"iana","extensions":["c11amz"]},"application/vnd.coffeescript":{"source":"iana"},"application/vnd.collabio.xodocuments.document":{"source":"iana"},"application/vnd.collabio.xodocuments.document-template":{"source":"iana"},"application/vnd.collabio.xodocuments.presentation":{"source":"iana"},"application/vnd.collabio.xodocuments.presentation-template":{"source":"iana"},"application/vnd.collabio.xodocuments.spreadsheet":{"source":"iana"},"application/vnd.collabio.xodocuments.spreadsheet-template":{"source":"iana"},"application/vnd.collection+json":{"source":"iana","compressible":true},"application/vnd.collection.doc+json":{"source":"iana","compressible":true},"application/vnd.collection.next+json":{"source":"iana","compressible":true},"application/vnd.comicbook+zip":{"source":"iana","compressible":false},"application/vnd.comicbook-rar":{"source":"iana"},"application/vnd.commerce-battelle":{"source":"iana"},"application/vnd.commonspace":{"source":"iana","extensions":["csp"]},"application/vnd.contact.cmsg":{"source":"iana","extensions":["cdbcmsg"]},"application/vnd.coreos.ignition+json":{"source":"iana","compressible":true},"application/vnd.cosmocaller":{"source":"iana","extensions":["cmc"]},"application/vnd.crick.clicker":{"source":"iana","extensions":["clkx"]},"application/vnd.crick.clicker.keyboard":{"source":"iana","extensions":["clkk"]},"application/vnd.crick.clicker.palette":{"source":"iana","extensions":["clkp"]},"application/vnd.crick.clicker.template":{"source":"iana","extensions":["clkt"]},"application/vnd.crick.clicker.wordbank":{"source":"iana","extensions":["clkw"]},"application/vnd.criticaltools.wbs+xml":{"source":"iana","compressible":true,"extensions":["wbs"]},"application/vnd.cryptii.pipe+json":{"source":"iana","compressible":true},"application/vnd.crypto-shade-file":{"source":"iana"},"application/vnd.cryptomator.encrypted":{"source":"iana"},"application/vnd.cryptomator.vault":{"source":"iana"},"application/vnd.ctc-posml":{"source":"iana","extensions":["pml"]},"application/vnd.ctct.ws+xml":{"source":"iana","compressible":true},"application/vnd.cups-pdf":{"source":"iana"},"application/vnd.cups-postscript":{"source":"iana"},"application/vnd.cups-ppd":{"source":"iana","extensions":["ppd"]},"application/vnd.cups-raster":{"source":"iana"},"application/vnd.cups-raw":{"source":"iana"},"application/vnd.curl":{"source":"iana"},"application/vnd.curl.car":{"source":"apache","extensions":["car"]},"application/vnd.curl.pcurl":{"source":"apache","extensions":["pcurl"]},"application/vnd.cyan.dean.root+xml":{"source":"iana","compressible":true},"application/vnd.cybank":{"source":"iana"},"application/vnd.cyclonedx+json":{"source":"iana","compressible":true},"application/vnd.cyclonedx+xml":{"source":"iana","compressible":true},"application/vnd.d2l.coursepackage1p0+zip":{"source":"iana","compressible":false},"application/vnd.d3m-dataset":{"source":"iana"},"application/vnd.d3m-problem":{"source":"iana"},"application/vnd.dart":{"source":"iana","compressible":true,"extensions":["dart"]},"application/vnd.data-vision.rdz":{"source":"iana","extensions":["rdz"]},"application/vnd.datapackage+json":{"source":"iana","compressible":true},"application/vnd.dataresource+json":{"source":"iana","compressible":true},"application/vnd.dbf":{"source":"iana","extensions":["dbf"]},"application/vnd.debian.binary-package":{"source":"iana"},"application/vnd.dece.data":{"source":"iana","extensions":["uvf","uvvf","uvd","uvvd"]},"application/vnd.dece.ttml+xml":{"source":"iana","compressible":true,"extensions":["uvt","uvvt"]},"application/vnd.dece.unspecified":{"source":"iana","extensions":["uvx","uvvx"]},"application/vnd.dece.zip":{"source":"iana","extensions":["uvz","uvvz"]},"application/vnd.denovo.fcselayout-link":{"source":"iana","extensions":["fe_launch"]},"application/vnd.desmume.movie":{"source":"iana"},"application/vnd.dir-bi.plate-dl-nosuffix":{"source":"iana"},"application/vnd.dm.delegation+xml":{"source":"iana","compressible":true},"application/vnd.dna":{"source":"iana","extensions":["dna"]},"application/vnd.document+json":{"source":"iana","compressible":true},"application/vnd.dolby.mlp":{"source":"apache","extensions":["mlp"]},"application/vnd.dolby.mobile.1":{"source":"iana"},"application/vnd.dolby.mobile.2":{"source":"iana"},"application/vnd.doremir.scorecloud-binary-document":{"source":"iana"},"application/vnd.dpgraph":{"source":"iana","extensions":["dpg"]},"application/vnd.dreamfactory":{"source":"iana","extensions":["dfac"]},"application/vnd.drive+json":{"source":"iana","compressible":true},"application/vnd.ds-keypoint":{"source":"apache","extensions":["kpxx"]},"application/vnd.dtg.local":{"source":"iana"},"application/vnd.dtg.local.flash":{"source":"iana"},"application/vnd.dtg.local.html":{"source":"iana"},"application/vnd.dvb.ait":{"source":"iana","extensions":["ait"]},"application/vnd.dvb.dvbisl+xml":{"source":"iana","compressible":true},"application/vnd.dvb.dvbj":{"source":"iana"},"application/vnd.dvb.esgcontainer":{"source":"iana"},"application/vnd.dvb.ipdcdftnotifaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess2":{"source":"iana"},"application/vnd.dvb.ipdcesgpdd":{"source":"iana"},"application/vnd.dvb.ipdcroaming":{"source":"iana"},"application/vnd.dvb.iptv.alfec-base":{"source":"iana"},"application/vnd.dvb.iptv.alfec-enhancement":{"source":"iana"},"application/vnd.dvb.notif-aggregate-root+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-container+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-generic+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-msglist+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-registration-request+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-registration-response+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-init+xml":{"source":"iana","compressible":true},"application/vnd.dvb.pfr":{"source":"iana"},"application/vnd.dvb.service":{"source":"iana","extensions":["svc"]},"application/vnd.dxr":{"source":"iana"},"application/vnd.dynageo":{"source":"iana","extensions":["geo"]},"application/vnd.dzr":{"source":"iana"},"application/vnd.easykaraoke.cdgdownload":{"source":"iana"},"application/vnd.ecdis-update":{"source":"iana"},"application/vnd.ecip.rlp":{"source":"iana"},"application/vnd.eclipse.ditto+json":{"source":"iana","compressible":true},"application/vnd.ecowin.chart":{"source":"iana","extensions":["mag"]},"application/vnd.ecowin.filerequest":{"source":"iana"},"application/vnd.ecowin.fileupdate":{"source":"iana"},"application/vnd.ecowin.series":{"source":"iana"},"application/vnd.ecowin.seriesrequest":{"source":"iana"},"application/vnd.ecowin.seriesupdate":{"source":"iana"},"application/vnd.efi.img":{"source":"iana"},"application/vnd.efi.iso":{"source":"iana"},"application/vnd.emclient.accessrequest+xml":{"source":"iana","compressible":true},"application/vnd.enliven":{"source":"iana","extensions":["nml"]},"application/vnd.enphase.envoy":{"source":"iana"},"application/vnd.eprints.data+xml":{"source":"iana","compressible":true},"application/vnd.epson.esf":{"source":"iana","extensions":["esf"]},"application/vnd.epson.msf":{"source":"iana","extensions":["msf"]},"application/vnd.epson.quickanime":{"source":"iana","extensions":["qam"]},"application/vnd.epson.salt":{"source":"iana","extensions":["slt"]},"application/vnd.epson.ssf":{"source":"iana","extensions":["ssf"]},"application/vnd.ericsson.quickcall":{"source":"iana"},"application/vnd.espass-espass+zip":{"source":"iana","compressible":false},"application/vnd.eszigno3+xml":{"source":"iana","compressible":true,"extensions":["es3","et3"]},"application/vnd.etsi.aoc+xml":{"source":"iana","compressible":true},"application/vnd.etsi.asic-e+zip":{"source":"iana","compressible":false},"application/vnd.etsi.asic-s+zip":{"source":"iana","compressible":false},"application/vnd.etsi.cug+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvcommand+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvdiscovery+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvprofile+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-bc+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-cod+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-npvr+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvservice+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsync+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvueprofile+xml":{"source":"iana","compressible":true},"application/vnd.etsi.mcid+xml":{"source":"iana","compressible":true},"application/vnd.etsi.mheg5":{"source":"iana"},"application/vnd.etsi.overload-control-policy-dataset+xml":{"source":"iana","compressible":true},"application/vnd.etsi.pstn+xml":{"source":"iana","compressible":true},"application/vnd.etsi.sci+xml":{"source":"iana","compressible":true},"application/vnd.etsi.simservs+xml":{"source":"iana","compressible":true},"application/vnd.etsi.timestamp-token":{"source":"iana"},"application/vnd.etsi.tsl+xml":{"source":"iana","compressible":true},"application/vnd.etsi.tsl.der":{"source":"iana"},"application/vnd.eu.kasparian.car+json":{"source":"iana","compressible":true},"application/vnd.eudora.data":{"source":"iana"},"application/vnd.evolv.ecig.profile":{"source":"iana"},"application/vnd.evolv.ecig.settings":{"source":"iana"},"application/vnd.evolv.ecig.theme":{"source":"iana"},"application/vnd.exstream-empower+zip":{"source":"iana","compressible":false},"application/vnd.exstream-package":{"source":"iana"},"application/vnd.ezpix-album":{"source":"iana","extensions":["ez2"]},"application/vnd.ezpix-package":{"source":"iana","extensions":["ez3"]},"application/vnd.f-secure.mobile":{"source":"iana"},"application/vnd.familysearch.gedcom+zip":{"source":"iana","compressible":false},"application/vnd.fastcopy-disk-image":{"source":"iana"},"application/vnd.fdf":{"source":"iana","extensions":["fdf"]},"application/vnd.fdsn.mseed":{"source":"iana","extensions":["mseed"]},"application/vnd.fdsn.seed":{"source":"iana","extensions":["seed","dataless"]},"application/vnd.ffsns":{"source":"iana"},"application/vnd.ficlab.flb+zip":{"source":"iana","compressible":false},"application/vnd.filmit.zfc":{"source":"iana"},"application/vnd.fints":{"source":"iana"},"application/vnd.firemonkeys.cloudcell":{"source":"iana"},"application/vnd.flographit":{"source":"iana","extensions":["gph"]},"application/vnd.fluxtime.clip":{"source":"iana","extensions":["ftc"]},"application/vnd.font-fontforge-sfd":{"source":"iana"},"application/vnd.framemaker":{"source":"iana","extensions":["fm","frame","maker","book"]},"application/vnd.frogans.fnc":{"source":"iana","extensions":["fnc"]},"application/vnd.frogans.ltf":{"source":"iana","extensions":["ltf"]},"application/vnd.fsc.weblaunch":{"source":"iana","extensions":["fsc"]},"application/vnd.fujifilm.fb.docuworks":{"source":"iana"},"application/vnd.fujifilm.fb.docuworks.binder":{"source":"iana"},"application/vnd.fujifilm.fb.docuworks.container":{"source":"iana"},"application/vnd.fujifilm.fb.jfi+xml":{"source":"iana","compressible":true},"application/vnd.fujitsu.oasys":{"source":"iana","extensions":["oas"]},"application/vnd.fujitsu.oasys2":{"source":"iana","extensions":["oa2"]},"application/vnd.fujitsu.oasys3":{"source":"iana","extensions":["oa3"]},"application/vnd.fujitsu.oasysgp":{"source":"iana","extensions":["fg5"]},"application/vnd.fujitsu.oasysprs":{"source":"iana","extensions":["bh2"]},"application/vnd.fujixerox.art-ex":{"source":"iana"},"application/vnd.fujixerox.art4":{"source":"iana"},"application/vnd.fujixerox.ddd":{"source":"iana","extensions":["ddd"]},"application/vnd.fujixerox.docuworks":{"source":"iana","extensions":["xdw"]},"application/vnd.fujixerox.docuworks.binder":{"source":"iana","extensions":["xbd"]},"application/vnd.fujixerox.docuworks.container":{"source":"iana"},"application/vnd.fujixerox.hbpl":{"source":"iana"},"application/vnd.fut-misnet":{"source":"iana"},"application/vnd.futoin+cbor":{"source":"iana"},"application/vnd.futoin+json":{"source":"iana","compressible":true},"application/vnd.fuzzysheet":{"source":"iana","extensions":["fzs"]},"application/vnd.genomatix.tuxedo":{"source":"iana","extensions":["txd"]},"application/vnd.gentics.grd+json":{"source":"iana","compressible":true},"application/vnd.geo+json":{"source":"iana","compressible":true},"application/vnd.geocube+xml":{"source":"iana","compressible":true},"application/vnd.geogebra.file":{"source":"iana","extensions":["ggb"]},"application/vnd.geogebra.slides":{"source":"iana"},"application/vnd.geogebra.tool":{"source":"iana","extensions":["ggt"]},"application/vnd.geometry-explorer":{"source":"iana","extensions":["gex","gre"]},"application/vnd.geonext":{"source":"iana","extensions":["gxt"]},"application/vnd.geoplan":{"source":"iana","extensions":["g2w"]},"application/vnd.geospace":{"source":"iana","extensions":["g3w"]},"application/vnd.gerber":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt-response":{"source":"iana"},"application/vnd.gmx":{"source":"iana","extensions":["gmx"]},"application/vnd.google-apps.document":{"compressible":false,"extensions":["gdoc"]},"application/vnd.google-apps.presentation":{"compressible":false,"extensions":["gslides"]},"application/vnd.google-apps.spreadsheet":{"compressible":false,"extensions":["gsheet"]},"application/vnd.google-earth.kml+xml":{"source":"iana","compressible":true,"extensions":["kml"]},"application/vnd.google-earth.kmz":{"source":"iana","compressible":false,"extensions":["kmz"]},"application/vnd.gov.sk.e-form+xml":{"source":"iana","compressible":true},"application/vnd.gov.sk.e-form+zip":{"source":"iana","compressible":false},"application/vnd.gov.sk.xmldatacontainer+xml":{"source":"iana","compressible":true},"application/vnd.grafeq":{"source":"iana","extensions":["gqf","gqs"]},"application/vnd.gridmp":{"source":"iana"},"application/vnd.groove-account":{"source":"iana","extensions":["gac"]},"application/vnd.groove-help":{"source":"iana","extensions":["ghf"]},"application/vnd.groove-identity-message":{"source":"iana","extensions":["gim"]},"application/vnd.groove-injector":{"source":"iana","extensions":["grv"]},"application/vnd.groove-tool-message":{"source":"iana","extensions":["gtm"]},"application/vnd.groove-tool-template":{"source":"iana","extensions":["tpl"]},"application/vnd.groove-vcard":{"source":"iana","extensions":["vcg"]},"application/vnd.hal+json":{"source":"iana","compressible":true},"application/vnd.hal+xml":{"source":"iana","compressible":true,"extensions":["hal"]},"application/vnd.handheld-entertainment+xml":{"source":"iana","compressible":true,"extensions":["zmm"]},"application/vnd.hbci":{"source":"iana","extensions":["hbci"]},"application/vnd.hc+json":{"source":"iana","compressible":true},"application/vnd.hcl-bireports":{"source":"iana"},"application/vnd.hdt":{"source":"iana"},"application/vnd.heroku+json":{"source":"iana","compressible":true},"application/vnd.hhe.lesson-player":{"source":"iana","extensions":["les"]},"application/vnd.hl7cda+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.hl7v2+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.hp-hpgl":{"source":"iana","extensions":["hpgl"]},"application/vnd.hp-hpid":{"source":"iana","extensions":["hpid"]},"application/vnd.hp-hps":{"source":"iana","extensions":["hps"]},"application/vnd.hp-jlyt":{"source":"iana","extensions":["jlt"]},"application/vnd.hp-pcl":{"source":"iana","extensions":["pcl"]},"application/vnd.hp-pclxl":{"source":"iana","extensions":["pclxl"]},"application/vnd.httphone":{"source":"iana"},"application/vnd.hydrostatix.sof-data":{"source":"iana","extensions":["sfd-hdstx"]},"application/vnd.hyper+json":{"source":"iana","compressible":true},"application/vnd.hyper-item+json":{"source":"iana","compressible":true},"application/vnd.hyperdrive+json":{"source":"iana","compressible":true},"application/vnd.hzn-3d-crossword":{"source":"iana"},"application/vnd.ibm.afplinedata":{"source":"iana"},"application/vnd.ibm.electronic-media":{"source":"iana"},"application/vnd.ibm.minipay":{"source":"iana","extensions":["mpy"]},"application/vnd.ibm.modcap":{"source":"iana","extensions":["afp","listafp","list3820"]},"application/vnd.ibm.rights-management":{"source":"iana","extensions":["irm"]},"application/vnd.ibm.secure-container":{"source":"iana","extensions":["sc"]},"application/vnd.iccprofile":{"source":"iana","extensions":["icc","icm"]},"application/vnd.ieee.1905":{"source":"iana"},"application/vnd.igloader":{"source":"iana","extensions":["igl"]},"application/vnd.imagemeter.folder+zip":{"source":"iana","compressible":false},"application/vnd.imagemeter.image+zip":{"source":"iana","compressible":false},"application/vnd.immervision-ivp":{"source":"iana","extensions":["ivp"]},"application/vnd.immervision-ivu":{"source":"iana","extensions":["ivu"]},"application/vnd.ims.imsccv1p1":{"source":"iana"},"application/vnd.ims.imsccv1p2":{"source":"iana"},"application/vnd.ims.imsccv1p3":{"source":"iana"},"application/vnd.ims.lis.v2.result+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolconsumerprofile+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy.id+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings.simple+json":{"source":"iana","compressible":true},"application/vnd.informedcontrol.rms+xml":{"source":"iana","compressible":true},"application/vnd.informix-visionary":{"source":"iana"},"application/vnd.infotech.project":{"source":"iana"},"application/vnd.infotech.project+xml":{"source":"iana","compressible":true},"application/vnd.innopath.wamp.notification":{"source":"iana"},"application/vnd.insors.igm":{"source":"iana","extensions":["igm"]},"application/vnd.intercon.formnet":{"source":"iana","extensions":["xpw","xpx"]},"application/vnd.intergeo":{"source":"iana","extensions":["i2g"]},"application/vnd.intertrust.digibox":{"source":"iana"},"application/vnd.intertrust.nncp":{"source":"iana"},"application/vnd.intu.qbo":{"source":"iana","extensions":["qbo"]},"application/vnd.intu.qfx":{"source":"iana","extensions":["qfx"]},"application/vnd.iptc.g2.catalogitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.conceptitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.knowledgeitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.newsitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.newsmessage+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.packageitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.planningitem+xml":{"source":"iana","compressible":true},"application/vnd.ipunplugged.rcprofile":{"source":"iana","extensions":["rcprofile"]},"application/vnd.irepository.package+xml":{"source":"iana","compressible":true,"extensions":["irp"]},"application/vnd.is-xpr":{"source":"iana","extensions":["xpr"]},"application/vnd.isac.fcs":{"source":"iana","extensions":["fcs"]},"application/vnd.iso11783-10+zip":{"source":"iana","compressible":false},"application/vnd.jam":{"source":"iana","extensions":["jam"]},"application/vnd.japannet-directory-service":{"source":"iana"},"application/vnd.japannet-jpnstore-wakeup":{"source":"iana"},"application/vnd.japannet-payment-wakeup":{"source":"iana"},"application/vnd.japannet-registration":{"source":"iana"},"application/vnd.japannet-registration-wakeup":{"source":"iana"},"application/vnd.japannet-setstore-wakeup":{"source":"iana"},"application/vnd.japannet-verification":{"source":"iana"},"application/vnd.japannet-verification-wakeup":{"source":"iana"},"application/vnd.jcp.javame.midlet-rms":{"source":"iana","extensions":["rms"]},"application/vnd.jisp":{"source":"iana","extensions":["jisp"]},"application/vnd.joost.joda-archive":{"source":"iana","extensions":["joda"]},"application/vnd.jsk.isdn-ngn":{"source":"iana"},"application/vnd.kahootz":{"source":"iana","extensions":["ktz","ktr"]},"application/vnd.kde.karbon":{"source":"iana","extensions":["karbon"]},"application/vnd.kde.kchart":{"source":"iana","extensions":["chrt"]},"application/vnd.kde.kformula":{"source":"iana","extensions":["kfo"]},"application/vnd.kde.kivio":{"source":"iana","extensions":["flw"]},"application/vnd.kde.kontour":{"source":"iana","extensions":["kon"]},"application/vnd.kde.kpresenter":{"source":"iana","extensions":["kpr","kpt"]},"application/vnd.kde.kspread":{"source":"iana","extensions":["ksp"]},"application/vnd.kde.kword":{"source":"iana","extensions":["kwd","kwt"]},"application/vnd.kenameaapp":{"source":"iana","extensions":["htke"]},"application/vnd.kidspiration":{"source":"iana","extensions":["kia"]},"application/vnd.kinar":{"source":"iana","extensions":["kne","knp"]},"application/vnd.koan":{"source":"iana","extensions":["skp","skd","skt","skm"]},"application/vnd.kodak-descriptor":{"source":"iana","extensions":["sse"]},"application/vnd.las":{"source":"iana"},"application/vnd.las.las+json":{"source":"iana","compressible":true},"application/vnd.las.las+xml":{"source":"iana","compressible":true,"extensions":["lasxml"]},"application/vnd.laszip":{"source":"iana"},"application/vnd.leap+json":{"source":"iana","compressible":true},"application/vnd.liberty-request+xml":{"source":"iana","compressible":true},"application/vnd.llamagraphics.life-balance.desktop":{"source":"iana","extensions":["lbd"]},"application/vnd.llamagraphics.life-balance.exchange+xml":{"source":"iana","compressible":true,"extensions":["lbe"]},"application/vnd.logipipe.circuit+zip":{"source":"iana","compressible":false},"application/vnd.loom":{"source":"iana"},"application/vnd.lotus-1-2-3":{"source":"iana","extensions":["123"]},"application/vnd.lotus-approach":{"source":"iana","extensions":["apr"]},"application/vnd.lotus-freelance":{"source":"iana","extensions":["pre"]},"application/vnd.lotus-notes":{"source":"iana","extensions":["nsf"]},"application/vnd.lotus-organizer":{"source":"iana","extensions":["org"]},"application/vnd.lotus-screencam":{"source":"iana","extensions":["scm"]},"application/vnd.lotus-wordpro":{"source":"iana","extensions":["lwp"]},"application/vnd.macports.portpkg":{"source":"iana","extensions":["portpkg"]},"application/vnd.mapbox-vector-tile":{"source":"iana","extensions":["mvt"]},"application/vnd.marlin.drm.actiontoken+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.conftoken+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.license+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.mdcf":{"source":"iana"},"application/vnd.mason+json":{"source":"iana","compressible":true},"application/vnd.maxar.archive.3tz+zip":{"source":"iana","compressible":false},"application/vnd.maxmind.maxmind-db":{"source":"iana"},"application/vnd.mcd":{"source":"iana","extensions":["mcd"]},"application/vnd.medcalcdata":{"source":"iana","extensions":["mc1"]},"application/vnd.mediastation.cdkey":{"source":"iana","extensions":["cdkey"]},"application/vnd.meridian-slingshot":{"source":"iana"},"application/vnd.mfer":{"source":"iana","extensions":["mwf"]},"application/vnd.mfmp":{"source":"iana","extensions":["mfm"]},"application/vnd.micro+json":{"source":"iana","compressible":true},"application/vnd.micrografx.flo":{"source":"iana","extensions":["flo"]},"application/vnd.micrografx.igx":{"source":"iana","extensions":["igx"]},"application/vnd.microsoft.portable-executable":{"source":"iana"},"application/vnd.microsoft.windows.thumbnail-cache":{"source":"iana"},"application/vnd.miele+json":{"source":"iana","compressible":true},"application/vnd.mif":{"source":"iana","extensions":["mif"]},"application/vnd.minisoft-hp3000-save":{"source":"iana"},"application/vnd.mitsubishi.misty-guard.trustweb":{"source":"iana"},"application/vnd.mobius.daf":{"source":"iana","extensions":["daf"]},"application/vnd.mobius.dis":{"source":"iana","extensions":["dis"]},"application/vnd.mobius.mbk":{"source":"iana","extensions":["mbk"]},"application/vnd.mobius.mqy":{"source":"iana","extensions":["mqy"]},"application/vnd.mobius.msl":{"source":"iana","extensions":["msl"]},"application/vnd.mobius.plc":{"source":"iana","extensions":["plc"]},"application/vnd.mobius.txf":{"source":"iana","extensions":["txf"]},"application/vnd.mophun.application":{"source":"iana","extensions":["mpn"]},"application/vnd.mophun.certificate":{"source":"iana","extensions":["mpc"]},"application/vnd.motorola.flexsuite":{"source":"iana"},"application/vnd.motorola.flexsuite.adsi":{"source":"iana"},"application/vnd.motorola.flexsuite.fis":{"source":"iana"},"application/vnd.motorola.flexsuite.gotap":{"source":"iana"},"application/vnd.motorola.flexsuite.kmr":{"source":"iana"},"application/vnd.motorola.flexsuite.ttc":{"source":"iana"},"application/vnd.motorola.flexsuite.wem":{"source":"iana"},"application/vnd.motorola.iprm":{"source":"iana"},"application/vnd.mozilla.xul+xml":{"source":"iana","compressible":true,"extensions":["xul"]},"application/vnd.ms-3mfdocument":{"source":"iana"},"application/vnd.ms-artgalry":{"source":"iana","extensions":["cil"]},"application/vnd.ms-asf":{"source":"iana"},"application/vnd.ms-cab-compressed":{"source":"iana","extensions":["cab"]},"application/vnd.ms-color.iccprofile":{"source":"apache"},"application/vnd.ms-excel":{"source":"iana","compressible":false,"extensions":["xls","xlm","xla","xlc","xlt","xlw"]},"application/vnd.ms-excel.addin.macroenabled.12":{"source":"iana","extensions":["xlam"]},"application/vnd.ms-excel.sheet.binary.macroenabled.12":{"source":"iana","extensions":["xlsb"]},"application/vnd.ms-excel.sheet.macroenabled.12":{"source":"iana","extensions":["xlsm"]},"application/vnd.ms-excel.template.macroenabled.12":{"source":"iana","extensions":["xltm"]},"application/vnd.ms-fontobject":{"source":"iana","compressible":true,"extensions":["eot"]},"application/vnd.ms-htmlhelp":{"source":"iana","extensions":["chm"]},"application/vnd.ms-ims":{"source":"iana","extensions":["ims"]},"application/vnd.ms-lrm":{"source":"iana","extensions":["lrm"]},"application/vnd.ms-office.activex+xml":{"source":"iana","compressible":true},"application/vnd.ms-officetheme":{"source":"iana","extensions":["thmx"]},"application/vnd.ms-opentype":{"source":"apache","compressible":true},"application/vnd.ms-outlook":{"compressible":false,"extensions":["msg"]},"application/vnd.ms-package.obfuscated-opentype":{"source":"apache"},"application/vnd.ms-pki.seccat":{"source":"apache","extensions":["cat"]},"application/vnd.ms-pki.stl":{"source":"apache","extensions":["stl"]},"application/vnd.ms-playready.initiator+xml":{"source":"iana","compressible":true},"application/vnd.ms-powerpoint":{"source":"iana","compressible":false,"extensions":["ppt","pps","pot"]},"application/vnd.ms-powerpoint.addin.macroenabled.12":{"source":"iana","extensions":["ppam"]},"application/vnd.ms-powerpoint.presentation.macroenabled.12":{"source":"iana","extensions":["pptm"]},"application/vnd.ms-powerpoint.slide.macroenabled.12":{"source":"iana","extensions":["sldm"]},"application/vnd.ms-powerpoint.slideshow.macroenabled.12":{"source":"iana","extensions":["ppsm"]},"application/vnd.ms-powerpoint.template.macroenabled.12":{"source":"iana","extensions":["potm"]},"application/vnd.ms-printdevicecapabilities+xml":{"source":"iana","compressible":true},"application/vnd.ms-printing.printticket+xml":{"source":"apache","compressible":true},"application/vnd.ms-printschematicket+xml":{"source":"iana","compressible":true},"application/vnd.ms-project":{"source":"iana","extensions":["mpp","mpt"]},"application/vnd.ms-tnef":{"source":"iana"},"application/vnd.ms-windows.devicepairing":{"source":"iana"},"application/vnd.ms-windows.nwprinting.oob":{"source":"iana"},"application/vnd.ms-windows.printerpairing":{"source":"iana"},"application/vnd.ms-windows.wsd.oob":{"source":"iana"},"application/vnd.ms-wmdrm.lic-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.lic-resp":{"source":"iana"},"application/vnd.ms-wmdrm.meter-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.meter-resp":{"source":"iana"},"application/vnd.ms-word.document.macroenabled.12":{"source":"iana","extensions":["docm"]},"application/vnd.ms-word.template.macroenabled.12":{"source":"iana","extensions":["dotm"]},"application/vnd.ms-works":{"source":"iana","extensions":["wps","wks","wcm","wdb"]},"application/vnd.ms-wpl":{"source":"iana","extensions":["wpl"]},"application/vnd.ms-xpsdocument":{"source":"iana","compressible":false,"extensions":["xps"]},"application/vnd.msa-disk-image":{"source":"iana"},"application/vnd.mseq":{"source":"iana","extensions":["mseq"]},"application/vnd.msign":{"source":"iana"},"application/vnd.multiad.creator":{"source":"iana"},"application/vnd.multiad.creator.cif":{"source":"iana"},"application/vnd.music-niff":{"source":"iana"},"application/vnd.musician":{"source":"iana","extensions":["mus"]},"application/vnd.muvee.style":{"source":"iana","extensions":["msty"]},"application/vnd.mynfc":{"source":"iana","extensions":["taglet"]},"application/vnd.nacamar.ybrid+json":{"source":"iana","compressible":true},"application/vnd.ncd.control":{"source":"iana"},"application/vnd.ncd.reference":{"source":"iana"},"application/vnd.nearst.inv+json":{"source":"iana","compressible":true},"application/vnd.nebumind.line":{"source":"iana"},"application/vnd.nervana":{"source":"iana"},"application/vnd.netfpx":{"source":"iana"},"application/vnd.neurolanguage.nlu":{"source":"iana","extensions":["nlu"]},"application/vnd.nimn":{"source":"iana"},"application/vnd.nintendo.nitro.rom":{"source":"iana"},"application/vnd.nintendo.snes.rom":{"source":"iana"},"application/vnd.nitf":{"source":"iana","extensions":["ntf","nitf"]},"application/vnd.noblenet-directory":{"source":"iana","extensions":["nnd"]},"application/vnd.noblenet-sealer":{"source":"iana","extensions":["nns"]},"application/vnd.noblenet-web":{"source":"iana","extensions":["nnw"]},"application/vnd.nokia.catalogs":{"source":"iana"},"application/vnd.nokia.conml+wbxml":{"source":"iana"},"application/vnd.nokia.conml+xml":{"source":"iana","compressible":true},"application/vnd.nokia.iptv.config+xml":{"source":"iana","compressible":true},"application/vnd.nokia.isds-radio-presets":{"source":"iana"},"application/vnd.nokia.landmark+wbxml":{"source":"iana"},"application/vnd.nokia.landmark+xml":{"source":"iana","compressible":true},"application/vnd.nokia.landmarkcollection+xml":{"source":"iana","compressible":true},"application/vnd.nokia.n-gage.ac+xml":{"source":"iana","compressible":true,"extensions":["ac"]},"application/vnd.nokia.n-gage.data":{"source":"iana","extensions":["ngdat"]},"application/vnd.nokia.n-gage.symbian.install":{"source":"iana","extensions":["n-gage"]},"application/vnd.nokia.ncd":{"source":"iana"},"application/vnd.nokia.pcd+wbxml":{"source":"iana"},"application/vnd.nokia.pcd+xml":{"source":"iana","compressible":true},"application/vnd.nokia.radio-preset":{"source":"iana","extensions":["rpst"]},"application/vnd.nokia.radio-presets":{"source":"iana","extensions":["rpss"]},"application/vnd.novadigm.edm":{"source":"iana","extensions":["edm"]},"application/vnd.novadigm.edx":{"source":"iana","extensions":["edx"]},"application/vnd.novadigm.ext":{"source":"iana","extensions":["ext"]},"application/vnd.ntt-local.content-share":{"source":"iana"},"application/vnd.ntt-local.file-transfer":{"source":"iana"},"application/vnd.ntt-local.ogw_remote-access":{"source":"iana"},"application/vnd.ntt-local.sip-ta_remote":{"source":"iana"},"application/vnd.ntt-local.sip-ta_tcp_stream":{"source":"iana"},"application/vnd.oasis.opendocument.chart":{"source":"iana","extensions":["odc"]},"application/vnd.oasis.opendocument.chart-template":{"source":"iana","extensions":["otc"]},"application/vnd.oasis.opendocument.database":{"source":"iana","extensions":["odb"]},"application/vnd.oasis.opendocument.formula":{"source":"iana","extensions":["odf"]},"application/vnd.oasis.opendocument.formula-template":{"source":"iana","extensions":["odft"]},"application/vnd.oasis.opendocument.graphics":{"source":"iana","compressible":false,"extensions":["odg"]},"application/vnd.oasis.opendocument.graphics-template":{"source":"iana","extensions":["otg"]},"application/vnd.oasis.opendocument.image":{"source":"iana","extensions":["odi"]},"application/vnd.oasis.opendocument.image-template":{"source":"iana","extensions":["oti"]},"application/vnd.oasis.opendocument.presentation":{"source":"iana","compressible":false,"extensions":["odp"]},"application/vnd.oasis.opendocument.presentation-template":{"source":"iana","extensions":["otp"]},"application/vnd.oasis.opendocument.spreadsheet":{"source":"iana","compressible":false,"extensions":["ods"]},"application/vnd.oasis.opendocument.spreadsheet-template":{"source":"iana","extensions":["ots"]},"application/vnd.oasis.opendocument.text":{"source":"iana","compressible":false,"extensions":["odt"]},"application/vnd.oasis.opendocument.text-master":{"source":"iana","extensions":["odm"]},"application/vnd.oasis.opendocument.text-template":{"source":"iana","extensions":["ott"]},"application/vnd.oasis.opendocument.text-web":{"source":"iana","extensions":["oth"]},"application/vnd.obn":{"source":"iana"},"application/vnd.ocf+cbor":{"source":"iana"},"application/vnd.oci.image.manifest.v1+json":{"source":"iana","compressible":true},"application/vnd.oftn.l10n+json":{"source":"iana","compressible":true},"application/vnd.oipf.contentaccessdownload+xml":{"source":"iana","compressible":true},"application/vnd.oipf.contentaccessstreaming+xml":{"source":"iana","compressible":true},"application/vnd.oipf.cspg-hexbinary":{"source":"iana"},"application/vnd.oipf.dae.svg+xml":{"source":"iana","compressible":true},"application/vnd.oipf.dae.xhtml+xml":{"source":"iana","compressible":true},"application/vnd.oipf.mippvcontrolmessage+xml":{"source":"iana","compressible":true},"application/vnd.oipf.pae.gem":{"source":"iana"},"application/vnd.oipf.spdiscovery+xml":{"source":"iana","compressible":true},"application/vnd.oipf.spdlist+xml":{"source":"iana","compressible":true},"application/vnd.oipf.ueprofile+xml":{"source":"iana","compressible":true},"application/vnd.oipf.userprofile+xml":{"source":"iana","compressible":true},"application/vnd.olpc-sugar":{"source":"iana","extensions":["xo"]},"application/vnd.oma-scws-config":{"source":"iana"},"application/vnd.oma-scws-http-request":{"source":"iana"},"application/vnd.oma-scws-http-response":{"source":"iana"},"application/vnd.oma.bcast.associated-procedure-parameter+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.drm-trigger+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.imd+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.ltkm":{"source":"iana"},"application/vnd.oma.bcast.notification+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.provisioningtrigger":{"source":"iana"},"application/vnd.oma.bcast.sgboot":{"source":"iana"},"application/vnd.oma.bcast.sgdd+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.sgdu":{"source":"iana"},"application/vnd.oma.bcast.simple-symbol-container":{"source":"iana"},"application/vnd.oma.bcast.smartcard-trigger+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.sprov+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.stkm":{"source":"iana"},"application/vnd.oma.cab-address-book+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-feature-handler+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-pcc+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-subs-invite+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-user-prefs+xml":{"source":"iana","compressible":true},"application/vnd.oma.dcd":{"source":"iana"},"application/vnd.oma.dcdc":{"source":"iana"},"application/vnd.oma.dd2+xml":{"source":"iana","compressible":true,"extensions":["dd2"]},"application/vnd.oma.drm.risd+xml":{"source":"iana","compressible":true},"application/vnd.oma.group-usage-list+xml":{"source":"iana","compressible":true},"application/vnd.oma.lwm2m+cbor":{"source":"iana"},"application/vnd.oma.lwm2m+json":{"source":"iana","compressible":true},"application/vnd.oma.lwm2m+tlv":{"source":"iana"},"application/vnd.oma.pal+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.detailed-progress-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.final-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.groups+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.invocation-descriptor+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.optimized-progress-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.push":{"source":"iana"},"application/vnd.oma.scidm.messages+xml":{"source":"iana","compressible":true},"application/vnd.oma.xcap-directory+xml":{"source":"iana","compressible":true},"application/vnd.omads-email+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.omads-file+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.omads-folder+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.omaloc-supl-init":{"source":"iana"},"application/vnd.onepager":{"source":"iana"},"application/vnd.onepagertamp":{"source":"iana"},"application/vnd.onepagertamx":{"source":"iana"},"application/vnd.onepagertat":{"source":"iana"},"application/vnd.onepagertatp":{"source":"iana"},"application/vnd.onepagertatx":{"source":"iana"},"application/vnd.openblox.game+xml":{"source":"iana","compressible":true,"extensions":["obgx"]},"application/vnd.openblox.game-binary":{"source":"iana"},"application/vnd.openeye.oeb":{"source":"iana"},"application/vnd.openofficeorg.extension":{"source":"apache","extensions":["oxt"]},"application/vnd.openstreetmap.data+xml":{"source":"iana","compressible":true,"extensions":["osm"]},"application/vnd.opentimestamps.ots":{"source":"iana"},"application/vnd.openxmlformats-officedocument.custom-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.customxmlproperties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawing+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.chart+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.extended-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.presentation":{"source":"iana","compressible":false,"extensions":["pptx"]},"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slide":{"source":"iana","extensions":["sldx"]},"application/vnd.openxmlformats-officedocument.presentationml.slide+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slideshow":{"source":"iana","extensions":["ppsx"]},"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.tags+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.template":{"source":"iana","extensions":["potx"]},"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"source":"iana","compressible":false,"extensions":["xlsx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.template":{"source":"iana","extensions":["xltx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.theme+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.themeoverride+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.vmldrawing":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"source":"iana","compressible":false,"extensions":["docx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.template":{"source":"iana","extensions":["dotx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.core-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.relationships+xml":{"source":"iana","compressible":true},"application/vnd.oracle.resource+json":{"source":"iana","compressible":true},"application/vnd.orange.indata":{"source":"iana"},"application/vnd.osa.netdeploy":{"source":"iana"},"application/vnd.osgeo.mapguide.package":{"source":"iana","extensions":["mgp"]},"application/vnd.osgi.bundle":{"source":"iana"},"application/vnd.osgi.dp":{"source":"iana","extensions":["dp"]},"application/vnd.osgi.subsystem":{"source":"iana","extensions":["esa"]},"application/vnd.otps.ct-kip+xml":{"source":"iana","compressible":true},"application/vnd.oxli.countgraph":{"source":"iana"},"application/vnd.pagerduty+json":{"source":"iana","compressible":true},"application/vnd.palm":{"source":"iana","extensions":["pdb","pqa","oprc"]},"application/vnd.panoply":{"source":"iana"},"application/vnd.paos.xml":{"source":"iana"},"application/vnd.patentdive":{"source":"iana"},"application/vnd.patientecommsdoc":{"source":"iana"},"application/vnd.pawaafile":{"source":"iana","extensions":["paw"]},"application/vnd.pcos":{"source":"iana"},"application/vnd.pg.format":{"source":"iana","extensions":["str"]},"application/vnd.pg.osasli":{"source":"iana","extensions":["ei6"]},"application/vnd.piaccess.application-licence":{"source":"iana"},"application/vnd.picsel":{"source":"iana","extensions":["efif"]},"application/vnd.pmi.widget":{"source":"iana","extensions":["wg"]},"application/vnd.poc.group-advertisement+xml":{"source":"iana","compressible":true},"application/vnd.pocketlearn":{"source":"iana","extensions":["plf"]},"application/vnd.powerbuilder6":{"source":"iana","extensions":["pbd"]},"application/vnd.powerbuilder6-s":{"source":"iana"},"application/vnd.powerbuilder7":{"source":"iana"},"application/vnd.powerbuilder7-s":{"source":"iana"},"application/vnd.powerbuilder75":{"source":"iana"},"application/vnd.powerbuilder75-s":{"source":"iana"},"application/vnd.preminet":{"source":"iana"},"application/vnd.previewsystems.box":{"source":"iana","extensions":["box"]},"application/vnd.proteus.magazine":{"source":"iana","extensions":["mgz"]},"application/vnd.psfs":{"source":"iana"},"application/vnd.publishare-delta-tree":{"source":"iana","extensions":["qps"]},"application/vnd.pvi.ptid1":{"source":"iana","extensions":["ptid"]},"application/vnd.pwg-multiplexed":{"source":"iana"},"application/vnd.pwg-xhtml-print+xml":{"source":"iana","compressible":true},"application/vnd.qualcomm.brew-app-res":{"source":"iana"},"application/vnd.quarantainenet":{"source":"iana"},"application/vnd.quark.quarkxpress":{"source":"iana","extensions":["qxd","qxt","qwd","qwt","qxl","qxb"]},"application/vnd.quobject-quoxdocument":{"source":"iana"},"application/vnd.radisys.moml+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-conf+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-conn+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-dialog+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-stream+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-conf+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-base+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-fax-detect+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-fax-sendrecv+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-group+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-speech+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-transform+xml":{"source":"iana","compressible":true},"application/vnd.rainstor.data":{"source":"iana"},"application/vnd.rapid":{"source":"iana"},"application/vnd.rar":{"source":"iana","extensions":["rar"]},"application/vnd.realvnc.bed":{"source":"iana","extensions":["bed"]},"application/vnd.recordare.musicxml":{"source":"iana","extensions":["mxl"]},"application/vnd.recordare.musicxml+xml":{"source":"iana","compressible":true,"extensions":["musicxml"]},"application/vnd.renlearn.rlprint":{"source":"iana"},"application/vnd.resilient.logic":{"source":"iana"},"application/vnd.restful+json":{"source":"iana","compressible":true},"application/vnd.rig.cryptonote":{"source":"iana","extensions":["cryptonote"]},"application/vnd.rim.cod":{"source":"apache","extensions":["cod"]},"application/vnd.rn-realmedia":{"source":"apache","extensions":["rm"]},"application/vnd.rn-realmedia-vbr":{"source":"apache","extensions":["rmvb"]},"application/vnd.route66.link66+xml":{"source":"iana","compressible":true,"extensions":["link66"]},"application/vnd.rs-274x":{"source":"iana"},"application/vnd.ruckus.download":{"source":"iana"},"application/vnd.s3sms":{"source":"iana"},"application/vnd.sailingtracker.track":{"source":"iana","extensions":["st"]},"application/vnd.sar":{"source":"iana"},"application/vnd.sbm.cid":{"source":"iana"},"application/vnd.sbm.mid2":{"source":"iana"},"application/vnd.scribus":{"source":"iana"},"application/vnd.sealed.3df":{"source":"iana"},"application/vnd.sealed.csf":{"source":"iana"},"application/vnd.sealed.doc":{"source":"iana"},"application/vnd.sealed.eml":{"source":"iana"},"application/vnd.sealed.mht":{"source":"iana"},"application/vnd.sealed.net":{"source":"iana"},"application/vnd.sealed.ppt":{"source":"iana"},"application/vnd.sealed.tiff":{"source":"iana"},"application/vnd.sealed.xls":{"source":"iana"},"application/vnd.sealedmedia.softseal.html":{"source":"iana"},"application/vnd.sealedmedia.softseal.pdf":{"source":"iana"},"application/vnd.seemail":{"source":"iana","extensions":["see"]},"application/vnd.seis+json":{"source":"iana","compressible":true},"application/vnd.sema":{"source":"iana","extensions":["sema"]},"application/vnd.semd":{"source":"iana","extensions":["semd"]},"application/vnd.semf":{"source":"iana","extensions":["semf"]},"application/vnd.shade-save-file":{"source":"iana"},"application/vnd.shana.informed.formdata":{"source":"iana","extensions":["ifm"]},"application/vnd.shana.informed.formtemplate":{"source":"iana","extensions":["itp"]},"application/vnd.shana.informed.interchange":{"source":"iana","extensions":["iif"]},"application/vnd.shana.informed.package":{"source":"iana","extensions":["ipk"]},"application/vnd.shootproof+json":{"source":"iana","compressible":true},"application/vnd.shopkick+json":{"source":"iana","compressible":true},"application/vnd.shp":{"source":"iana"},"application/vnd.shx":{"source":"iana"},"application/vnd.sigrok.session":{"source":"iana"},"application/vnd.simtech-mindmapper":{"source":"iana","extensions":["twd","twds"]},"application/vnd.siren+json":{"source":"iana","compressible":true},"application/vnd.smaf":{"source":"iana","extensions":["mmf"]},"application/vnd.smart.notebook":{"source":"iana"},"application/vnd.smart.teacher":{"source":"iana","extensions":["teacher"]},"application/vnd.snesdev-page-table":{"source":"iana"},"application/vnd.software602.filler.form+xml":{"source":"iana","compressible":true,"extensions":["fo"]},"application/vnd.software602.filler.form-xml-zip":{"source":"iana"},"application/vnd.solent.sdkm+xml":{"source":"iana","compressible":true,"extensions":["sdkm","sdkd"]},"application/vnd.spotfire.dxp":{"source":"iana","extensions":["dxp"]},"application/vnd.spotfire.sfs":{"source":"iana","extensions":["sfs"]},"application/vnd.sqlite3":{"source":"iana"},"application/vnd.sss-cod":{"source":"iana"},"application/vnd.sss-dtf":{"source":"iana"},"application/vnd.sss-ntf":{"source":"iana"},"application/vnd.stardivision.calc":{"source":"apache","extensions":["sdc"]},"application/vnd.stardivision.draw":{"source":"apache","extensions":["sda"]},"application/vnd.stardivision.impress":{"source":"apache","extensions":["sdd"]},"application/vnd.stardivision.math":{"source":"apache","extensions":["smf"]},"application/vnd.stardivision.writer":{"source":"apache","extensions":["sdw","vor"]},"application/vnd.stardivision.writer-global":{"source":"apache","extensions":["sgl"]},"application/vnd.stepmania.package":{"source":"iana","extensions":["smzip"]},"application/vnd.stepmania.stepchart":{"source":"iana","extensions":["sm"]},"application/vnd.street-stream":{"source":"iana"},"application/vnd.sun.wadl+xml":{"source":"iana","compressible":true,"extensions":["wadl"]},"application/vnd.sun.xml.calc":{"source":"apache","extensions":["sxc"]},"application/vnd.sun.xml.calc.template":{"source":"apache","extensions":["stc"]},"application/vnd.sun.xml.draw":{"source":"apache","extensions":["sxd"]},"application/vnd.sun.xml.draw.template":{"source":"apache","extensions":["std"]},"application/vnd.sun.xml.impress":{"source":"apache","extensions":["sxi"]},"application/vnd.sun.xml.impress.template":{"source":"apache","extensions":["sti"]},"application/vnd.sun.xml.math":{"source":"apache","extensions":["sxm"]},"application/vnd.sun.xml.writer":{"source":"apache","extensions":["sxw"]},"application/vnd.sun.xml.writer.global":{"source":"apache","extensions":["sxg"]},"application/vnd.sun.xml.writer.template":{"source":"apache","extensions":["stw"]},"application/vnd.sus-calendar":{"source":"iana","extensions":["sus","susp"]},"application/vnd.svd":{"source":"iana","extensions":["svd"]},"application/vnd.swiftview-ics":{"source":"iana"},"application/vnd.sycle+xml":{"source":"iana","compressible":true},"application/vnd.syft+json":{"source":"iana","compressible":true},"application/vnd.symbian.install":{"source":"apache","extensions":["sis","sisx"]},"application/vnd.syncml+xml":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["xsm"]},"application/vnd.syncml.dm+wbxml":{"source":"iana","charset":"UTF-8","extensions":["bdm"]},"application/vnd.syncml.dm+xml":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["xdm"]},"application/vnd.syncml.dm.notification":{"source":"iana"},"application/vnd.syncml.dmddf+wbxml":{"source":"iana"},"application/vnd.syncml.dmddf+xml":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["ddf"]},"application/vnd.syncml.dmtnds+wbxml":{"source":"iana"},"application/vnd.syncml.dmtnds+xml":{"source":"iana","charset":"UTF-8","compressible":true},"application/vnd.syncml.ds.notification":{"source":"iana"},"application/vnd.tableschema+json":{"source":"iana","compressible":true},"application/vnd.tao.intent-module-archive":{"source":"iana","extensions":["tao"]},"application/vnd.tcpdump.pcap":{"source":"iana","extensions":["pcap","cap","dmp"]},"application/vnd.think-cell.ppttc+json":{"source":"iana","compressible":true},"application/vnd.tmd.mediaflex.api+xml":{"source":"iana","compressible":true},"application/vnd.tml":{"source":"iana"},"application/vnd.tmobile-livetv":{"source":"iana","extensions":["tmo"]},"application/vnd.tri.onesource":{"source":"iana"},"application/vnd.trid.tpt":{"source":"iana","extensions":["tpt"]},"application/vnd.triscape.mxs":{"source":"iana","extensions":["mxs"]},"application/vnd.trueapp":{"source":"iana","extensions":["tra"]},"application/vnd.truedoc":{"source":"iana"},"application/vnd.ubisoft.webplayer":{"source":"iana"},"application/vnd.ufdl":{"source":"iana","extensions":["ufd","ufdl"]},"application/vnd.uiq.theme":{"source":"iana","extensions":["utz"]},"application/vnd.umajin":{"source":"iana","extensions":["umj"]},"application/vnd.unity":{"source":"iana","extensions":["unityweb"]},"application/vnd.uoml+xml":{"source":"iana","compressible":true,"extensions":["uoml"]},"application/vnd.uplanet.alert":{"source":"iana"},"application/vnd.uplanet.alert-wbxml":{"source":"iana"},"application/vnd.uplanet.bearer-choice":{"source":"iana"},"application/vnd.uplanet.bearer-choice-wbxml":{"source":"iana"},"application/vnd.uplanet.cacheop":{"source":"iana"},"application/vnd.uplanet.cacheop-wbxml":{"source":"iana"},"application/vnd.uplanet.channel":{"source":"iana"},"application/vnd.uplanet.channel-wbxml":{"source":"iana"},"application/vnd.uplanet.list":{"source":"iana"},"application/vnd.uplanet.list-wbxml":{"source":"iana"},"application/vnd.uplanet.listcmd":{"source":"iana"},"application/vnd.uplanet.listcmd-wbxml":{"source":"iana"},"application/vnd.uplanet.signal":{"source":"iana"},"application/vnd.uri-map":{"source":"iana"},"application/vnd.valve.source.material":{"source":"iana"},"application/vnd.vcx":{"source":"iana","extensions":["vcx"]},"application/vnd.vd-study":{"source":"iana"},"application/vnd.vectorworks":{"source":"iana"},"application/vnd.vel+json":{"source":"iana","compressible":true},"application/vnd.verimatrix.vcas":{"source":"iana"},"application/vnd.veritone.aion+json":{"source":"iana","compressible":true},"application/vnd.veryant.thin":{"source":"iana"},"application/vnd.ves.encrypted":{"source":"iana"},"application/vnd.vidsoft.vidconference":{"source":"iana"},"application/vnd.visio":{"source":"iana","extensions":["vsd","vst","vss","vsw"]},"application/vnd.visionary":{"source":"iana","extensions":["vis"]},"application/vnd.vividence.scriptfile":{"source":"iana"},"application/vnd.vsf":{"source":"iana","extensions":["vsf"]},"application/vnd.wap.sic":{"source":"iana"},"application/vnd.wap.slc":{"source":"iana"},"application/vnd.wap.wbxml":{"source":"iana","charset":"UTF-8","extensions":["wbxml"]},"application/vnd.wap.wmlc":{"source":"iana","extensions":["wmlc"]},"application/vnd.wap.wmlscriptc":{"source":"iana","extensions":["wmlsc"]},"application/vnd.webturbo":{"source":"iana","extensions":["wtb"]},"application/vnd.wfa.dpp":{"source":"iana"},"application/vnd.wfa.p2p":{"source":"iana"},"application/vnd.wfa.wsc":{"source":"iana"},"application/vnd.windows.devicepairing":{"source":"iana"},"application/vnd.wmc":{"source":"iana"},"application/vnd.wmf.bootstrap":{"source":"iana"},"application/vnd.wolfram.mathematica":{"source":"iana"},"application/vnd.wolfram.mathematica.package":{"source":"iana"},"application/vnd.wolfram.player":{"source":"iana","extensions":["nbp"]},"application/vnd.wordperfect":{"source":"iana","extensions":["wpd"]},"application/vnd.wqd":{"source":"iana","extensions":["wqd"]},"application/vnd.wrq-hp3000-labelled":{"source":"iana"},"application/vnd.wt.stf":{"source":"iana","extensions":["stf"]},"application/vnd.wv.csp+wbxml":{"source":"iana"},"application/vnd.wv.csp+xml":{"source":"iana","compressible":true},"application/vnd.wv.ssp+xml":{"source":"iana","compressible":true},"application/vnd.xacml+json":{"source":"iana","compressible":true},"application/vnd.xara":{"source":"iana","extensions":["xar"]},"application/vnd.xfdl":{"source":"iana","extensions":["xfdl"]},"application/vnd.xfdl.webform":{"source":"iana"},"application/vnd.xmi+xml":{"source":"iana","compressible":true},"application/vnd.xmpie.cpkg":{"source":"iana"},"application/vnd.xmpie.dpkg":{"source":"iana"},"application/vnd.xmpie.plan":{"source":"iana"},"application/vnd.xmpie.ppkg":{"source":"iana"},"application/vnd.xmpie.xlim":{"source":"iana"},"application/vnd.yamaha.hv-dic":{"source":"iana","extensions":["hvd"]},"application/vnd.yamaha.hv-script":{"source":"iana","extensions":["hvs"]},"application/vnd.yamaha.hv-voice":{"source":"iana","extensions":["hvp"]},"application/vnd.yamaha.openscoreformat":{"source":"iana","extensions":["osf"]},"application/vnd.yamaha.openscoreformat.osfpvg+xml":{"source":"iana","compressible":true,"extensions":["osfpvg"]},"application/vnd.yamaha.remote-setup":{"source":"iana"},"application/vnd.yamaha.smaf-audio":{"source":"iana","extensions":["saf"]},"application/vnd.yamaha.smaf-phrase":{"source":"iana","extensions":["spf"]},"application/vnd.yamaha.through-ngn":{"source":"iana"},"application/vnd.yamaha.tunnel-udpencap":{"source":"iana"},"application/vnd.yaoweme":{"source":"iana"},"application/vnd.yellowriver-custom-menu":{"source":"iana","extensions":["cmp"]},"application/vnd.youtube.yt":{"source":"iana"},"application/vnd.zul":{"source":"iana","extensions":["zir","zirz"]},"application/vnd.zzazz.deck+xml":{"source":"iana","compressible":true,"extensions":["zaz"]},"application/voicexml+xml":{"source":"iana","compressible":true,"extensions":["vxml"]},"application/voucher-cms+json":{"source":"iana","compressible":true},"application/vq-rtcpxr":{"source":"iana"},"application/wasm":{"source":"iana","compressible":true,"extensions":["wasm"]},"application/watcherinfo+xml":{"source":"iana","compressible":true,"extensions":["wif"]},"application/webpush-options+json":{"source":"iana","compressible":true},"application/whoispp-query":{"source":"iana"},"application/whoispp-response":{"source":"iana"},"application/widget":{"source":"iana","extensions":["wgt"]},"application/winhlp":{"source":"apache","extensions":["hlp"]},"application/wita":{"source":"iana"},"application/wordperfect5.1":{"source":"iana"},"application/wsdl+xml":{"source":"iana","compressible":true,"extensions":["wsdl"]},"application/wspolicy+xml":{"source":"iana","compressible":true,"extensions":["wspolicy"]},"application/x-7z-compressed":{"source":"apache","compressible":false,"extensions":["7z"]},"application/x-abiword":{"source":"apache","extensions":["abw"]},"application/x-ace-compressed":{"source":"apache","extensions":["ace"]},"application/x-amf":{"source":"apache"},"application/x-apple-diskimage":{"source":"apache","extensions":["dmg"]},"application/x-arj":{"compressible":false,"extensions":["arj"]},"application/x-authorware-bin":{"source":"apache","extensions":["aab","x32","u32","vox"]},"application/x-authorware-map":{"source":"apache","extensions":["aam"]},"application/x-authorware-seg":{"source":"apache","extensions":["aas"]},"application/x-bcpio":{"source":"apache","extensions":["bcpio"]},"application/x-bdoc":{"compressible":false,"extensions":["bdoc"]},"application/x-bittorrent":{"source":"apache","extensions":["torrent"]},"application/x-blorb":{"source":"apache","extensions":["blb","blorb"]},"application/x-bzip":{"source":"apache","compressible":false,"extensions":["bz"]},"application/x-bzip2":{"source":"apache","compressible":false,"extensions":["bz2","boz"]},"application/x-cbr":{"source":"apache","extensions":["cbr","cba","cbt","cbz","cb7"]},"application/x-cdlink":{"source":"apache","extensions":["vcd"]},"application/x-cfs-compressed":{"source":"apache","extensions":["cfs"]},"application/x-chat":{"source":"apache","extensions":["chat"]},"application/x-chess-pgn":{"source":"apache","extensions":["pgn"]},"application/x-chrome-extension":{"extensions":["crx"]},"application/x-cocoa":{"source":"nginx","extensions":["cco"]},"application/x-compress":{"source":"apache"},"application/x-conference":{"source":"apache","extensions":["nsc"]},"application/x-cpio":{"source":"apache","extensions":["cpio"]},"application/x-csh":{"source":"apache","extensions":["csh"]},"application/x-deb":{"compressible":false},"application/x-debian-package":{"source":"apache","extensions":["deb","udeb"]},"application/x-dgc-compressed":{"source":"apache","extensions":["dgc"]},"application/x-director":{"source":"apache","extensions":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]},"application/x-doom":{"source":"apache","extensions":["wad"]},"application/x-dtbncx+xml":{"source":"apache","compressible":true,"extensions":["ncx"]},"application/x-dtbook+xml":{"source":"apache","compressible":true,"extensions":["dtb"]},"application/x-dtbresource+xml":{"source":"apache","compressible":true,"extensions":["res"]},"application/x-dvi":{"source":"apache","compressible":false,"extensions":["dvi"]},"application/x-envoy":{"source":"apache","extensions":["evy"]},"application/x-eva":{"source":"apache","extensions":["eva"]},"application/x-font-bdf":{"source":"apache","extensions":["bdf"]},"application/x-font-dos":{"source":"apache"},"application/x-font-framemaker":{"source":"apache"},"application/x-font-ghostscript":{"source":"apache","extensions":["gsf"]},"application/x-font-libgrx":{"source":"apache"},"application/x-font-linux-psf":{"source":"apache","extensions":["psf"]},"application/x-font-pcf":{"source":"apache","extensions":["pcf"]},"application/x-font-snf":{"source":"apache","extensions":["snf"]},"application/x-font-speedo":{"source":"apache"},"application/x-font-sunos-news":{"source":"apache"},"application/x-font-type1":{"source":"apache","extensions":["pfa","pfb","pfm","afm"]},"application/x-font-vfont":{"source":"apache"},"application/x-freearc":{"source":"apache","extensions":["arc"]},"application/x-futuresplash":{"source":"apache","extensions":["spl"]},"application/x-gca-compressed":{"source":"apache","extensions":["gca"]},"application/x-glulx":{"source":"apache","extensions":["ulx"]},"application/x-gnumeric":{"source":"apache","extensions":["gnumeric"]},"application/x-gramps-xml":{"source":"apache","extensions":["gramps"]},"application/x-gtar":{"source":"apache","extensions":["gtar"]},"application/x-gzip":{"source":"apache"},"application/x-hdf":{"source":"apache","extensions":["hdf"]},"application/x-httpd-php":{"compressible":true,"extensions":["php"]},"application/x-install-instructions":{"source":"apache","extensions":["install"]},"application/x-iso9660-image":{"source":"apache","extensions":["iso"]},"application/x-iwork-keynote-sffkey":{"extensions":["key"]},"application/x-iwork-numbers-sffnumbers":{"extensions":["numbers"]},"application/x-iwork-pages-sffpages":{"extensions":["pages"]},"application/x-java-archive-diff":{"source":"nginx","extensions":["jardiff"]},"application/x-java-jnlp-file":{"source":"apache","compressible":false,"extensions":["jnlp"]},"application/x-javascript":{"compressible":true},"application/x-keepass2":{"extensions":["kdbx"]},"application/x-latex":{"source":"apache","compressible":false,"extensions":["latex"]},"application/x-lua-bytecode":{"extensions":["luac"]},"application/x-lzh-compressed":{"source":"apache","extensions":["lzh","lha"]},"application/x-makeself":{"source":"nginx","extensions":["run"]},"application/x-mie":{"source":"apache","extensions":["mie"]},"application/x-mobipocket-ebook":{"source":"apache","extensions":["prc","mobi"]},"application/x-mpegurl":{"compressible":false},"application/x-ms-application":{"source":"apache","extensions":["application"]},"application/x-ms-shortcut":{"source":"apache","extensions":["lnk"]},"application/x-ms-wmd":{"source":"apache","extensions":["wmd"]},"application/x-ms-wmz":{"source":"apache","extensions":["wmz"]},"application/x-ms-xbap":{"source":"apache","extensions":["xbap"]},"application/x-msaccess":{"source":"apache","extensions":["mdb"]},"application/x-msbinder":{"source":"apache","extensions":["obd"]},"application/x-mscardfile":{"source":"apache","extensions":["crd"]},"application/x-msclip":{"source":"apache","extensions":["clp"]},"application/x-msdos-program":{"extensions":["exe"]},"application/x-msdownload":{"source":"apache","extensions":["exe","dll","com","bat","msi"]},"application/x-msmediaview":{"source":"apache","extensions":["mvb","m13","m14"]},"application/x-msmetafile":{"source":"apache","extensions":["wmf","wmz","emf","emz"]},"application/x-msmoney":{"source":"apache","extensions":["mny"]},"application/x-mspublisher":{"source":"apache","extensions":["pub"]},"application/x-msschedule":{"source":"apache","extensions":["scd"]},"application/x-msterminal":{"source":"apache","extensions":["trm"]},"application/x-mswrite":{"source":"apache","extensions":["wri"]},"application/x-netcdf":{"source":"apache","extensions":["nc","cdf"]},"application/x-ns-proxy-autoconfig":{"compressible":true,"extensions":["pac"]},"application/x-nzb":{"source":"apache","extensions":["nzb"]},"application/x-perl":{"source":"nginx","extensions":["pl","pm"]},"application/x-pilot":{"source":"nginx","extensions":["prc","pdb"]},"application/x-pkcs12":{"source":"apache","compressible":false,"extensions":["p12","pfx"]},"application/x-pkcs7-certificates":{"source":"apache","extensions":["p7b","spc"]},"application/x-pkcs7-certreqresp":{"source":"apache","extensions":["p7r"]},"application/x-pki-message":{"source":"iana"},"application/x-rar-compressed":{"source":"apache","compressible":false,"extensions":["rar"]},"application/x-redhat-package-manager":{"source":"nginx","extensions":["rpm"]},"application/x-research-info-systems":{"source":"apache","extensions":["ris"]},"application/x-sea":{"source":"nginx","extensions":["sea"]},"application/x-sh":{"source":"apache","compressible":true,"extensions":["sh"]},"application/x-shar":{"source":"apache","extensions":["shar"]},"application/x-shockwave-flash":{"source":"apache","compressible":false,"extensions":["swf"]},"application/x-silverlight-app":{"source":"apache","extensions":["xap"]},"application/x-sql":{"source":"apache","extensions":["sql"]},"application/x-stuffit":{"source":"apache","compressible":false,"extensions":["sit"]},"application/x-stuffitx":{"source":"apache","extensions":["sitx"]},"application/x-subrip":{"source":"apache","extensions":["srt"]},"application/x-sv4cpio":{"source":"apache","extensions":["sv4cpio"]},"application/x-sv4crc":{"source":"apache","extensions":["sv4crc"]},"application/x-t3vm-image":{"source":"apache","extensions":["t3"]},"application/x-tads":{"source":"apache","extensions":["gam"]},"application/x-tar":{"source":"apache","compressible":true,"extensions":["tar"]},"application/x-tcl":{"source":"apache","extensions":["tcl","tk"]},"application/x-tex":{"source":"apache","extensions":["tex"]},"application/x-tex-tfm":{"source":"apache","extensions":["tfm"]},"application/x-texinfo":{"source":"apache","extensions":["texinfo","texi"]},"application/x-tgif":{"source":"apache","extensions":["obj"]},"application/x-ustar":{"source":"apache","extensions":["ustar"]},"application/x-virtualbox-hdd":{"compressible":true,"extensions":["hdd"]},"application/x-virtualbox-ova":{"compressible":true,"extensions":["ova"]},"application/x-virtualbox-ovf":{"compressible":true,"extensions":["ovf"]},"application/x-virtualbox-vbox":{"compressible":true,"extensions":["vbox"]},"application/x-virtualbox-vbox-extpack":{"compressible":false,"extensions":["vbox-extpack"]},"application/x-virtualbox-vdi":{"compressible":true,"extensions":["vdi"]},"application/x-virtualbox-vhd":{"compressible":true,"extensions":["vhd"]},"application/x-virtualbox-vmdk":{"compressible":true,"extensions":["vmdk"]},"application/x-wais-source":{"source":"apache","extensions":["src"]},"application/x-web-app-manifest+json":{"compressible":true,"extensions":["webapp"]},"application/x-www-form-urlencoded":{"source":"iana","compressible":true},"application/x-x509-ca-cert":{"source":"iana","extensions":["der","crt","pem"]},"application/x-x509-ca-ra-cert":{"source":"iana"},"application/x-x509-next-ca-cert":{"source":"iana"},"application/x-xfig":{"source":"apache","extensions":["fig"]},"application/x-xliff+xml":{"source":"apache","compressible":true,"extensions":["xlf"]},"application/x-xpinstall":{"source":"apache","compressible":false,"extensions":["xpi"]},"application/x-xz":{"source":"apache","extensions":["xz"]},"application/x-zmachine":{"source":"apache","extensions":["z1","z2","z3","z4","z5","z6","z7","z8"]},"application/x400-bp":{"source":"iana"},"application/xacml+xml":{"source":"iana","compressible":true},"application/xaml+xml":{"source":"apache","compressible":true,"extensions":["xaml"]},"application/xcap-att+xml":{"source":"iana","compressible":true,"extensions":["xav"]},"application/xcap-caps+xml":{"source":"iana","compressible":true,"extensions":["xca"]},"application/xcap-diff+xml":{"source":"iana","compressible":true,"extensions":["xdf"]},"application/xcap-el+xml":{"source":"iana","compressible":true,"extensions":["xel"]},"application/xcap-error+xml":{"source":"iana","compressible":true},"application/xcap-ns+xml":{"source":"iana","compressible":true,"extensions":["xns"]},"application/xcon-conference-info+xml":{"source":"iana","compressible":true},"application/xcon-conference-info-diff+xml":{"source":"iana","compressible":true},"application/xenc+xml":{"source":"iana","compressible":true,"extensions":["xenc"]},"application/xhtml+xml":{"source":"iana","compressible":true,"extensions":["xhtml","xht"]},"application/xhtml-voice+xml":{"source":"apache","compressible":true},"application/xliff+xml":{"source":"iana","compressible":true,"extensions":["xlf"]},"application/xml":{"source":"iana","compressible":true,"extensions":["xml","xsl","xsd","rng"]},"application/xml-dtd":{"source":"iana","compressible":true,"extensions":["dtd"]},"application/xml-external-parsed-entity":{"source":"iana"},"application/xml-patch+xml":{"source":"iana","compressible":true},"application/xmpp+xml":{"source":"iana","compressible":true},"application/xop+xml":{"source":"iana","compressible":true,"extensions":["xop"]},"application/xproc+xml":{"source":"apache","compressible":true,"extensions":["xpl"]},"application/xslt+xml":{"source":"iana","compressible":true,"extensions":["xsl","xslt"]},"application/xspf+xml":{"source":"apache","compressible":true,"extensions":["xspf"]},"application/xv+xml":{"source":"iana","compressible":true,"extensions":["mxml","xhvml","xvml","xvm"]},"application/yang":{"source":"iana","extensions":["yang"]},"application/yang-data+json":{"source":"iana","compressible":true},"application/yang-data+xml":{"source":"iana","compressible":true},"application/yang-patch+json":{"source":"iana","compressible":true},"application/yang-patch+xml":{"source":"iana","compressible":true},"application/yin+xml":{"source":"iana","compressible":true,"extensions":["yin"]},"application/zip":{"source":"iana","compressible":false,"extensions":["zip"]},"application/zlib":{"source":"iana"},"application/zstd":{"source":"iana"},"audio/1d-interleaved-parityfec":{"source":"iana"},"audio/32kadpcm":{"source":"iana"},"audio/3gpp":{"source":"iana","compressible":false,"extensions":["3gpp"]},"audio/3gpp2":{"source":"iana"},"audio/aac":{"source":"iana"},"audio/ac3":{"source":"iana"},"audio/adpcm":{"source":"apache","extensions":["adp"]},"audio/amr":{"source":"iana","extensions":["amr"]},"audio/amr-wb":{"source":"iana"},"audio/amr-wb+":{"source":"iana"},"audio/aptx":{"source":"iana"},"audio/asc":{"source":"iana"},"audio/atrac-advanced-lossless":{"source":"iana"},"audio/atrac-x":{"source":"iana"},"audio/atrac3":{"source":"iana"},"audio/basic":{"source":"iana","compressible":false,"extensions":["au","snd"]},"audio/bv16":{"source":"iana"},"audio/bv32":{"source":"iana"},"audio/clearmode":{"source":"iana"},"audio/cn":{"source":"iana"},"audio/dat12":{"source":"iana"},"audio/dls":{"source":"iana"},"audio/dsr-es201108":{"source":"iana"},"audio/dsr-es202050":{"source":"iana"},"audio/dsr-es202211":{"source":"iana"},"audio/dsr-es202212":{"source":"iana"},"audio/dv":{"source":"iana"},"audio/dvi4":{"source":"iana"},"audio/eac3":{"source":"iana"},"audio/encaprtp":{"source":"iana"},"audio/evrc":{"source":"iana"},"audio/evrc-qcp":{"source":"iana"},"audio/evrc0":{"source":"iana"},"audio/evrc1":{"source":"iana"},"audio/evrcb":{"source":"iana"},"audio/evrcb0":{"source":"iana"},"audio/evrcb1":{"source":"iana"},"audio/evrcnw":{"source":"iana"},"audio/evrcnw0":{"source":"iana"},"audio/evrcnw1":{"source":"iana"},"audio/evrcwb":{"source":"iana"},"audio/evrcwb0":{"source":"iana"},"audio/evrcwb1":{"source":"iana"},"audio/evs":{"source":"iana"},"audio/flexfec":{"source":"iana"},"audio/fwdred":{"source":"iana"},"audio/g711-0":{"source":"iana"},"audio/g719":{"source":"iana"},"audio/g722":{"source":"iana"},"audio/g7221":{"source":"iana"},"audio/g723":{"source":"iana"},"audio/g726-16":{"source":"iana"},"audio/g726-24":{"source":"iana"},"audio/g726-32":{"source":"iana"},"audio/g726-40":{"source":"iana"},"audio/g728":{"source":"iana"},"audio/g729":{"source":"iana"},"audio/g7291":{"source":"iana"},"audio/g729d":{"source":"iana"},"audio/g729e":{"source":"iana"},"audio/gsm":{"source":"iana"},"audio/gsm-efr":{"source":"iana"},"audio/gsm-hr-08":{"source":"iana"},"audio/ilbc":{"source":"iana"},"audio/ip-mr_v2.5":{"source":"iana"},"audio/isac":{"source":"apache"},"audio/l16":{"source":"iana"},"audio/l20":{"source":"iana"},"audio/l24":{"source":"iana","compressible":false},"audio/l8":{"source":"iana"},"audio/lpc":{"source":"iana"},"audio/melp":{"source":"iana"},"audio/melp1200":{"source":"iana"},"audio/melp2400":{"source":"iana"},"audio/melp600":{"source":"iana"},"audio/mhas":{"source":"iana"},"audio/midi":{"source":"apache","extensions":["mid","midi","kar","rmi"]},"audio/mobile-xmf":{"source":"iana","extensions":["mxmf"]},"audio/mp3":{"compressible":false,"extensions":["mp3"]},"audio/mp4":{"source":"iana","compressible":false,"extensions":["m4a","mp4a"]},"audio/mp4a-latm":{"source":"iana"},"audio/mpa":{"source":"iana"},"audio/mpa-robust":{"source":"iana"},"audio/mpeg":{"source":"iana","compressible":false,"extensions":["mpga","mp2","mp2a","mp3","m2a","m3a"]},"audio/mpeg4-generic":{"source":"iana"},"audio/musepack":{"source":"apache"},"audio/ogg":{"source":"iana","compressible":false,"extensions":["oga","ogg","spx","opus"]},"audio/opus":{"source":"iana"},"audio/parityfec":{"source":"iana"},"audio/pcma":{"source":"iana"},"audio/pcma-wb":{"source":"iana"},"audio/pcmu":{"source":"iana"},"audio/pcmu-wb":{"source":"iana"},"audio/prs.sid":{"source":"iana"},"audio/qcelp":{"source":"iana"},"audio/raptorfec":{"source":"iana"},"audio/red":{"source":"iana"},"audio/rtp-enc-aescm128":{"source":"iana"},"audio/rtp-midi":{"source":"iana"},"audio/rtploopback":{"source":"iana"},"audio/rtx":{"source":"iana"},"audio/s3m":{"source":"apache","extensions":["s3m"]},"audio/scip":{"source":"iana"},"audio/silk":{"source":"apache","extensions":["sil"]},"audio/smv":{"source":"iana"},"audio/smv-qcp":{"source":"iana"},"audio/smv0":{"source":"iana"},"audio/sofa":{"source":"iana"},"audio/sp-midi":{"source":"iana"},"audio/speex":{"source":"iana"},"audio/t140c":{"source":"iana"},"audio/t38":{"source":"iana"},"audio/telephone-event":{"source":"iana"},"audio/tetra_acelp":{"source":"iana"},"audio/tetra_acelp_bb":{"source":"iana"},"audio/tone":{"source":"iana"},"audio/tsvcis":{"source":"iana"},"audio/uemclip":{"source":"iana"},"audio/ulpfec":{"source":"iana"},"audio/usac":{"source":"iana"},"audio/vdvi":{"source":"iana"},"audio/vmr-wb":{"source":"iana"},"audio/vnd.3gpp.iufp":{"source":"iana"},"audio/vnd.4sb":{"source":"iana"},"audio/vnd.audiokoz":{"source":"iana"},"audio/vnd.celp":{"source":"iana"},"audio/vnd.cisco.nse":{"source":"iana"},"audio/vnd.cmles.radio-events":{"source":"iana"},"audio/vnd.cns.anp1":{"source":"iana"},"audio/vnd.cns.inf1":{"source":"iana"},"audio/vnd.dece.audio":{"source":"iana","extensions":["uva","uvva"]},"audio/vnd.digital-winds":{"source":"iana","extensions":["eol"]},"audio/vnd.dlna.adts":{"source":"iana"},"audio/vnd.dolby.heaac.1":{"source":"iana"},"audio/vnd.dolby.heaac.2":{"source":"iana"},"audio/vnd.dolby.mlp":{"source":"iana"},"audio/vnd.dolby.mps":{"source":"iana"},"audio/vnd.dolby.pl2":{"source":"iana"},"audio/vnd.dolby.pl2x":{"source":"iana"},"audio/vnd.dolby.pl2z":{"source":"iana"},"audio/vnd.dolby.pulse.1":{"source":"iana"},"audio/vnd.dra":{"source":"iana","extensions":["dra"]},"audio/vnd.dts":{"source":"iana","extensions":["dts"]},"audio/vnd.dts.hd":{"source":"iana","extensions":["dtshd"]},"audio/vnd.dts.uhd":{"source":"iana"},"audio/vnd.dvb.file":{"source":"iana"},"audio/vnd.everad.plj":{"source":"iana"},"audio/vnd.hns.audio":{"source":"iana"},"audio/vnd.lucent.voice":{"source":"iana","extensions":["lvp"]},"audio/vnd.ms-playready.media.pya":{"source":"iana","extensions":["pya"]},"audio/vnd.nokia.mobile-xmf":{"source":"iana"},"audio/vnd.nortel.vbk":{"source":"iana"},"audio/vnd.nuera.ecelp4800":{"source":"iana","extensions":["ecelp4800"]},"audio/vnd.nuera.ecelp7470":{"source":"iana","extensions":["ecelp7470"]},"audio/vnd.nuera.ecelp9600":{"source":"iana","extensions":["ecelp9600"]},"audio/vnd.octel.sbc":{"source":"iana"},"audio/vnd.presonus.multitrack":{"source":"iana"},"audio/vnd.qcelp":{"source":"iana"},"audio/vnd.rhetorex.32kadpcm":{"source":"iana"},"audio/vnd.rip":{"source":"iana","extensions":["rip"]},"audio/vnd.rn-realaudio":{"compressible":false},"audio/vnd.sealedmedia.softseal.mpeg":{"source":"iana"},"audio/vnd.vmx.cvsd":{"source":"iana"},"audio/vnd.wave":{"compressible":false},"audio/vorbis":{"source":"iana","compressible":false},"audio/vorbis-config":{"source":"iana"},"audio/wav":{"compressible":false,"extensions":["wav"]},"audio/wave":{"compressible":false,"extensions":["wav"]},"audio/webm":{"source":"apache","compressible":false,"extensions":["weba"]},"audio/x-aac":{"source":"apache","compressible":false,"extensions":["aac"]},"audio/x-aiff":{"source":"apache","extensions":["aif","aiff","aifc"]},"audio/x-caf":{"source":"apache","compressible":false,"extensions":["caf"]},"audio/x-flac":{"source":"apache","extensions":["flac"]},"audio/x-m4a":{"source":"nginx","extensions":["m4a"]},"audio/x-matroska":{"source":"apache","extensions":["mka"]},"audio/x-mpegurl":{"source":"apache","extensions":["m3u"]},"audio/x-ms-wax":{"source":"apache","extensions":["wax"]},"audio/x-ms-wma":{"source":"apache","extensions":["wma"]},"audio/x-pn-realaudio":{"source":"apache","extensions":["ram","ra"]},"audio/x-pn-realaudio-plugin":{"source":"apache","extensions":["rmp"]},"audio/x-realaudio":{"source":"nginx","extensions":["ra"]},"audio/x-tta":{"source":"apache"},"audio/x-wav":{"source":"apache","extensions":["wav"]},"audio/xm":{"source":"apache","extensions":["xm"]},"chemical/x-cdx":{"source":"apache","extensions":["cdx"]},"chemical/x-cif":{"source":"apache","extensions":["cif"]},"chemical/x-cmdf":{"source":"apache","extensions":["cmdf"]},"chemical/x-cml":{"source":"apache","extensions":["cml"]},"chemical/x-csml":{"source":"apache","extensions":["csml"]},"chemical/x-pdb":{"source":"apache"},"chemical/x-xyz":{"source":"apache","extensions":["xyz"]},"font/collection":{"source":"iana","extensions":["ttc"]},"font/otf":{"source":"iana","compressible":true,"extensions":["otf"]},"font/sfnt":{"source":"iana"},"font/ttf":{"source":"iana","compressible":true,"extensions":["ttf"]},"font/woff":{"source":"iana","extensions":["woff"]},"font/woff2":{"source":"iana","extensions":["woff2"]},"image/aces":{"source":"iana","extensions":["exr"]},"image/apng":{"compressible":false,"extensions":["apng"]},"image/avci":{"source":"iana","extensions":["avci"]},"image/avcs":{"source":"iana","extensions":["avcs"]},"image/avif":{"source":"iana","compressible":false,"extensions":["avif"]},"image/bmp":{"source":"iana","compressible":true,"extensions":["bmp"]},"image/cgm":{"source":"iana","extensions":["cgm"]},"image/dicom-rle":{"source":"iana","extensions":["drle"]},"image/emf":{"source":"iana","extensions":["emf"]},"image/fits":{"source":"iana","extensions":["fits"]},"image/g3fax":{"source":"iana","extensions":["g3"]},"image/gif":{"source":"iana","compressible":false,"extensions":["gif"]},"image/heic":{"source":"iana","extensions":["heic"]},"image/heic-sequence":{"source":"iana","extensions":["heics"]},"image/heif":{"source":"iana","extensions":["heif"]},"image/heif-sequence":{"source":"iana","extensions":["heifs"]},"image/hej2k":{"source":"iana","extensions":["hej2"]},"image/hsj2":{"source":"iana","extensions":["hsj2"]},"image/ief":{"source":"iana","extensions":["ief"]},"image/jls":{"source":"iana","extensions":["jls"]},"image/jp2":{"source":"iana","compressible":false,"extensions":["jp2","jpg2"]},"image/jpeg":{"source":"iana","compressible":false,"extensions":["jpeg","jpg","jpe"]},"image/jph":{"source":"iana","extensions":["jph"]},"image/jphc":{"source":"iana","extensions":["jhc"]},"image/jpm":{"source":"iana","compressible":false,"extensions":["jpm"]},"image/jpx":{"source":"iana","compressible":false,"extensions":["jpx","jpf"]},"image/jxr":{"source":"iana","extensions":["jxr"]},"image/jxra":{"source":"iana","extensions":["jxra"]},"image/jxrs":{"source":"iana","extensions":["jxrs"]},"image/jxs":{"source":"iana","extensions":["jxs"]},"image/jxsc":{"source":"iana","extensions":["jxsc"]},"image/jxsi":{"source":"iana","extensions":["jxsi"]},"image/jxss":{"source":"iana","extensions":["jxss"]},"image/ktx":{"source":"iana","extensions":["ktx"]},"image/ktx2":{"source":"iana","extensions":["ktx2"]},"image/naplps":{"source":"iana"},"image/pjpeg":{"compressible":false},"image/png":{"source":"iana","compressible":false,"extensions":["png"]},"image/prs.btif":{"source":"iana","extensions":["btif"]},"image/prs.pti":{"source":"iana","extensions":["pti"]},"image/pwg-raster":{"source":"iana"},"image/sgi":{"source":"apache","extensions":["sgi"]},"image/svg+xml":{"source":"iana","compressible":true,"extensions":["svg","svgz"]},"image/t38":{"source":"iana","extensions":["t38"]},"image/tiff":{"source":"iana","compressible":false,"extensions":["tif","tiff"]},"image/tiff-fx":{"source":"iana","extensions":["tfx"]},"image/vnd.adobe.photoshop":{"source":"iana","compressible":true,"extensions":["psd"]},"image/vnd.airzip.accelerator.azv":{"source":"iana","extensions":["azv"]},"image/vnd.cns.inf2":{"source":"iana"},"image/vnd.dece.graphic":{"source":"iana","extensions":["uvi","uvvi","uvg","uvvg"]},"image/vnd.djvu":{"source":"iana","extensions":["djvu","djv"]},"image/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"image/vnd.dwg":{"source":"iana","extensions":["dwg"]},"image/vnd.dxf":{"source":"iana","extensions":["dxf"]},"image/vnd.fastbidsheet":{"source":"iana","extensions":["fbs"]},"image/vnd.fpx":{"source":"iana","extensions":["fpx"]},"image/vnd.fst":{"source":"iana","extensions":["fst"]},"image/vnd.fujixerox.edmics-mmr":{"source":"iana","extensions":["mmr"]},"image/vnd.fujixerox.edmics-rlc":{"source":"iana","extensions":["rlc"]},"image/vnd.globalgraphics.pgb":{"source":"iana"},"image/vnd.microsoft.icon":{"source":"iana","compressible":true,"extensions":["ico"]},"image/vnd.mix":{"source":"iana"},"image/vnd.mozilla.apng":{"source":"iana"},"image/vnd.ms-dds":{"compressible":true,"extensions":["dds"]},"image/vnd.ms-modi":{"source":"iana","extensions":["mdi"]},"image/vnd.ms-photo":{"source":"apache","extensions":["wdp"]},"image/vnd.net-fpx":{"source":"iana","extensions":["npx"]},"image/vnd.pco.b16":{"source":"iana","extensions":["b16"]},"image/vnd.radiance":{"source":"iana"},"image/vnd.sealed.png":{"source":"iana"},"image/vnd.sealedmedia.softseal.gif":{"source":"iana"},"image/vnd.sealedmedia.softseal.jpg":{"source":"iana"},"image/vnd.svf":{"source":"iana"},"image/vnd.tencent.tap":{"source":"iana","extensions":["tap"]},"image/vnd.valve.source.texture":{"source":"iana","extensions":["vtf"]},"image/vnd.wap.wbmp":{"source":"iana","extensions":["wbmp"]},"image/vnd.xiff":{"source":"iana","extensions":["xif"]},"image/vnd.zbrush.pcx":{"source":"iana","extensions":["pcx"]},"image/webp":{"source":"apache","extensions":["webp"]},"image/wmf":{"source":"iana","extensions":["wmf"]},"image/x-3ds":{"source":"apache","extensions":["3ds"]},"image/x-cmu-raster":{"source":"apache","extensions":["ras"]},"image/x-cmx":{"source":"apache","extensions":["cmx"]},"image/x-freehand":{"source":"apache","extensions":["fh","fhc","fh4","fh5","fh7"]},"image/x-icon":{"source":"apache","compressible":true,"extensions":["ico"]},"image/x-jng":{"source":"nginx","extensions":["jng"]},"image/x-mrsid-image":{"source":"apache","extensions":["sid"]},"image/x-ms-bmp":{"source":"nginx","compressible":true,"extensions":["bmp"]},"image/x-pcx":{"source":"apache","extensions":["pcx"]},"image/x-pict":{"source":"apache","extensions":["pic","pct"]},"image/x-portable-anymap":{"source":"apache","extensions":["pnm"]},"image/x-portable-bitmap":{"source":"apache","extensions":["pbm"]},"image/x-portable-graymap":{"source":"apache","extensions":["pgm"]},"image/x-portable-pixmap":{"source":"apache","extensions":["ppm"]},"image/x-rgb":{"source":"apache","extensions":["rgb"]},"image/x-tga":{"source":"apache","extensions":["tga"]},"image/x-xbitmap":{"source":"apache","extensions":["xbm"]},"image/x-xcf":{"compressible":false},"image/x-xpixmap":{"source":"apache","extensions":["xpm"]},"image/x-xwindowdump":{"source":"apache","extensions":["xwd"]},"message/cpim":{"source":"iana"},"message/delivery-status":{"source":"iana"},"message/disposition-notification":{"source":"iana","extensions":["disposition-notification"]},"message/external-body":{"source":"iana"},"message/feedback-report":{"source":"iana"},"message/global":{"source":"iana","extensions":["u8msg"]},"message/global-delivery-status":{"source":"iana","extensions":["u8dsn"]},"message/global-disposition-notification":{"source":"iana","extensions":["u8mdn"]},"message/global-headers":{"source":"iana","extensions":["u8hdr"]},"message/http":{"source":"iana","compressible":false},"message/imdn+xml":{"source":"iana","compressible":true},"message/news":{"source":"iana"},"message/partial":{"source":"iana","compressible":false},"message/rfc822":{"source":"iana","compressible":true,"extensions":["eml","mime"]},"message/s-http":{"source":"iana"},"message/sip":{"source":"iana"},"message/sipfrag":{"source":"iana"},"message/tracking-status":{"source":"iana"},"message/vnd.si.simp":{"source":"iana"},"message/vnd.wfa.wsc":{"source":"iana","extensions":["wsc"]},"model/3mf":{"source":"iana","extensions":["3mf"]},"model/e57":{"source":"iana"},"model/gltf+json":{"source":"iana","compressible":true,"extensions":["gltf"]},"model/gltf-binary":{"source":"iana","compressible":true,"extensions":["glb"]},"model/iges":{"source":"iana","compressible":false,"extensions":["igs","iges"]},"model/mesh":{"source":"iana","compressible":false,"extensions":["msh","mesh","silo"]},"model/mtl":{"source":"iana","extensions":["mtl"]},"model/obj":{"source":"iana","extensions":["obj"]},"model/step":{"source":"iana"},"model/step+xml":{"source":"iana","compressible":true,"extensions":["stpx"]},"model/step+zip":{"source":"iana","compressible":false,"extensions":["stpz"]},"model/step-xml+zip":{"source":"iana","compressible":false,"extensions":["stpxz"]},"model/stl":{"source":"iana","extensions":["stl"]},"model/vnd.collada+xml":{"source":"iana","compressible":true,"extensions":["dae"]},"model/vnd.dwf":{"source":"iana","extensions":["dwf"]},"model/vnd.flatland.3dml":{"source":"iana"},"model/vnd.gdl":{"source":"iana","extensions":["gdl"]},"model/vnd.gs-gdl":{"source":"apache"},"model/vnd.gs.gdl":{"source":"iana"},"model/vnd.gtw":{"source":"iana","extensions":["gtw"]},"model/vnd.moml+xml":{"source":"iana","compressible":true},"model/vnd.mts":{"source":"iana","extensions":["mts"]},"model/vnd.opengex":{"source":"iana","extensions":["ogex"]},"model/vnd.parasolid.transmit.binary":{"source":"iana","extensions":["x_b"]},"model/vnd.parasolid.transmit.text":{"source":"iana","extensions":["x_t"]},"model/vnd.pytha.pyox":{"source":"iana"},"model/vnd.rosette.annotated-data-model":{"source":"iana"},"model/vnd.sap.vds":{"source":"iana","extensions":["vds"]},"model/vnd.usdz+zip":{"source":"iana","compressible":false,"extensions":["usdz"]},"model/vnd.valve.source.compiled-map":{"source":"iana","extensions":["bsp"]},"model/vnd.vtu":{"source":"iana","extensions":["vtu"]},"model/vrml":{"source":"iana","compressible":false,"extensions":["wrl","vrml"]},"model/x3d+binary":{"source":"apache","compressible":false,"extensions":["x3db","x3dbz"]},"model/x3d+fastinfoset":{"source":"iana","extensions":["x3db"]},"model/x3d+vrml":{"source":"apache","compressible":false,"extensions":["x3dv","x3dvz"]},"model/x3d+xml":{"source":"iana","compressible":true,"extensions":["x3d","x3dz"]},"model/x3d-vrml":{"source":"iana","extensions":["x3dv"]},"multipart/alternative":{"source":"iana","compressible":false},"multipart/appledouble":{"source":"iana"},"multipart/byteranges":{"source":"iana"},"multipart/digest":{"source":"iana"},"multipart/encrypted":{"source":"iana","compressible":false},"multipart/form-data":{"source":"iana","compressible":false},"multipart/header-set":{"source":"iana"},"multipart/mixed":{"source":"iana"},"multipart/multilingual":{"source":"iana"},"multipart/parallel":{"source":"iana"},"multipart/related":{"source":"iana","compressible":false},"multipart/report":{"source":"iana"},"multipart/signed":{"source":"iana","compressible":false},"multipart/vnd.bint.med-plus":{"source":"iana"},"multipart/voice-message":{"source":"iana"},"multipart/x-mixed-replace":{"source":"iana"},"text/1d-interleaved-parityfec":{"source":"iana"},"text/cache-manifest":{"source":"iana","compressible":true,"extensions":["appcache","manifest"]},"text/calendar":{"source":"iana","extensions":["ics","ifb"]},"text/calender":{"compressible":true},"text/cmd":{"compressible":true},"text/coffeescript":{"extensions":["coffee","litcoffee"]},"text/cql":{"source":"iana"},"text/cql-expression":{"source":"iana"},"text/cql-identifier":{"source":"iana"},"text/css":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["css"]},"text/csv":{"source":"iana","compressible":true,"extensions":["csv"]},"text/csv-schema":{"source":"iana"},"text/directory":{"source":"iana"},"text/dns":{"source":"iana"},"text/ecmascript":{"source":"iana"},"text/encaprtp":{"source":"iana"},"text/enriched":{"source":"iana"},"text/fhirpath":{"source":"iana"},"text/flexfec":{"source":"iana"},"text/fwdred":{"source":"iana"},"text/gff3":{"source":"iana"},"text/grammar-ref-list":{"source":"iana"},"text/html":{"source":"iana","compressible":true,"extensions":["html","htm","shtml"]},"text/jade":{"extensions":["jade"]},"text/javascript":{"source":"iana","compressible":true},"text/jcr-cnd":{"source":"iana"},"text/jsx":{"compressible":true,"extensions":["jsx"]},"text/less":{"compressible":true,"extensions":["less"]},"text/markdown":{"source":"iana","compressible":true,"extensions":["markdown","md"]},"text/mathml":{"source":"nginx","extensions":["mml"]},"text/mdx":{"compressible":true,"extensions":["mdx"]},"text/mizar":{"source":"iana"},"text/n3":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["n3"]},"text/parameters":{"source":"iana","charset":"UTF-8"},"text/parityfec":{"source":"iana"},"text/plain":{"source":"iana","compressible":true,"extensions":["txt","text","conf","def","list","log","in","ini"]},"text/provenance-notation":{"source":"iana","charset":"UTF-8"},"text/prs.fallenstein.rst":{"source":"iana"},"text/prs.lines.tag":{"source":"iana","extensions":["dsc"]},"text/prs.prop.logic":{"source":"iana"},"text/raptorfec":{"source":"iana"},"text/red":{"source":"iana"},"text/rfc822-headers":{"source":"iana"},"text/richtext":{"source":"iana","compressible":true,"extensions":["rtx"]},"text/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"text/rtp-enc-aescm128":{"source":"iana"},"text/rtploopback":{"source":"iana"},"text/rtx":{"source":"iana"},"text/sgml":{"source":"iana","extensions":["sgml","sgm"]},"text/shaclc":{"source":"iana"},"text/shex":{"source":"iana","extensions":["shex"]},"text/slim":{"extensions":["slim","slm"]},"text/spdx":{"source":"iana","extensions":["spdx"]},"text/strings":{"source":"iana"},"text/stylus":{"extensions":["stylus","styl"]},"text/t140":{"source":"iana"},"text/tab-separated-values":{"source":"iana","compressible":true,"extensions":["tsv"]},"text/troff":{"source":"iana","extensions":["t","tr","roff","man","me","ms"]},"text/turtle":{"source":"iana","charset":"UTF-8","extensions":["ttl"]},"text/ulpfec":{"source":"iana"},"text/uri-list":{"source":"iana","compressible":true,"extensions":["uri","uris","urls"]},"text/vcard":{"source":"iana","compressible":true,"extensions":["vcard"]},"text/vnd.a":{"source":"iana"},"text/vnd.abc":{"source":"iana"},"text/vnd.ascii-art":{"source":"iana"},"text/vnd.curl":{"source":"iana","extensions":["curl"]},"text/vnd.curl.dcurl":{"source":"apache","extensions":["dcurl"]},"text/vnd.curl.mcurl":{"source":"apache","extensions":["mcurl"]},"text/vnd.curl.scurl":{"source":"apache","extensions":["scurl"]},"text/vnd.debian.copyright":{"source":"iana","charset":"UTF-8"},"text/vnd.dmclientscript":{"source":"iana"},"text/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"text/vnd.esmertec.theme-descriptor":{"source":"iana","charset":"UTF-8"},"text/vnd.familysearch.gedcom":{"source":"iana","extensions":["ged"]},"text/vnd.ficlab.flt":{"source":"iana"},"text/vnd.fly":{"source":"iana","extensions":["fly"]},"text/vnd.fmi.flexstor":{"source":"iana","extensions":["flx"]},"text/vnd.gml":{"source":"iana"},"text/vnd.graphviz":{"source":"iana","extensions":["gv"]},"text/vnd.hans":{"source":"iana"},"text/vnd.hgl":{"source":"iana"},"text/vnd.in3d.3dml":{"source":"iana","extensions":["3dml"]},"text/vnd.in3d.spot":{"source":"iana","extensions":["spot"]},"text/vnd.iptc.newsml":{"source":"iana"},"text/vnd.iptc.nitf":{"source":"iana"},"text/vnd.latex-z":{"source":"iana"},"text/vnd.motorola.reflex":{"source":"iana"},"text/vnd.ms-mediapackage":{"source":"iana"},"text/vnd.net2phone.commcenter.command":{"source":"iana"},"text/vnd.radisys.msml-basic-layout":{"source":"iana"},"text/vnd.senx.warpscript":{"source":"iana"},"text/vnd.si.uricatalogue":{"source":"iana"},"text/vnd.sosi":{"source":"iana"},"text/vnd.sun.j2me.app-descriptor":{"source":"iana","charset":"UTF-8","extensions":["jad"]},"text/vnd.trolltech.linguist":{"source":"iana","charset":"UTF-8"},"text/vnd.wap.si":{"source":"iana"},"text/vnd.wap.sl":{"source":"iana"},"text/vnd.wap.wml":{"source":"iana","extensions":["wml"]},"text/vnd.wap.wmlscript":{"source":"iana","extensions":["wmls"]},"text/vtt":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["vtt"]},"text/x-asm":{"source":"apache","extensions":["s","asm"]},"text/x-c":{"source":"apache","extensions":["c","cc","cxx","cpp","h","hh","dic"]},"text/x-component":{"source":"nginx","extensions":["htc"]},"text/x-fortran":{"source":"apache","extensions":["f","for","f77","f90"]},"text/x-gwt-rpc":{"compressible":true},"text/x-handlebars-template":{"extensions":["hbs"]},"text/x-java-source":{"source":"apache","extensions":["java"]},"text/x-jquery-tmpl":{"compressible":true},"text/x-lua":{"extensions":["lua"]},"text/x-markdown":{"compressible":true,"extensions":["mkd"]},"text/x-nfo":{"source":"apache","extensions":["nfo"]},"text/x-opml":{"source":"apache","extensions":["opml"]},"text/x-org":{"compressible":true,"extensions":["org"]},"text/x-pascal":{"source":"apache","extensions":["p","pas"]},"text/x-processing":{"compressible":true,"extensions":["pde"]},"text/x-sass":{"extensions":["sass"]},"text/x-scss":{"extensions":["scss"]},"text/x-setext":{"source":"apache","extensions":["etx"]},"text/x-sfv":{"source":"apache","extensions":["sfv"]},"text/x-suse-ymp":{"compressible":true,"extensions":["ymp"]},"text/x-uuencode":{"source":"apache","extensions":["uu"]},"text/x-vcalendar":{"source":"apache","extensions":["vcs"]},"text/x-vcard":{"source":"apache","extensions":["vcf"]},"text/xml":{"source":"iana","compressible":true,"extensions":["xml"]},"text/xml-external-parsed-entity":{"source":"iana"},"text/yaml":{"compressible":true,"extensions":["yaml","yml"]},"video/1d-interleaved-parityfec":{"source":"iana"},"video/3gpp":{"source":"iana","extensions":["3gp","3gpp"]},"video/3gpp-tt":{"source":"iana"},"video/3gpp2":{"source":"iana","extensions":["3g2"]},"video/av1":{"source":"iana"},"video/bmpeg":{"source":"iana"},"video/bt656":{"source":"iana"},"video/celb":{"source":"iana"},"video/dv":{"source":"iana"},"video/encaprtp":{"source":"iana"},"video/ffv1":{"source":"iana"},"video/flexfec":{"source":"iana"},"video/h261":{"source":"iana","extensions":["h261"]},"video/h263":{"source":"iana","extensions":["h263"]},"video/h263-1998":{"source":"iana"},"video/h263-2000":{"source":"iana"},"video/h264":{"source":"iana","extensions":["h264"]},"video/h264-rcdo":{"source":"iana"},"video/h264-svc":{"source":"iana"},"video/h265":{"source":"iana"},"video/iso.segment":{"source":"iana","extensions":["m4s"]},"video/jpeg":{"source":"iana","extensions":["jpgv"]},"video/jpeg2000":{"source":"iana"},"video/jpm":{"source":"apache","extensions":["jpm","jpgm"]},"video/jxsv":{"source":"iana"},"video/mj2":{"source":"iana","extensions":["mj2","mjp2"]},"video/mp1s":{"source":"iana"},"video/mp2p":{"source":"iana"},"video/mp2t":{"source":"iana","extensions":["ts"]},"video/mp4":{"source":"iana","compressible":false,"extensions":["mp4","mp4v","mpg4"]},"video/mp4v-es":{"source":"iana"},"video/mpeg":{"source":"iana","compressible":false,"extensions":["mpeg","mpg","mpe","m1v","m2v"]},"video/mpeg4-generic":{"source":"iana"},"video/mpv":{"source":"iana"},"video/nv":{"source":"iana"},"video/ogg":{"source":"iana","compressible":false,"extensions":["ogv"]},"video/parityfec":{"source":"iana"},"video/pointer":{"source":"iana"},"video/quicktime":{"source":"iana","compressible":false,"extensions":["qt","mov"]},"video/raptorfec":{"source":"iana"},"video/raw":{"source":"iana"},"video/rtp-enc-aescm128":{"source":"iana"},"video/rtploopback":{"source":"iana"},"video/rtx":{"source":"iana"},"video/scip":{"source":"iana"},"video/smpte291":{"source":"iana"},"video/smpte292m":{"source":"iana"},"video/ulpfec":{"source":"iana"},"video/vc1":{"source":"iana"},"video/vc2":{"source":"iana"},"video/vnd.cctv":{"source":"iana"},"video/vnd.dece.hd":{"source":"iana","extensions":["uvh","uvvh"]},"video/vnd.dece.mobile":{"source":"iana","extensions":["uvm","uvvm"]},"video/vnd.dece.mp4":{"source":"iana"},"video/vnd.dece.pd":{"source":"iana","extensions":["uvp","uvvp"]},"video/vnd.dece.sd":{"source":"iana","extensions":["uvs","uvvs"]},"video/vnd.dece.video":{"source":"iana","extensions":["uvv","uvvv"]},"video/vnd.directv.mpeg":{"source":"iana"},"video/vnd.directv.mpeg-tts":{"source":"iana"},"video/vnd.dlna.mpeg-tts":{"source":"iana"},"video/vnd.dvb.file":{"source":"iana","extensions":["dvb"]},"video/vnd.fvt":{"source":"iana","extensions":["fvt"]},"video/vnd.hns.video":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.ttsavc":{"source":"iana"},"video/vnd.iptvforum.ttsmpeg2":{"source":"iana"},"video/vnd.motorola.video":{"source":"iana"},"video/vnd.motorola.videop":{"source":"iana"},"video/vnd.mpegurl":{"source":"iana","extensions":["mxu","m4u"]},"video/vnd.ms-playready.media.pyv":{"source":"iana","extensions":["pyv"]},"video/vnd.nokia.interleaved-multimedia":{"source":"iana"},"video/vnd.nokia.mp4vr":{"source":"iana"},"video/vnd.nokia.videovoip":{"source":"iana"},"video/vnd.objectvideo":{"source":"iana"},"video/vnd.radgamettools.bink":{"source":"iana"},"video/vnd.radgamettools.smacker":{"source":"iana"},"video/vnd.sealed.mpeg1":{"source":"iana"},"video/vnd.sealed.mpeg4":{"source":"iana"},"video/vnd.sealed.swf":{"source":"iana"},"video/vnd.sealedmedia.softseal.mov":{"source":"iana"},"video/vnd.uvvu.mp4":{"source":"iana","extensions":["uvu","uvvu"]},"video/vnd.vivo":{"source":"iana","extensions":["viv"]},"video/vnd.youtube.yt":{"source":"iana"},"video/vp8":{"source":"iana"},"video/vp9":{"source":"iana"},"video/webm":{"source":"apache","compressible":false,"extensions":["webm"]},"video/x-f4v":{"source":"apache","extensions":["f4v"]},"video/x-fli":{"source":"apache","extensions":["fli"]},"video/x-flv":{"source":"apache","compressible":false,"extensions":["flv"]},"video/x-m4v":{"source":"apache","extensions":["m4v"]},"video/x-matroska":{"source":"apache","compressible":false,"extensions":["mkv","mk3d","mks"]},"video/x-mng":{"source":"apache","extensions":["mng"]},"video/x-ms-asf":{"source":"apache","extensions":["asf","asx"]},"video/x-ms-vob":{"source":"apache","extensions":["vob"]},"video/x-ms-wm":{"source":"apache","extensions":["wm"]},"video/x-ms-wmv":{"source":"apache","compressible":false,"extensions":["wmv"]},"video/x-ms-wmx":{"source":"apache","extensions":["wmx"]},"video/x-ms-wvx":{"source":"apache","extensions":["wvx"]},"video/x-msvideo":{"source":"apache","extensions":["avi"]},"video/x-sgi-movie":{"source":"apache","extensions":["movie"]},"video/x-smv":{"source":"apache","extensions":["smv"]},"x-conference/x-cooltalk":{"source":"apache","extensions":["ice"]},"x-shader/x-fragment":{"compressible":true},"x-shader/x-vertex":{"compressible":true}}')}};var t={};function __nccwpck_require__(a){var n=t[a];if(n!==undefined){return n.exports}var i=t[a]={exports:{}};var o=true;try{e[a].call(i.exports,i,i.exports,__nccwpck_require__);o=false}finally{if(o)delete t[a]}return i.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var a=__nccwpck_require__(8755);module.exports=a})(); \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..8d7316d --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,49 @@ +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import {importX} from 'eslint-plugin-import-x'; +import jest from 'eslint-plugin-jest'; +import prettierRecommended from 'eslint-plugin-prettier/recommended'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import js from '@eslint/js'; + +export default [ + js.configs.recommended, + ...typescriptEslint.configs['flat/recommended'], + importX.flatConfigs.errors, + importX.flatConfigs.warnings, + importX.flatConfigs.typescript, + prettierRecommended, + eslintConfigPrettier, + { + plugins: { + jest + }, + + languageOptions: { + globals: { + ...globals.node, + ...globals.jest + }, + + parser: tsParser, + ecmaVersion: 2021, + sourceType: 'module' + }, + + settings: { + 'import-x/resolver': { + typescript: { + alwaysTryTypes: true, + project: './tsconfig.json' + }, + node: { + extensions: ['.js', '.ts'] + } + }, + 'import-x/parsers': { + '@typescript-eslint/parser': ['.ts'] + } + } + } +]; diff --git a/examples/bedrock.yml b/examples/bedrock.yml new file mode 100644 index 0000000..2a938dc --- /dev/null +++ b/examples/bedrock.yml @@ -0,0 +1,38 @@ +# GitHub Action for roots/bedrock +name: Testing Bedrock +on: [push, pull_request] +jobs: + bedrock: + name: Bedrock (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: PHP test + run: composer test diff --git a/examples/blackfire-player.yml b/examples/blackfire-player.yml new file mode 100644 index 0000000..c9e5489 --- /dev/null +++ b/examples/blackfire-player.yml @@ -0,0 +1,47 @@ +# GitHub Action for Blackfire Player +name: Play a Blackfire Scenario +on: [push, pull_request] +jobs: + blackfire-player: + name: Blackfire (PHP ${{ matrix.php-versions }}) + defaults: + run: + shell: bash + # Add your Blackfire credentials securely using GitHub Secrets + env: + BLACKFIRE_SERVER_ID: ${{ secrets.BLACKFIRE_SERVER_ID }} + BLACKFIRE_SERVER_TOKEN: ${{ secrets.BLACKFIRE_SERVER_TOKEN }} + BLACKFIRE_CLIENT_ID: ${{ secrets.BLACKFIRE_CLIENT_ID }} + BLACKFIRE_CLIENT_TOKEN: ${{ secrets.BLACKFIRE_CLIENT_TOKEN }} + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + # Blackfire Player supports PHP 8.5 and is available on Ubuntu and macOS. + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: blackfire + # Setup Blackfire CLI and player + tools: blackfire, blackfire-player + coverage: none + + - name: Start local endpoint + run: | + php -S 127.0.0.1:8080 > "$RUNNER_TEMP/blackfire-player.log" 2>&1 & + sleep 5 + + - name: Validate scenario + run: blackfire-player validate scenario.bkf + + # Refer to https://docs.blackfire.io/builds-cookbooks/player + - name: Play the scenario + run: blackfire-player run scenario.bkf --endpoint=http://127.0.0.1:8080 diff --git a/examples/blackfire.yml b/examples/blackfire.yml new file mode 100644 index 0000000..c295175 --- /dev/null +++ b/examples/blackfire.yml @@ -0,0 +1,49 @@ +# GitHub Action for Blackfire +name: Profiling with blackfire +on: [push, pull_request] +jobs: + blackfire: + name: Blackfire (PHP ${{ matrix.php-versions }}) + # Add your Blackfire credentials securely using GitHub Secrets + env: + BLACKFIRE_SERVER_ID: ${{ secrets.BLACKFIRE_SERVER_ID }} + BLACKFIRE_SERVER_TOKEN: ${{ secrets.BLACKFIRE_SERVER_TOKEN }} + BLACKFIRE_CLIENT_ID: ${{ secrets.BLACKFIRE_CLIENT_ID }} + BLACKFIRE_CLIENT_TOKEN: ${{ secrets.BLACKFIRE_CLIENT_TOKEN }} + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + # Blackfire supports the current PHP releases on Ubuntu, macOS, and Windows. + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + # Setup Blackfire extension and CLI. + extensions: blackfire, :xdebug + tools: blackfire + # Disable Xdebug and PCOV coverage drivers + coverage: none + + # Refer to https://blackfire.io/docs/cookbooks/profiling-cli + - name: Profile + shell: bash + run: | + set +e + output=$(blackfire run php my-script.php 2>&1) + exit_code=$? + printf '%s\n' "$output" + if [ "$exit_code" -ne 0 ]; then + if printf '%s' "$output" | grep -q "upgrade your subscription"; then + echo "Blackfire profiling reached the repository quota limit; treating this as a known non-fatal condition." + exit 0 + fi + exit "$exit_code" + fi diff --git a/examples/cakephp-mysql.yml b/examples/cakephp-mysql.yml new file mode 100644 index 0000000..a505cb1 --- /dev/null +++ b/examples/cakephp-mysql.yml @@ -0,0 +1,142 @@ +# GitHub Action for CakePHP with MySQL and Redis +# Tested with https://github.com/cakephp/app +name: Testing CakePHP with MySQL +on: [push, pull_request] +jobs: + tests: + strategy: + matrix: + php-versions: ['8.4', '8.5'] + # The latest cakephp/app release resolves dev dependencies that require PHP 8.4+. + runs-on: ubuntu-latest + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:latest + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: cakephp + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + # You can also use ext-apcu or ext-memcached instead of ext-redis + # Install memcached if using ext-memcached + extensions: mbstring, intl, redis, apcu, pdo_mysql + coverage: pcov + + # Local MySQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start mysql service + # run: sudo systemctl start mysql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + # Add a step to run migrations if required + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text + env: + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + DATABASE_URL: "mysql://root:password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/cakephp?init[]=SET sql_mode = \"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\"" + DATABASE_TEST_URL: "mysql://root:password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/cakephp?init[]=SET sql_mode = \"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\"" + + coding-standard: + name: Coding Standard + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: PHP CodeSniffer + run: composer cs-check + + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl + tools: phpstan + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + - name: Static Analysis using PHPStan + run: phpstan analyse --no-progress src/ diff --git a/examples/cakephp-postgres.yml b/examples/cakephp-postgres.yml new file mode 100644 index 0000000..18de034 --- /dev/null +++ b/examples/cakephp-postgres.yml @@ -0,0 +1,143 @@ +# GitHub Action for CakePHP with PostgreSQL and Redis +# Tested with https://github.com/cakephp/app +name: Testing CakePHP with PostgreSQL +on: [push, pull_request] +jobs: + tests: + strategy: + fail-fast: false + matrix: + php-versions: ['8.4', '8.5'] + # The latest cakephp/app release resolves dev dependencies that require PHP 8.4+. + runs-on: ubuntu-latest + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + # You can also use ext-apcu or ext-memcached instead of ext-redis + # Install memcached if using ext-memcached + extensions: mbstring, intl, redis, apcu, pdo_pgsql + coverage: pcov + + # Local PostgreSQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start postgresql service + # run: sudo systemctl start postgresql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + # Add a step to run migrations if required + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text + env: + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + DATABASE_URL: postgres://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/postgres?encoding=UTF8 + DATABASE_TEST_URL: postgres://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/postgres?encoding=UTF8 + + coding-standard: + name: Coding Standard + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl, apcu + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: PHP CodeSniffer + run: composer cs-check + + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl, apcu + tools: phpstan + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + - name: Static Analysis using PHPStan + run: phpstan analyse --no-progress src/ diff --git a/examples/cakephp.yml b/examples/cakephp.yml new file mode 100644 index 0000000..15026b7 --- /dev/null +++ b/examples/cakephp.yml @@ -0,0 +1,115 @@ +# GitHub Action for CakePHP +# Tested with https://github.com/cakephp/app +name: Testing CakePHP +on: [push, pull_request] +jobs: + tests: + strategy: + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.4', '8.5'] + # The latest cakephp/app release resolves dev dependencies that require PHP 8.4+. + runs-on: ${{ matrix.operating-system }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, intl, pdo_sqlite, pdo_mysql + coverage: pcov + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text + + coding-standard: + name: Coding Standard + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: PHP CodeSniffer + run: composer cs-check + + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, intl + tools: phpstan + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer run-script post-install-cmd --no-interaction + + - name: Static Analysis using PHPStan + run: phpstan analyse --no-progress src/ diff --git a/examples/codeigniter.yml b/examples/codeigniter.yml new file mode 100644 index 0000000..3fb333c --- /dev/null +++ b/examples/codeigniter.yml @@ -0,0 +1,41 @@ +# GitHub Action for CodeIgniter +name: Testing CodeIgniter +on: [push, pull_request] +jobs: + build: + strategy: + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + runs-on: ${{ matrix.operating-system }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, intl, curl, dom, sqlite3, pdo_sqlite + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text diff --git a/examples/drupal.yml b/examples/drupal.yml new file mode 100644 index 0000000..0ecd649 --- /dev/null +++ b/examples/drupal.yml @@ -0,0 +1,59 @@ +# GitHub Action for Drupal 11 composer-managed projects +# Requires drupal/core-dev in require-dev for vendor/bin/phpunit +name: Testing Drupal +on: [push, pull_request] +jobs: + drupal: + name: Drupal (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + SIMPLETEST_BASE_URL: http://127.0.0.1:8080 + SIMPLETEST_DB: sqlite://localhost/sites/default/files/.ht.sqlite + BROWSERTEST_OUTPUT_DIRECTORY: /tmp/browser_output + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: apcu, ctype, curl, dom, gd, iconv, intl, mbstring, pdo_sqlite, simplexml, xml, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: | + if [ "${{ matrix.php-versions }}" = "8.3" ]; then + composer require --dev drupal/core-dev:11.2.10 doctrine/instantiator:^2.0.0 --no-interaction --no-update + composer update drupal/core-dev doctrine/instantiator --with-all-dependencies --no-interaction --no-progress --prefer-dist --optimize-autoloader + else + composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader + fi + + - name: Prepare Drupal test directories + run: mkdir -p web/sites/default/files "$BROWSERTEST_OUTPUT_DIRECTORY" + + - name: Start Drupal web server + run: php -S 127.0.0.1:8080 -t web >/tmp/php-server.log 2>&1 & + + - name: Test with phpunit + # Adjust the test path to match your custom modules or themes. + run: vendor/bin/phpunit -c web/core web/modules/custom diff --git a/examples/laminas-mvc.yml b/examples/laminas-mvc.yml new file mode 100644 index 0000000..48d4d08 --- /dev/null +++ b/examples/laminas-mvc.yml @@ -0,0 +1,40 @@ +# GitHub Action for Laminas framework MVC projects +name: Testing Laminas MVC +on: [push, pull_request] +jobs: + build: + strategy: + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.1', '8.2', '8.3'] + runs-on: ${{ matrix.operating-system }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text diff --git a/examples/laravel-mysql.yml b/examples/laravel-mysql.yml new file mode 100644 index 0000000..6efc444 --- /dev/null +++ b/examples/laravel-mysql.yml @@ -0,0 +1,91 @@ +# GitHub Action for Laravel with MySQL and Redis +name: Testing Laravel with MySQL +on: [push, pull_request] +jobs: + laravel: + name: Laravel (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + DB_CONNECTION: mysql + DB_HOST: 127.0.0.1 + DB_DATABASE: laravel + DB_USERNAME: root + DB_PASSWORD: password + BROADCAST_CONNECTION: log + CACHE_STORE: redis + QUEUE_CONNECTION: redis + SESSION_DRIVER: redis + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:latest + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: laravel + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, mysql + coverage: xdebug + + # Local MySQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start mysql service + # run: sudo systemctl start mysql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare the application + run: | + php -r "file_exists('.env') || copy('.env.example', '.env');" + php artisan key:generate + + - name: Clear Config + run: php artisan config:clear + + - name: Run Migration + run: php artisan migrate -v + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} diff --git a/examples/laravel-postgres.yml b/examples/laravel-postgres.yml new file mode 100644 index 0000000..db43c29 --- /dev/null +++ b/examples/laravel-postgres.yml @@ -0,0 +1,91 @@ +# GitHub Action for Laravel with PostgreSQL and Redis +name: Testing Laravel with PostgreSQL +on: [push, pull_request] +jobs: + laravel: + name: Laravel (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + BROADCAST_DRIVER: log + CACHE_DRIVER: redis + QUEUE_CONNECTION: redis + SESSION_DRIVER: redis + DB_CONNECTION: pgsql + DB_HOST: 127.0.0.1 + DB_PASSWORD: postgres + DB_USERNAME: postgres + DB_DATABASE: postgres + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, pgsql + coverage: xdebug + + # Local PostgreSQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start postgresql service + # run: sudo systemctl start postgresql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare the application + run: | + php -r "file_exists('.env') || copy('.env.example', '.env');" + php artisan key:generate + + - name: Clear Config + run: php artisan config:clear + + - name: Run Migration + run: php artisan migrate -v + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} diff --git a/examples/laravel.yml b/examples/laravel.yml new file mode 100644 index 0000000..599b9bf --- /dev/null +++ b/examples/laravel.yml @@ -0,0 +1,51 @@ +# GitHub Action for Laravel +name: Testing Laravel +on: [push, pull_request] +jobs: + laravel: + name: Laravel (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}) + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare the application + run: | + php -r "file_exists('.env') || copy('.env.example', '.env');" + php artisan key:generate + + - name: Clear Config + run: php artisan config:clear + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text diff --git a/examples/lumen-mysql.yml b/examples/lumen-mysql.yml new file mode 100644 index 0000000..2815833 --- /dev/null +++ b/examples/lumen-mysql.yml @@ -0,0 +1,89 @@ +# GitHub Action for Lumen with MySQL and Redis +name: Testing Lumen with MySQL +on: [push, pull_request] +jobs: + lumen: + name: Lumen (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + DB_DATABASE: lumen + DB_USERNAME: root + DB_PASSWORD: password + BROADCAST_DRIVER: log + CACHE_DRIVER: redis + QUEUE_CONNECTION: redis + SESSION_DRIVER: redis + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:latest + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: lumen + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, mysql + coverage: xdebug + + # Local MySQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start mysql service + # run: sudo systemctl start mysql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer require predis/predis illuminate/redis + + - name: Prepare the application + run: php -r "file_exists('.env') || copy('.env.example', '.env');" + + - name: Register Redis as service provider + run: sed -i '$i\$app->register(Illuminate\\Redis\\RedisServiceProvider::class);' bootstrap/app.php + + - name: Run Migration + run: php artisan migrate -v + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text --coverage-filter app + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} diff --git a/examples/lumen-postgres.yml b/examples/lumen-postgres.yml new file mode 100644 index 0000000..d8976ce --- /dev/null +++ b/examples/lumen-postgres.yml @@ -0,0 +1,91 @@ +# GitHub Action for Lumen with PostgreSQL and Redis +name: Testing Lumen with PostgreSQL +on: [push, pull_request] +jobs: + laravel: + name: Lumen (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + BROADCAST_DRIVER: log + CACHE_DRIVER: redis + QUEUE_CONNECTION: redis + SESSION_DRIVER: redis + DB_CONNECTION: pgsql + DB_HOST: 127.0.0.1 + DB_PASSWORD: postgres + DB_USERNAME: postgres + DB_DATABASE: postgres + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + + redis: + image: redis + ports: + - 6379/tcp + options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, pgsql + coverage: none + + # Local PostgreSQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start postgresql service + # run: sudo systemctl start postgresql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + composer require predis/predis illuminate/redis + + - name: Prepare the application + run: php -r "file_exists('.env') || copy('.env.example', '.env');" + + - name: Register Redis as service provider + run: sed -i '$i\$app->register(Illuminate\\Redis\\RedisServiceProvider::class);' bootstrap/app.php + + - name: Run Migration + run: php artisan migrate -v + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} + + - name: Test with phpunit + run: vendor/bin/phpunit + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + REDIS_PORT: ${{ job.services.redis.ports['6379'] }} diff --git a/examples/lumen.yml b/examples/lumen.yml new file mode 100644 index 0000000..5650310 --- /dev/null +++ b/examples/lumen.yml @@ -0,0 +1,46 @@ +# GitHub Action for Lumen +name: Unit Testing Lumen +on: [push, pull_request] +jobs: + lumen: + name: Lumen (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}) + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, mysql + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare the application + run: php -r "file_exists('.env') || copy('.env.example', '.env');" + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text --coverage-filter app diff --git a/examples/phalcon-mysql.yml b/examples/phalcon-mysql.yml new file mode 100644 index 0000000..9cc0cfb --- /dev/null +++ b/examples/phalcon-mysql.yml @@ -0,0 +1,85 @@ +# GitHub Action for Phalcon with MySQL +## Notes +## Make sure you have .env.example or .env file in your project +## and you have loaded Dotenv (https://github.com/vlucas/phpdotenv) +name: Testing Phalcon with MySQL +on: [push, pull_request] +jobs: + phalcon: + name: Phalcon (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + DB_ADAPTER: mysql + DB_HOST: 127.0.0.1 + DB_NAME: vokuro + DB_USERNAME: root + DB_PASSWORD: password + CODECEPTION_URL: 127.0.0.1 + CODECEPTION_PORT: 8888 + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:5.7 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: vokuro + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['7.2', '7.3', '7.4'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + # Use phalcon4 for the latest compatible Vokuro sample release. + extensions: mbstring, dom, zip, phalcon4, mysql + coverage: xdebug + + # Local MySQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start mysql service + # run: sudo systemctl start mysql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare the application + run: php -r "file_exists('.env') || copy('.env.example', '.env');" + + - name: Run Migration + run: | + vendor/bin/phinx migrate + vendor/bin/phinx seed:run + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + + - name: Run Tests + run: | + (cd public && nohup php -S $CODECEPTION_URL:$CODECEPTION_PORT > phalcon.log 2>&1 &) + vendor/bin/codecept build + vendor/bin/codecept run + env: + DB_PORT: ${{ job.services.mysql.ports['3306'] }} diff --git a/examples/phalcon-postgres.yml b/examples/phalcon-postgres.yml new file mode 100644 index 0000000..06a2285 --- /dev/null +++ b/examples/phalcon-postgres.yml @@ -0,0 +1,78 @@ +# GitHub Action for Phalcon with PostgreSQL +## Notes +## Make sure you have .env.example or .env file in your project +## and you have loaded Dotenv (https://github.com/vlucas/phpdotenv) +name: Testing Phalcon with PostgreSQL +on: [push, pull_request] +jobs: + phalcon: + name: Phalcon (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + DB_ADAPTER: pgsql + DB_HOST: 127.0.0.1 + DB_NAME: vokuro + DB_USERNAME: postgres + DB_PASSWORD: postgres + CODECEPTION_URL: 127.0.0.1 + CODECEPTION_PORT: 8888 + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: vokuro + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + strategy: + fail-fast: false + matrix: + php-versions: ['7.2', '7.3', '7.4'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, zip, phalcon4, pgsql + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader --no-security-blocking + + - name: Prepare the application + run: | + php -r "file_exists('.env') || copy('.env.example', '.env');" + mkdir -p var/cache/acl var/cache/metaData var/cache/session var/cache/volt var/logs + chmod -R 777 var/cache var/logs + + - name: Run Migration + run: | + vendor/bin/phinx migrate + vendor/bin/phinx seed:run + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + + - name: Run Tests + run: | + (cd public && nohup php -S $CODECEPTION_URL:$CODECEPTION_PORT > vokuro.log 2>&1 &) + vendor/bin/codecept build + vendor/bin/codecept run + env: + DB_PORT: ${{ job.services.postgres.ports['5432'] }} diff --git a/examples/sage.yml b/examples/sage.yml new file mode 100644 index 0000000..36d3e76 --- /dev/null +++ b/examples/sage.yml @@ -0,0 +1,62 @@ +# GitHub Action for roots/sage +name: Testing Sage +on: [push, pull_request] +jobs: + sage: + name: Sage (PHP ${{ matrix.php-versions }} & Node ${{ matrix.node-versions }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + node-versions: ['20'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: ${{ matrix.node-versions }} + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + + - name: Check node versions + run: node -v + + - name: Get yarn cache + id: yarn-cache + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v5 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: ${{ runner.os }}-yarn- + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install yarn dependencies + run: yarn install --frozen-lockfile --non-interactive + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Yarn build + run: yarn build diff --git a/examples/slim-framework.yml b/examples/slim-framework.yml new file mode 100644 index 0000000..9fa433f --- /dev/null +++ b/examples/slim-framework.yml @@ -0,0 +1,41 @@ +# GitHub Action for Slim Framework +name: Testing Slim Framework +on: [push, pull_request] +jobs: + build: + strategy: + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.3', '8.4', '8.5'] + runs-on: ${{ matrix.operating-system }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, simplexml, dom + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text diff --git a/examples/symfony-mysql.yml b/examples/symfony-mysql.yml new file mode 100644 index 0000000..3d6eb78 --- /dev/null +++ b/examples/symfony-mysql.yml @@ -0,0 +1,70 @@ +# GitHub Action for Symfony with MySQL +name: Testing Symfony with MySQL +on: [push, pull_request] +jobs: + symfony: + name: Symfony (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + APP_ENV: test + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:8.4 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: symfony + MYSQL_DATABASE: symfony + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.4', '8.5', '8.6'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql + coverage: xdebug + + # Local MySQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start mysql service + # run: sudo systemctl start mysql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare database + run: | + php bin/console doctrine:database:create --if-not-exists --no-interaction + php bin/console doctrine:schema:create --no-interaction + php bin/console doctrine:fixtures:load --no-interaction + env: + DATABASE_URL: mysql://root:symfony@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/symfony?serverVersion=8.4&charset=utf8mb4 + + - name: Run tests + run: php bin/phpunit --coverage-text + env: + DATABASE_URL: mysql://root:symfony@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/symfony?serverVersion=8.4&charset=utf8mb4 diff --git a/examples/symfony-postgres.yml b/examples/symfony-postgres.yml new file mode 100644 index 0000000..c69cd44 --- /dev/null +++ b/examples/symfony-postgres.yml @@ -0,0 +1,70 @@ +# GitHub Action for Symfony with PostgreSQL +name: Testing Symfony with PostgreSQL +on: [push, pull_request] +jobs: + symfony: + name: Symfony (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + APP_ENV: test + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.4', '8.5', '8.6'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, xml, ctype, iconv, intl, pdo_pgsql, pgsql + coverage: xdebug + + # Local PostgreSQL service in GitHub hosted environments is disabled by default. + # If you are using it instead of service containers, make sure you start it. + # - name: Start postgresql service + # run: sudo systemctl start postgresql.service + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Prepare database + run: | + php bin/console doctrine:database:create --if-not-exists --no-interaction + php bin/console doctrine:schema:create --no-interaction + php bin/console doctrine:fixtures:load --no-interaction + env: + DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports[5432] }}/postgres?serverVersion=16.0.0&charset=utf8 + + - name: Run tests + run: php bin/phpunit --coverage-text + env: + DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports[5432] }}/postgres?serverVersion=16.0.0&charset=utf8 diff --git a/examples/symfony.yml b/examples/symfony.yml new file mode 100644 index 0000000..277ddcc --- /dev/null +++ b/examples/symfony.yml @@ -0,0 +1,43 @@ +# GitHub Action for Symfony +name: Testing Symfony +on: [push, pull_request] +jobs: + symfony: + name: Symfony (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}) + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest, macos-latest] + php-versions: ['8.4', '8.5', '8.6'] + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, zip + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run tests + run: ./bin/phpunit --coverage-text diff --git a/examples/wordpress.yml b/examples/wordpress.yml new file mode 100644 index 0000000..706f204 --- /dev/null +++ b/examples/wordpress.yml @@ -0,0 +1,68 @@ +# GitHub Action for WordPress plugins +# Tested with files scaffolded by wp scaffold plugin-tests --ci=github +# Requires phpunit/phpunit and yoast/phpunit-polyfills in require-dev for vendor/bin/phpunit +name: Testing WordPress +on: [push, pull_request] +jobs: + wordpress: + name: WordPress (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['8.3', '8.4', '8.5'] + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:latest + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: wordpress_test + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, xml, zip, intl, mysql + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y subversion default-mysql-client + + - name: Install Composer dependencies + run: | + if [ "${{ matrix.php-versions }}" = "8.3" ]; then + composer require --dev doctrine/instantiator:^2.0.0 --no-interaction --no-update + composer update doctrine/instantiator --with-all-dependencies --no-interaction --no-progress --prefer-dist --optimize-autoloader + else + composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader + fi + + - name: Install WordPress test environment + run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }} latest true + + - name: Test with phpunit + run: vendor/bin/phpunit diff --git a/examples/yii3-mysql.yml b/examples/yii3-mysql.yml new file mode 100644 index 0000000..466ac40 --- /dev/null +++ b/examples/yii3-mysql.yml @@ -0,0 +1,78 @@ +# GitHub Action for Yii3 web application with MySQL +# Tested with https://github.com/yiisoft/app +name: Testing Yii3 with MySQL +on: [push, pull_request] +jobs: + yii: + name: Yii3 (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + APP_C3: true + APP_ENV: test + APP_DEBUG: false + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + mysql: + image: mysql:8.4 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: app + ports: + - 3306/tcp + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.4', '8.5'] + # The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+. + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: fileinfo, intl, pdo_mysql + ini-values: date.timezone='UTC', register_argc_argv=On + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run migrations + run: php yii migrate:up --no-interaction + env: + DB_HOST: 127.0.0.1 + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + DB_NAME: app + DB_USERNAME: root + DB_PASSWORD: password + + - name: Run codeception build + run: vendor/bin/codecept build + + - name: Run tests with Codeception + run: vendor/bin/codecept run + env: + DB_HOST: 127.0.0.1 + DB_PORT: ${{ job.services.mysql.ports['3306'] }} + DB_NAME: app + DB_USERNAME: root + DB_PASSWORD: password diff --git a/examples/yii3-postgres.yml b/examples/yii3-postgres.yml new file mode 100644 index 0000000..1fbd839 --- /dev/null +++ b/examples/yii3-postgres.yml @@ -0,0 +1,78 @@ +# GitHub Action for Yii3 web application with PostgreSQL +# Tested with https://github.com/yiisoft/app +name: Testing Yii3 with PostgreSQL +on: [push, pull_request] +jobs: + yii: + name: Yii3 (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + env: + APP_C3: true + APP_ENV: test + APP_DEBUG: false + + # Docs: https://docs.github.com/en/actions/using-containerized-services + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: app + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + strategy: + fail-fast: false + matrix: + php-versions: ['8.4', '8.5'] + # The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+. + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: fileinfo, intl, pdo_pgsql + ini-values: date.timezone='UTC', register_argc_argv=On + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run migrations + run: php yii migrate:up --no-interaction + env: + DB_HOST: 127.0.0.1 + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + DB_NAME: app + DB_USERNAME: postgres + DB_PASSWORD: postgres + + - name: Run codeception build + run: vendor/bin/codecept build + + - name: Run tests with Codeception + run: vendor/bin/codecept run + env: + DB_HOST: 127.0.0.1 + DB_PORT: ${{ job.services.postgres.ports['5432'] }} + DB_NAME: app + DB_USERNAME: postgres + DB_PASSWORD: postgres diff --git a/examples/yii3.yml b/examples/yii3.yml new file mode 100644 index 0000000..f29fdac --- /dev/null +++ b/examples/yii3.yml @@ -0,0 +1,53 @@ +# GitHub Action for Yii3 web application +# Tested with https://github.com/yiisoft/app +name: Testing Yii3 +on: [push, pull_request] +jobs: + yii: + name: Yii3 (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}) + runs-on: ${{ matrix.operating-system }} + env: + APP_C3: true + APP_ENV: test + APP_DEBUG: false + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest] + php-versions: ['8.4', '8.5'] + # The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+. + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Docs: https://github.com/step-security/setup-php + - name: Setup PHP + uses: step-security/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: fileinfo, intl + ini-values: date.timezone='UTC', register_argc_argv=On + coverage: none + + - name: Get composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + # Use composer.json for key, if composer.lock is not committed. + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run codeception build + run: vendor/bin/codecept build + + - name: Run tests with Codeception + run: vendor/bin/codecept run diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..f670531 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,12 @@ +module.exports = { + clearMocks: true, + moduleFileExtensions: ['js', 'ts'], + testEnvironment: 'node', + testMatch: ['**/*.test.ts'], + testRunner: 'jest-circus/runner', + transform: { + '^.+\\.ts$': 'ts-jest' + }, + verbose: true, + collectCoverage: true +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..beb86a1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6410 @@ +{ + "name": "setup-php", + "version": "2.37.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "setup-php", + "version": "2.37.0", + "license": "MIT", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/exec": "^2.0.0", + "axios": "^1.16.0", + "compare-versions": "^6.1.1" + }, + "devDependencies": { + "@eslint/compat": "^2.0.3", + "@eslint/js": "^10.0.1", + "@types/jest": "^30.0.0", + "@types/node": "^25.5.0", + "@typescript-eslint/eslint-plugin": "^8.57.2", + "@typescript-eslint/parser": "^8.57.2", + "@vercel/ncc": "^0.38.4", + "eslint": "^10.1.0", + "eslint-config-prettier": "^10.1.8", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import-x": "^4.16.2", + "eslint-plugin-jest": "^29.15.1", + "eslint-plugin-prettier": "^5.5.5", + "globals": "^17.4.0", + "jest": "^30.3.0", + "jest-circus": "^30.3.0", + "nock": "^14.0.11", + "prettier": "^3.8.1", + "ts-jest": "^29.4.6", + "typescript": "^5.9.3" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "license": "MIT", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/core/node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "license": "MIT", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/core/node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "license": "MIT" + }, + "node_modules/@actions/exec": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-2.0.0.tgz", + "integrity": "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==", + "license": "MIT", + "dependencies": { + "@actions/io": "^2.0.0" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz", + "integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@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/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@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-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@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-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.3.tgz", + "integrity": "sha512-SjIJhGigp8hmd1YGIBwh7Ovri7Kisl42GYFjrOyHhtfYGGoLW6teYi/5p8W50KSsawUPpuLOSmsq1bD0NGQLBw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "peerDependencies": { + "eslint": "^8.40 || 9 || 10" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.3", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", + "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", + "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", + "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.3.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.3.0", + "jest-config": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-resolve-dependencies": "30.3.0", + "jest-runner": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "jest-watcher": "30.3.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", + "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "30.3.0", + "jest-snapshot": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", + "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@sinonjs/fake-timers": "^15.0.0", + "@types/node": "*", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", + "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/types": "30.3.0", + "jest-mock": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", + "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", + "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", + "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.3.0", + "@jest/types": "30.3.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", + "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", + "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.41.3", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz", + "integrity": "sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@package-json/types": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@package-json/types/-/types-0.0.12.tgz", + "integrity": "sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", + "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", + "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/type-utils": "8.57.2", + "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.57.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", + "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", + "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.57.2", + "@typescript-eslint/types": "^8.57.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", + "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", + "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", + "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/utils": "8.57.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", + "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", + "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", + "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", + "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vercel/ncc": { + "version": "0.38.4", + "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.4.tgz", + "integrity": "sha512-8LwjnlP39s08C08J5NstzriPvW1SP8Zfpp1BvC2sI35kPeZnHfxVkCwu4/+Wodgnd60UtT1n8K8zw+Mp7J9JmQ==", + "dev": true, + "license": "MIT", + "bin": { + "ncc": "dist/ncc/cli.js" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz", + "integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/babel-jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", + "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.3.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-plugin-istanbul/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "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/babel-plugin-istanbul/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", + "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", + "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", + "integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.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==", + "dev": true, + "license": "MIT" + }, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001781", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comment-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", + "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz", + "integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz", + "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.3", + "@eslint/config-helpers": "^0.5.3", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "dev": true, + "license": "ISC", + "dependencies": { + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", + "is-bun-module": "^2.0.0", + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^16.17.0 || >=18.6.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-import-x": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.2.tgz", + "integrity": "sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@package-json/types": "^0.0.12", + "@typescript-eslint/types": "^8.56.0", + "comment-parser": "^1.4.1", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.9", + "is-glob": "^4.0.3", + "minimatch": "^9.0.3 || ^10.1.2", + "semver": "^7.7.2", + "stable-hash-x": "^0.2.0", + "unrs-resolver": "^1.9.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-import-x" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "eslint-import-resolver-node": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/utils": { + "optional": true + }, + "eslint-import-resolver-node": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest": { + "version": "29.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.1.tgz", + "integrity": "sha512-6BjyErCQauz3zfJvzLw/kAez2lf4LEpbHLvWBfEcG4EI0ZiRSwjoH2uZulMouU8kRkBH+S0rhqn11IhTvxKgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.0.0" + }, + "engines": { + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "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==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.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==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "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-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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.", + "dev": true, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", + "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.3.0", + "@jest/types": "30.3.0", + "import-local": "^3.2.0", + "jest-cli": "30.3.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", + "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.3.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", + "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "p-limit": "^3.1.0", + "pretty-format": "30.3.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", + "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", + "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.3.0", + "@jest/types": "30.3.0", + "babel-jest": "30.3.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.3.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-runner": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "parse-json": "^5.2.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", + "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "jest-util": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", + "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", + "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "picomatch": "^4.0.3", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", + "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", + "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", + "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", + "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.3.0", + "@jest/environment": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-leak-detector": "30.3.0", + "jest-message-util": "30.3.0", + "jest-resolve": "30.3.0", + "jest-runtime": "30.3.0", + "jest-util": "30.3.0", + "jest-watcher": "30.3.0", + "jest-worker": "30.3.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", + "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/globals": "30.3.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-snapshot": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", + "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "pretty-format": "30.3.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", + "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.3.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", + "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.3.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "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/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/nock": { + "version": "14.0.11", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.11.tgz", + "integrity": "sha512-u5xUnYE+UOOBA6SpELJheMCtj2Laqx15Vl70QxKo43Wz/6nMHXS7PrEioXLjXAwhmawdEMNImwKCcPhBJWbKVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mswjs/interceptors": "^0.41.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">=18.20.0 <20 || >=20.12.1" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "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==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "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==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1b43596 --- /dev/null +++ b/package.json @@ -0,0 +1,63 @@ +{ + "name": "setup-php", + "version": "2.37.0", + "private": false, + "description": "Setup PHP for use with GitHub Actions", + "main": "lib/install.js", + "types": "lib/install.d.ts", + "directories": { + "lib": "lib", + "test": "__tests__", + "src": "src" + }, + "files": [ + "lib", + "src" + ], + "scripts": { + "build": "tsc && ncc build -m -o dist", + "lint": "eslint **/src/*.ts **/__tests__/*.ts --cache --fix", + "format": "prettier --write **/src/*.ts **/__tests__/*.ts && git add -f __tests__/ ", + "format-check": "prettier --check **/src/*.ts **/__tests__/*.ts", + "test": "jest" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/step-security/setup-php.git" + }, + "keywords": [ + "actions", + "php", + "setup" + ], + "author": "step-security", + "license": "MIT", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/exec": "^2.0.0", + "axios": "^1.16.0", + "compare-versions": "^6.1.1" + }, + "devDependencies": { + "@eslint/compat": "^2.0.3", + "@eslint/js": "^10.0.1", + "@types/jest": "^30.0.0", + "@types/node": "^25.5.0", + "@typescript-eslint/eslint-plugin": "^8.57.2", + "@typescript-eslint/parser": "^8.57.2", + "@vercel/ncc": "^0.38.4", + "eslint": "^10.1.0", + "eslint-config-prettier": "^10.1.8", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import-x": "^4.16.2", + "eslint-plugin-jest": "^29.15.1", + "eslint-plugin-prettier": "^5.5.5", + "globals": "^17.4.0", + "jest": "^30.3.0", + "jest-circus": "^30.3.0", + "nock": "^14.0.11", + "prettier": "^3.8.1", + "ts-jest": "^29.4.6", + "typescript": "^5.9.3" + } +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..07f8976 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,82 @@ +import * as utils from './utils'; + +/** + * Add script to set custom ini values for unix + * + * @param ini_values_csv + */ +export async function addINIValuesUnix( + ini_values_csv: string +): Promise { + const ini_values: Array = await utils.CSVArray(ini_values_csv); + let script = ''; + await utils.asyncForEach(ini_values, async function (line: string) { + script += + '\n' + (await utils.addLog('$tick', line, 'Added to php.ini', 'linux')); + }); + return ( + 'echo "' + + ini_values.join('\n') + + '" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1' + + script + ); +} + +/** + * Add script to set custom ini values for windows + * + * @param ini_values_csv + */ +export async function addINIValuesWindows( + ini_values_csv: string +): Promise { + const ini_values: Array = await utils.CSVArray(ini_values_csv); + let script = '\n'; + await utils.asyncForEach(ini_values, async function (line: string) { + script += + (await utils.addLog('$tick', line, 'Added to php.ini', 'win32')) + '\n'; + }); + return ( + 'Add-Content "$php_dir\\php.ini" "' + ini_values.join('\n') + '"' + script + ); +} + +/** + * Function to add custom ini values + * + * @param ini_values_csv + * @param os + * @param no_step + */ +export async function addINIValues( + ini_values_csv: string, + os: string, + no_step = false +): Promise { + let script = '\n'; + switch (no_step) { + case true: + script += + (await utils.stepLog('Add php.ini values', os)) + + (await utils.suppressOutput(os)) + + '\n'; + break; + case false: + default: + script += (await utils.stepLog('Add php.ini values', os)) + '\n'; + break; + } + switch (os) { + case 'win32': + return script + (await addINIValuesWindows(ini_values_csv)); + case 'darwin': + case 'linux': + return script + (await addINIValuesUnix(ini_values_csv)); + default: + return await utils.log( + 'Platform ' + os + ' is not supported', + os, + 'error' + ); + } +} diff --git a/src/configs/brew_extensions b/src/configs/brew_extensions new file mode 100644 index 0000000..dd1c3f4 --- /dev/null +++ b/src/configs/brew_extensions @@ -0,0 +1,65 @@ +amqp=amqp +apcu=apcu +ast=ast +brotli=brotli +couchbase=couchbase +ds=ds +event=event +excimer=excimer +expect=expect +gearman=gearman +gmagick=gmagick +gnupg=gnupg +grpc=grpc +igbinary=igbinary +imagick=imagick +imap=imap +interbase=interbase +lua=lua +mailparse=mailparse +maxminddb=maxminddb +mcrypt=mcrypt +memcache=memcache +memcached=memcached +mongodb=mongodb +mongodb1=mongodb1 +msgpack=msgpack +newrelic=newrelic +oauth=oauth +opentelemetry=opentelemetry +pcov=pcov +pdo_firebird=pdo_firebird +pdo_sqlsrv=pdo_sqlsrv +pecl_http=http +phalcon3=phalcon +phalcon4=phalcon +phalcon5=phalcon +pinba=pinba +propro=propro +protobuf=protobuf +psr=psr +raphf=raphf +rdkafka=rdkafka +phpredis=redis +redis=redis +seaslog=seaslog +scalar_objects=scalar_objects +snmp=snmp +sqlsrv=sqlsrv +spx=spx +ssh2=ssh2 +swoole=swoole +swow=swow +uopz=uopz +uploadprogress=uploadprogress +uuid=uuid +v8js=v8js +vips=vips +vld=vld +xdebug=xdebug +xdebug2=xdebug +xhprof=xhprof +xlswriter=xlswriter +yaml=yaml +zmq=zmq +zstd=zstd diff --git a/src/configs/composer.env b/src/configs/composer.env new file mode 100644 index 0000000..6335d61 --- /dev/null +++ b/src/configs/composer.env @@ -0,0 +1,3 @@ +COMPOSER_PROCESS_TIMEOUT=0 +COMPOSER_NO_INTERACTION=1 +COMPOSER_NO_AUDIT=1 diff --git a/src/configs/darwin_libs b/src/configs/darwin_libs new file mode 100644 index 0000000..2a66493 --- /dev/null +++ b/src/configs/darwin_libs @@ -0,0 +1,22 @@ +amqp=rabbitmq-c +decimal=mpdecimal +ev=libev +event=libevent +geoip=geoip +gmagick=graphicsmagick +gnupg=gpgme +grpc=grpc protobuf +imagick=imagemagick +memcached=libmemcached libevent +protobuf=protobuf +rdkafka=librdkafka +snappy=snappy +sodium=libsodium +ssh2=libssh2 +uv=libuv +uuid=util-linux +vips=vips +yaz=yaz +yaml=libyaml +zstd=zstd +zmq=zeromq \ No newline at end of file diff --git a/src/configs/ini/jit.ini b/src/configs/ini/jit.ini new file mode 100644 index 0000000..0fe0350 --- /dev/null +++ b/src/configs/ini/jit.ini @@ -0,0 +1,3 @@ +opcache.enable=1 +opcache.jit_buffer_size=256M +opcache.jit=1235 diff --git a/src/configs/ini/jit_aarch64.ini b/src/configs/ini/jit_aarch64.ini new file mode 100644 index 0000000..d083eaf --- /dev/null +++ b/src/configs/ini/jit_aarch64.ini @@ -0,0 +1,3 @@ +opcache.enable=1 +opcache.jit_buffer_size=128M +opcache.jit=1235 diff --git a/src/configs/ini/php.ini b/src/configs/ini/php.ini new file mode 100644 index 0000000..494cfc8 --- /dev/null +++ b/src/configs/ini/php.ini @@ -0,0 +1,2 @@ +date.timezone=UTC +memory_limit=-1 diff --git a/src/configs/ini/xdebug.ini b/src/configs/ini/xdebug.ini new file mode 100644 index 0000000..cea362e --- /dev/null +++ b/src/configs/ini/xdebug.ini @@ -0,0 +1 @@ +xdebug.mode=coverage diff --git a/src/configs/linux_libs b/src/configs/linux_libs new file mode 100644 index 0000000..5d59557 --- /dev/null +++ b/src/configs/linux_libs @@ -0,0 +1,22 @@ +amqp=librabbitmq-dev +decimal=libmpdec-dev +ev=libev-dev +event=libevent-dev +geoip=libgeoip-dev +gmagick=graphicsmagick-libmagick-dev-compat +gnupg=libgpgme-dev +grpc=libgrpc-dev libprotobuf-dev protobuf-compiler +imagick=libmagickwand-dev libmagickcore-dev +memcached=libmemcached-dev libevent-dev +protobuf=libprotobuf-dev protobuf-compiler +rdkafka=librdkafka-dev +snappy=libsnappy-dev +sodium=libsodium-dev +ssh2=libssh2-1-dev +uv=libuv1-dev +uuid=uuid-dev +vips=libvips-dev +yaz=libyaz-dev +yaml=libyaml-dev +zstd=libzstd-dev +zmq=libzmq3-dev \ No newline at end of file diff --git a/src/configs/mod_priority b/src/configs/mod_priority new file mode 100644 index 0000000..8a293ac --- /dev/null +++ b/src/configs/mod_priority @@ -0,0 +1,31 @@ +apc=25 +apcu_bc=25 +apcu-bc=25 +blackfire=30 +couchbase=30 +decimal=30 +ds=30 +event=30 +ev=30 +grpc=30 +http=25 +pecl_http=25 +pecl-http=25 +inotify=30 +libvirt-php=40 +mailparse=25 +maxminddb=30 +memcached=25 +mysqlnd=10 +mysqlnd_ms=30 +opcache=10 +openswoole=25 +pdo=10 +phalcon=35 +protobuf=30 +psr=15 +rdkafka=30 +swoole=25 +vips=30 +xml=15 +zstd=30 diff --git a/src/configs/os_releases.csv b/src/configs/os_releases.csv new file mode 100644 index 0000000..250e128 --- /dev/null +++ b/src/configs/os_releases.csv @@ -0,0 +1,27 @@ +8,jessie +9,stretch +10,buster +11,bullseye +12,bookworm +13,trixie +16.04 LTS,xenial +16.10,yakkety +17.04,zesty +17.10,artful +18.04 LTS,bionic +18.10,cosmic +19.04,disco +19.10,eoan +20.04 LTS,focal +20.10,groovy +21.04,hirsute +21.10,impish +22.04,jammy +23.04,lunar +23.10,mantic +24.04,noble +24.10,oracular +25.05,plucky +25.10,questing +26.04,resolute +26.10,stonking diff --git a/src/configs/php-versions.json b/src/configs/php-versions.json new file mode 100644 index 0000000..0ed946c --- /dev/null +++ b/src/configs/php-versions.json @@ -0,0 +1,10 @@ +{ + "lowest": "8.1", + "highest": "8.5", + "latest": "8.5", + "nightly": "8.6", + "master": "8.6", + "5.x": "5.6", + "7.x": "7.4", + "8.x": "8.5" +} diff --git a/src/configs/php_debug_packages b/src/configs/php_debug_packages new file mode 100644 index 0000000..5475016 --- /dev/null +++ b/src/configs/php_debug_packages @@ -0,0 +1,11 @@ +cgi +cli +curl +fpm +intl +mbstring +mysql +opcache +pgsql +xml +zip diff --git a/src/configs/php_packages b/src/configs/php_packages new file mode 100644 index 0000000..cf581a0 --- /dev/null +++ b/src/configs/php_packages @@ -0,0 +1,12 @@ +cgi +cli +curl +dev +fpm +intl +mbstring +mysql +opcache +pgsql +xml +zip diff --git a/src/configs/pm/php.json b/src/configs/pm/php.json new file mode 100644 index 0000000..1f0ee8b --- /dev/null +++ b/src/configs/pm/php.json @@ -0,0 +1,29 @@ +{ + "problemMatcher": [ + { + "owner": "php_native_error", + "severity": "error", + "pattern": [ + { + "regexp": "^(.*error):\\s+\\s+(.+) in (.+) on line (\\d+)$", + "code": 1, + "message": 2, + "file": 3, + "line": 4 + } + ] + }, { + "owner": "php_native_warning", + "severity": "warning", + "pattern": [ + { + "regexp": "^(.*Warning|.*Deprecated|.*Notice):\\s+\\s+(.+) in (.+) on line (\\d+)$", + "code": 1, + "message": 2, + "file": 3, + "line": 4 + } + ] + } + ] +} diff --git a/src/configs/pm/phpunit.json b/src/configs/pm/phpunit.json new file mode 100644 index 0000000..2cc9dab --- /dev/null +++ b/src/configs/pm/phpunit.json @@ -0,0 +1,24 @@ +{ + "problemMatcher": [ + { + "owner": "phpunit", + "pattern": [ + { + "regexp": "^\\d+\\)\\s.*$" + }, + { + "regexp": "^(.*Failed\\sasserting\\sthat.*)$", + "message": 1 + }, + { + "regexp": "^\\s*$" + }, + { + "regexp": "^(.*):(\\d+)$", + "file": 1, + "line": 2 + } + ] + } + ] +} diff --git a/src/configs/tools.json b/src/configs/tools.json new file mode 100644 index 0000000..a339e2c --- /dev/null +++ b/src/configs/tools.json @@ -0,0 +1,358 @@ +{ + "backward-compatibility-check": { + "type": "composer", + "repository": "roave/backward-compatibility-check", + "scope": "scoped" + }, + "box": { + "type": "phar", + "repository": "box-project/box", + "packagist": "humbug/box", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "--version" + }, + "churn": { + "type": "phar", + "repository": "bmitch/churn-php", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "composer-dependency-analyser": { + "type": "composer", + "repository": "shipmonk/composer-dependency-analyser", + "scope": "scoped" + }, + "composer-unused": { + "type": "phar", + "repository": "composer-unused/composer-unused", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "composer-normalize": { + "type": "phar", + "repository": "ergebnis/composer-normalize", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "diagnose" + }, + "cs2pr": { + "type": "phar", + "repository": "staabm/annotate-pull-request-from-checkstyle", + "extension": "", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "easy-coding-standard": { + "type": "composer", + "alias": "ecs", + "repository": "symplify/easy-coding-standard", + "scope": "scoped" + }, + "infection": { + "type": "phar", + "repository": "infection/infection", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "name-collision-detector": { + "type": "composer", + "repository": "shipmonk/name-collision-detector", + "scope": "scoped" + }, + "phan": { + "type": "phar", + "repository": "phan/phan", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-v" + }, + "parallel-lint": { + "type": "phar", + "repository": "php-parallel-lint/PHP-Parallel-Lint", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "v", + "version_parameter": "--version" + }, + "php-cs-fixer": { + "type": "phar", + "repository": "PHP-CS-Fixer/PHP-CS-Fixer", + "extension": ".phar", + "domain": "https://github.com", + "fetch_latest": "true", + "version_prefix": "v", + "version_parameter": "-V" + }, + "php-scoper": { + "type": "phar", + "repository": "humbug/php-scoper", + "packagist": "humbug/php-scoper", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpcbf": { + "type": "phar", + "repository": "PHPCSStandards/PHP_CodeSniffer", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpcs": { + "type": "phar", + "repository": "PHPCSStandards/PHP_CodeSniffer", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpDocumentor": { + "type": "phar", + "repository": "phpDocumentor/phpDocumentor", + "extension": ".phar", + "domain": "https://github.com", + "alias": "phpdoc", + "version_prefix": "v", + "version_parameter": "--version" + }, + "phpmd": { + "type": "phar", + "repository": "phpmd/phpmd", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpspec": { + "type": "phar", + "repository": "phpspec/phpspec", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "phpstan": { + "type": "phar", + "repository": "phpstan/phpstan", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "pie": { + "type": "phar", + "repository": "php/pie", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-V" + }, + "pint": { + "type": "phar", + "repository": "laravel/pint", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "v", + "version_parameter": "-V" + }, + "psalm": { + "type": "phar", + "repository": "vimeo/psalm", + "extension": ".phar", + "domain": "https://github.com", + "version_prefix": "", + "version_parameter": "-v" + }, + "behat": { + "type": "composer", + "repository": "behat/behat", + "scope": "scoped" + }, + "codeception": { + "type": "composer", + "repository": "codeception/codeception", + "scope": "scoped" + }, + "automatic-composer-prefetcher": { + "type": "composer", + "alias": "composer-prefetcher", + "repository": "narrowspark/automatic-composer-prefetcher", + "scope": "global" + }, + "composer-require-checker": { + "type": "composer", + "repository": "maglnet/composer-require-checker", + "scope": "scoped" + }, + "flex": { + "type": "composer", + "repository": "symfony/flex", + "scope": "global" + }, + "phinx": { + "type": "composer", + "repository": "robmorgan/phinx", + "scope": "scoped" + }, + "phplint": { + "type": "composer", + "repository": "overtrue/phplint", + "scope": "scoped" + }, + "phpunit-bridge": { + "alias": "simple-phpunit", + "type": "composer", + "repository": "symfony/phpunit-bridge", + "scope": "global" + }, + "phpunit-polyfills": { + "type": "composer", + "repository": "yoast/phpunit-polyfills", + "scope": "global" + }, + "prestissimo": { + "type": "composer", + "repository": "hirak/prestissimo", + "scope": "global" + }, + "vapor-cli": { + "type": "composer", + "alias": "vapor", + "repository": "laravel/vapor-cli", + "scope": "scoped" + }, + "rector": { + "type": "composer", + "repository": "rector/rector", + "scope": "scoped" + }, + "blackfire": { + "type": "custom-package", + "alias": "blackfire-agent" + }, + "grpc_php_plugin": { + "type": "custom-package", + "repository": "grpc/grpc", + "domain": "https://github.com", + "version_prefix": "v" + }, + "mago": { + "type": "custom-package", + "repository": "carthage-software/mago", + "domain": "https://github.com", + "version_prefix": "" + }, + "protoc": { + "type": "custom-package", + "repository": "protocolbuffers/protobuf", + "domain": "https://github.com", + "version_prefix": "v" + }, + "symfony-cli": { + "alias": "symfony", + "type": "custom-package", + "repository": "symfony-cli/symfony-cli", + "domain": "https://github.com", + "version_prefix": "v", + "version_parameter": "-V" + }, + "blackfire-player": { + "type": "custom-function", + "domain": "https://get.blackfire.io", + "function": "blackfire_player", + "version_prefix": "v", + "version_parameter": "-V" + }, + "castor": { + "type": "custom-function", + "domain": "https://github.com", + "repository": "jolicode/castor", + "function": "castor", + "version_prefix": "v", + "version_parameter": "-V" + }, + "composer": { + "type": "custom-function", + "domain": "https://getcomposer.org", + "repository": "composer/composer", + "function": "composer" + }, + "deployer": { + "type": "custom-function", + "domain": "https://deployer.org", + "repository": "deployphp/deployer", + "function": "deployer", + "version_prefix": "v", + "version_parameter": "-V" + }, + "pecl": { + "type": "custom-function", + "function": "pecl" + }, + "phing": { + "type": "custom-function", + "domain": "https://www.phing.info", + "repository": "phingofficial/phing", + "function": "phing", + "extension": ".phar", + "version_prefix": "", + "version_parameter": "-v" + }, + "phive": { + "type": "custom-function", + "repository": "phar-io/phive", + "domain": "https://github.com", + "function": "phive", + "version_prefix": "", + "version_parameter": "status" + }, + "phpcpd": { + "type": "custom-function", + "repository": "sebastianbergmann/phpcpd", + "domain": "https://phar.phpunit.de", + "function": "phpcpd", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpunit": { + "type": "custom-function", + "repository": "sebastianbergmann/phpunit", + "packagist": "phpunit/phpunit", + "domain": "https://phar.phpunit.de", + "function": "phpunit", + "version_prefix": "", + "version_parameter": "--version" + }, + "phpize": { + "type": "custom-function", + "function": "dev_tools", + "alias": "php-config" + }, + "php-config": { + "type": "custom-function", + "function": "dev_tools" + }, + "wp-cli": { + "type": "custom-function", + "function": "wp_cli", + "repository": "wp-cli/wp-cli", + "domain": "https://github.com", + "alias": "wp", + "extension": ".phar", + "version_parameter": "--version", + "version_prefix": "v" + } +} diff --git a/src/configs/tools_schema.json b/src/configs/tools_schema.json new file mode 100644 index 0000000..8254d6a --- /dev/null +++ b/src/configs/tools_schema.json @@ -0,0 +1,136 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/step-security/setup-php/release/src/configs/tools_schema.json", + "type": "object", + "title": "Tools", + "default": {}, + "examples": [ + { + "tool": { + "alias": "tool_alias", + "domain": "https://example.com", + "extension": ".ext", + "fetch_latest": "true", + "function": "function_name", + "repository": "user/tool", + "packagist": "user/tool", + "scope": "global, scoped", + "type": "phar, composer, custom-package or custom-function", + "version_parameter": "--version", + "version_prefix": "v" + } + } + ], + "items": { + "properties": { + "alias": { + "$id": "#/items/properties/alias", + "type": "string", + "title": "The alias schema", + "description": "Alias for a tool.", + "examples": [ + "tool_alias" + ] + }, + "domain": { + "$id": "#/items/properties/domain", + "type": "string", + "title": "The domain schema", + "description": "Domain URL of the tool.", + "examples": [ + "https://example.com" + ] + }, + "extension": { + "$id": "#/items/properties/extension", + "type": "string", + "title": "The extension schema", + "description": "File extension of the tool.", + "examples": [ + ".ext" + ] + }, + "fetch_latest": { + "$id": "#/items/properties/fetch_latest", + "type": "string", + "title": "The fetch_latest schema", + "description": "Fetch the latest version from GitHub releases.", + "enum": [ + "true", + "false" + ] + }, + "function": { + "$id": "#/items/properties/function", + "type": "string", + "title": "The function schema", + "description": "Function name in tools.ts which returns the script to setup the tool.", + "examples": [ + "function_name" + ] + }, + "repository": { + "$id": "#/items/properties/repository", + "type": "string", + "title": "The repository schema", + "description": "GitHub repository of the tool.", + "examples": [ + "user/tool" + ] + }, + "packagist": { + "$id": "#/items/properties/packagist", + "type": "string", + "title": "The repository schema", + "description": "Packagist repository of the tool in case different from repository.", + "examples": [ + "user/tool" + ] + }, + "scope": { + "$id": "#/items/properties/scope", + "type": "string", + "title": "The scope schema", + "description": "Scope of tool installation: global or scoped", + "enum": [ + "global", + "scoped" + ] + }, + "type": { + "$id": "#/items/properties/type", + "type": "string", + "title": "The type schema", + "description": "Type of tool: phar, composer, custom-package or custom-function.", + "enum": [ + "phar", + "composer", + "custom-package", + "custom-function" + ] + }, + "version_parameter": { + "$id": "#/items/properties/version_parameter", + "type": "string", + "title": "The version_parameter schema", + "description": "Parameter to get the tool version.", + "examples": [ + "--version" + ] + }, + "version_prefix": { + "$id": "#/items/properties/version_prefix", + "type": "string", + "title": "The version_prefix schema", + "description": "Prefix of the version in the download URL.", + "examples": [ + "v" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": true + } +} \ No newline at end of file diff --git a/src/configs/windows_extensions b/src/configs/windows_extensions new file mode 100644 index 0000000..1a8c801 --- /dev/null +++ b/src/configs/windows_extensions @@ -0,0 +1,2 @@ +xdebug +pcov \ No newline at end of file diff --git a/src/core.ts b/src/core.ts new file mode 100644 index 0000000..e93fde7 --- /dev/null +++ b/src/core.ts @@ -0,0 +1,120 @@ +import {EOL} from 'os'; + +/** + * Commands + * + * Command Format: + * ::name key=value,key=value::message + * + * @see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions + */ + +interface CommandProperties { + [key: string]: string; +} + +/** + * Sanitizes the message for use in a workflow command. + * @param message + */ +function toCommandValue(message: string | Error): string { + if (message instanceof Error) { + return message.toString(); + } + return message; +} + +/** + * Escapes data for safe use in workflow command messages. + * @param s + */ +function escapeData(s: string | Error): string { + return toCommandValue(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A'); +} + +/** + * Escapes property values for safe use in workflow command properties. + * @param s + */ +function escapeProperty(s: string): string { + return s + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A') + .replace(/:/g, '%3A') + .replace(/,/g, '%2C'); +} + +/** + * Issues a command to the GitHub Actions runner. + * + * @param command - The command name to issue + * @param properties - Additional properties for the command (key-value pairs) + * @param message - The message to include with the command + */ +export function issueCommand( + command: string, + properties: CommandProperties, + message: string | Error +): void { + let cmdStr = `::${command}`; + + if (properties && Object.keys(properties).length > 0) { + cmdStr += ' '; + const props = Object.entries(properties) + .filter(([, val]) => val) + .map(([key, val]) => `${key}=${escapeProperty(val)}`) + .join(','); + cmdStr += props; + } + + cmdStr += `::${escapeData(message)}`; + process.stdout.write(cmdStr + EOL); +} + +/** + * Writes info to stdout. + * @param message - info message + */ +export function info(message: string): void { + process.stdout.write(message + EOL); +} + +/** + * Adds an error issue. + * @param message - error issue message + */ +export function error(message: string | Error): void { + issueCommand('error', {}, message); +} + +/** + * Sets the action status to failed. + * When the action exits it will be with an exit code of 1. + * @param message - add error issue message + */ +export function setFailed(message: string | Error): void { + process.exitCode = 1; + error(message); +} + +/** + * Gets the value of an input. + * The value is trimmed. + * Returns an empty string if the value is not defined. + * + * @param name - name of the input to get + * @param required - whether the input is required + * @returns string + */ +export function getInput(name: string, required = false): string { + const val: string = + process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; + if (required && !val) { + throw new Error(`Input required and not supplied: ${name}`); + } + return val.trim(); +} diff --git a/src/coverage.ts b/src/coverage.ts new file mode 100644 index 0000000..0b92b86 --- /dev/null +++ b/src/coverage.ts @@ -0,0 +1,149 @@ +import * as utils from './utils'; +import * as extensions from './extensions'; +import * as config from './config'; + +export async function checkXdebugError( + extension: string, + version: string +): Promise { + if ( + (/^5\.[3-6]$|^7\.[0-1]$/.test(version) && extension == 'xdebug3') || + (/^8\.[0-9]$/.test(version) && extension == 'xdebug2') + ) { + return extension + ' is not supported on PHP ' + version; + } + return ''; +} + +/** + * Function to set up Xdebug + * + * @param extension + * @param version + * @param os + * @param pipe + */ +export async function addCoverageXdebug( + extension: string, + version: string, + os: string, + pipe: string +): Promise { + let script = '\n'; + const error: string = await checkXdebugError(extension, version); + if (!error) { + script += + (await extensions.addExtension(':pcov:false', version, os, true)) + pipe; + extension = extension == 'xdebug3' ? 'xdebug' : extension; + script += + (await extensions.addExtension(extension, version, os, true)) + pipe; + script += await utils.setVariable( + 'xdebug_version', + 'php -r "echo phpversion(\'xdebug\');"', + os + ); + script += + (await utils.getCommand(os, 'extension_log')) + + 'xdebug "Xdebug $xdebug_version enabled as coverage driver"'; + } else { + script += await utils.addLog('$cross', extension, error, os); + } + return script; +} + +/** + * Function to set up PCOV + * + * @param version + * @param os + * @param pipe + */ +export async function addCoveragePCOV( + version: string, + os: string, + pipe: string +): Promise { + let script = '\n'; + switch (true) { + default: + script += + (await extensions.addExtension(':xdebug:false', version, os, true)) + + pipe; + script += + (await extensions.addExtension('pcov', version, os, true)) + pipe; + script += (await config.addINIValues('pcov.enabled=1', os, true)) + '\n'; + script += await utils.setVariable( + 'pcov_version', + 'php -r "echo phpversion(\'pcov\');"', + os + ); + script += + (await utils.getCommand(os, 'extension_log')) + + 'pcov "PCOV $pcov_version enabled as coverage driver"'; + break; + + case /5\.[3-6]|7\.0/.test(version): + script += await utils.addLog( + '$cross', + 'pcov', + 'PHP 7.1 or newer is required', + os + ); + break; + } + + return script; +} + +/** + * Function to disable Xdebug and PCOV + * + * @param version + * @param os + * @param pipe + */ +export async function disableCoverage( + version: string, + os: string, + pipe: string +): Promise { + let script = '\n'; + script += + (await extensions.addExtension(':pcov:false', version, os, true)) + pipe; + script += + (await extensions.addExtension(':xdebug:false', version, os, true)) + pipe; + script += await utils.addLog('$tick', 'none', 'Disabled Xdebug and PCOV', os); + + return script; +} + +/** + * Function to set coverage driver + * + * @param coverage_driver + * @param version + * @param os + */ +export async function addCoverage( + coverage_driver: string, + version: string, + os: string +): Promise { + coverage_driver = coverage_driver.toLowerCase(); + const script: string = '\n' + (await utils.stepLog('Setup Coverage', os)); + const pipe: string = (await utils.suppressOutput(os)) + '\n'; + switch (coverage_driver) { + case 'pcov': + return script + (await addCoveragePCOV(version, os, pipe)); + case 'xdebug': + case 'xdebug2': + case 'xdebug3': + return ( + script + (await addCoverageXdebug(coverage_driver, version, os, pipe)) + ); + case 'none': + return script + (await disableCoverage(version, os, pipe)); + default: + return ''; + } +} diff --git a/src/extensions.ts b/src/extensions.ts new file mode 100644 index 0000000..41e023e --- /dev/null +++ b/src/extensions.ts @@ -0,0 +1,395 @@ +import * as utils from './utils'; + +/** + * Install and enable extensions for darwin + * + * @param extension_csv + * @param version + */ +export async function addExtensionDarwin( + extension_csv: string, + version: string +): Promise { + const extensions: Array = await utils.extensionArray(extension_csv); + let add_script = '\n'; + let remove_script = ''; + await utils.asyncForEach(extensions, async function (extension: string) { + const version_extension: string = version + extension; + const [ext_name, ext_version]: string[] = extension.split('-'); + const ext_prefix = await utils.getExtensionPrefix(ext_name); + + switch (true) { + // match :extension + case /^:/.test(ext_name): + remove_script += '\ndisable_extension' + ext_name.replace(/:/g, ' '); + return; + // Match none + case /^none$/.test(ext_name): + add_script += '\ndisable_all_shared'; + return; + // match extensions for compiling from source + case /.+-.+\/.+@.+/.test(extension): + add_script += await utils.parseExtensionSource(extension, ext_prefix); + return; + // match 7.4relay...8.5relay + // match 5.3blackfire...8.5blackfire + // match 5.3blackfire-(semver)...8.5blackfire-(semver) + // match couchbase, event, geos, ibm_db2, pdo_ibm, pdo_oci, oci8, http, pecl_http + // match 5.3ioncube...8.5ioncube + // match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, and 7.4phalcon5...8.4phalcon5 + // match 7.0zephir_parser...8.5zephir_parser + case /^(7\.4|8\.[0-5])relay(-v?\d+\.\d+\.\d+|-nightly)?$/.test( + version_extension + ): + case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])blackfire(-\d+\.\d+\.\d+)?$/.test( + version_extension + ): + case /^couchbase|^event|^gearman$|^geos$|^ibm_db2$|^pdo_ibm$|^pdo_oci$|^oci8$|^(pecl_)?http|^pdo_firebird$/.test( + extension + ): + case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])ioncube$/.test(version_extension): + case /(5\.6|7\.[0-3])phalcon3|7\.[2-4]phalcon4|(7\.4|8\.[0-4])phalcon5?/.test( + version_extension + ): + case /(? { + const extensions: Array = await utils.extensionArray(extension_csv); + let add_script = '\n'; + let remove_script = ''; + await utils.asyncForEach(extensions, async function (extension: string) { + const [ext_name, ext_version]: string[] = extension.split('-'); + const version_extension: string = version + extension; + let matches: RegExpExecArray; + switch (true) { + // Match :extension + case /^:/.test(ext_name): + remove_script += '\nDisable-Extension' + ext_name.replace(/:/g, ' '); + break; + // Match none + case /^none$/.test(ext_name): + add_script += '\nDisable-AllShared'; + break; + // match 5.3blackfire...8.5blackfire + // match 5.3blackfire-(semver)...8.5blackfire-(semver) + // match ibm_db2, pdo_ibm, pdo_oci and oci8 + // match 5.3ioncube...8.5ioncube + // match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, and 7.4phalcon5...8.4phalcon5 + // match 7.1pecl_http...8.5pecl_http and 7.1http...8.5http + // match 7.0zephir_parser...8.5zephir_parser + case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])blackfire(-\d+\.\d+\.\d+)?$/.test( + version_extension + ): + case /^ibm_db2$|^pdo_ibm$|^pdo_oci$|^oci8$|^pdo_firebird$/.test( + extension + ): + case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])ioncube$/.test(version_extension): + case /^7\.[0-3]phalcon3$|^7\.[2-4]phalcon4$|^(7\.4|8\.[0-4])phalcon5?$/.test( + version_extension + ): + case /^(7\.[1-4]|8\.[0-5])(pecl_)?http/.test(version_extension): + case /(? { + const extensions: Array = await utils.extensionArray(extension_csv); + let add_script = '\n'; + let remove_script = ''; + await utils.asyncForEach(extensions, async function (extension: string) { + const version_extension: string = version + extension; + const [ext_name, ext_version]: string[] = extension + .split(/-(.+)/) + .filter(Boolean); + const ext_prefix = await utils.getExtensionPrefix(ext_name); + + switch (true) { + // Match :extension + case /^:/.test(ext_name): + remove_script += '\ndisable_extension' + ext_name.replace(/:/g, ' '); + return; + // Match none + case /^none$/.test(ext_name): + add_script += '\ndisable_all_shared'; + return; + // match extensions for compiling from source + case /.+-.+\/.+@.+/.test(extension): + add_script += await utils.parseExtensionSource(extension, ext_prefix); + return; + // match 7.4relay...8.5relay + // match 5.3blackfire...8.5blackfire + // match 5.3blackfire-(semver)...8.5blackfire-(semver) + // match 5.3pdo_cubrid...7.2php_cubrid, 5.3cubrid...7.4cubrid + // match couchbase, geos, ibm_db2, pdo_ibm, pdo_oci, oci8, http, pecl_http + // match 5.3ioncube...8.5ioncube + // match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, 7.4phalcon5...8.4phalcon5 + // match 7.0zephir_parser...8.5zephir_parser + case /^(7\.4|8\.[0-5])relay(-v?\d+\.\d+\.\d+|-nightly)?$/.test( + version_extension + ): + case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])blackfire(-\d+\.\d+\.\d+)?$/.test( + version_extension + ): + case /^((5\.[3-6])|(7\.[0-2]))pdo_cubrid$|^((5\.[3-6])|(7\.[0-4]))cubrid$/.test( + version_extension + ): + case /^couchbase|^event|^gearman$|^geos$|^ibm_db2$|^pdo_ibm$|^pdo_oci$|^oci8$|^(pecl_)?http|^pdo_firebird$/.test( + extension + ): + case /(? { + const log: string = await utils.stepLog('Setup Extensions', os); + let script = '\n'; + switch (no_step) { + case true: + script += log + (await utils.suppressOutput(os)); + break; + case false: + default: + script += log; + break; + } + + switch (os) { + case 'win32': + return script + (await addExtensionWindows(extension_csv, version)); + case 'darwin': + return script + (await addExtensionDarwin(extension_csv, version)); + case 'linux': + return script + (await addExtensionLinux(extension_csv, version)); + default: + return await utils.log( + 'Platform ' + os + ' is not supported', + os, + 'error' + ); + } +} diff --git a/src/fetch.ts b/src/fetch.ts new file mode 100644 index 0000000..4709d3c --- /dev/null +++ b/src/fetch.ts @@ -0,0 +1,42 @@ +/** + * Redirect status codes set for O(1) lookup + */ +const REDIRECT_CODES = new Set([301, 302, 303, 307, 308]); + +/** + * Function to fetch a URL using native fetch API (Node 24+) + * + * @param input_url + * @param auth_token + * @param redirect_count + */ +export async function fetch( + input_url: string, + auth_token?: string, + redirect_count = 5 +): Promise> { + const headers: Record = { + 'User-Agent': `Mozilla/5.0 (${process.platform} ${process.arch}) setup-php` + }; + if (auth_token) { + headers['Authorization'] = 'Bearer ' + auth_token; + } + + try { + const response = await globalThis.fetch(input_url, { + headers, + redirect: redirect_count > 0 ? 'follow' : 'manual' + }); + + if (response.ok) { + const data = await response.text(); + return {data}; + } else if (REDIRECT_CODES.has(response.status) && redirect_count <= 0) { + return {error: `${response.status}: Redirect error`}; + } else { + return {error: `${response.status}: ${response.statusText}`}; + } + } catch (error) { + return {error: `Fetch error: ${(error as Error).message}`}; + } +} diff --git a/src/install.ts b/src/install.ts new file mode 100644 index 0000000..d247713 --- /dev/null +++ b/src/install.ts @@ -0,0 +1,123 @@ +import path from 'path'; +import fs from 'fs'; +import {exec} from '@actions/exec'; +import axios, {isAxiosError} from 'axios'; +import * as config from './config'; +import * as core from './core'; +import * as coverage from './coverage'; +import * as extensions from './extensions'; +import * as tools from './tools'; +import * as utils from './utils'; + +async function validateSubscription(): Promise { + const eventPath = process.env.GITHUB_EVENT_PATH; + let repoPrivate: boolean | undefined; + + if (eventPath && fs.existsSync(eventPath)) { + const eventData = JSON.parse(fs.readFileSync(eventPath, 'utf8')); + repoPrivate = eventData?.repository?.private; + } + + const upstream = 'shivammathur/setup-php'; + const action = process.env.GITHUB_ACTION_REPOSITORY; + const docsUrl = + 'https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions'; + + core.info(''); + core.info('\u001b[1;36mStepSecurity Maintained Action\u001b[0m'); + core.info(`Secure drop-in replacement for ${upstream}`); + if (repoPrivate === false) + core.info('\u001b[32m✓ Free for public repositories\u001b[0m'); + core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`); + core.info(''); + + if (repoPrivate === false) return; + + const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com'; + const body: Record = {action: action || ''}; + if (serverUrl !== 'https://github.com') body.ghes_server = serverUrl; + try { + await axios.post( + `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, + body, + {timeout: 3000} + ); + } catch (error) { + if (isAxiosError(error) && error.response?.status === 403) { + core.error( + `\u001b[1;31mThis action requires a StepSecurity subscription for private repositories.\u001b[0m` + ); + core.error( + `\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m` + ); + process.exit(1); + } + core.info('Timeout or API not reachable. Continuing to next step.'); + } +} + +/** + * Build the script + * + * @param os + */ +export async function getScript(os: string): Promise { + const url = 'https://setup-php.com/sponsor'; + const filename = os + (await utils.scriptExtension(os)); + const script_path = path.join(__dirname, '../src/scripts', filename); + const run_path = script_path.replace(os, 'run'); + const extension_csv: string = await utils.getInput('extensions', false); + const ini_values_csv: string = await utils.getInput('ini-values', false); + const coverage_driver: string = await utils.getInput('coverage', false); + const tools_csv: string = await utils.getInput('tools', false); + const version: string = await utils.parseVersion( + await utils.readPHPVersion() + ); + const ini_file: string = await utils.parseIniFile( + await utils.getInput('ini-file', false) + ); + let script = await utils.joins('.', script_path, version, ini_file); + if (extension_csv) { + script += await extensions.addExtension(extension_csv, version, os); + } + script += await tools.addTools(tools_csv, version, os); + if (coverage_driver) { + script += await coverage.addCoverage(coverage_driver, version, os); + } + if (ini_values_csv) { + script += await config.addINIValues(ini_values_csv, os); + } + script += '\n' + (await utils.stepLog(`Sponsor setup-php`, os)); + script += '\n' + (await utils.addLog('$tick', 'setup-php', url, os)); + + fs.writeFileSync(run_path, script, {mode: 0o755}); + + return run_path; +} + +/** + * Function to set environment variables based on inputs. + */ +export async function setEnv(): Promise { + process.env['fail_fast'] = await utils.getInput('fail-fast', false); + process.env['GITHUB_TOKEN'] ??= await utils.getInput('github-token', false); +} + +/** + * Run the script + */ +export async function run(): Promise { + await validateSubscription(); + await setEnv(); + const os: string = process.platform; + const tool = await utils.scriptTool(os); + const run_path = await getScript(os); + await exec(tool + run_path); +} + +// call the run function +(async () => { + await run(); +})().catch(error => { + core.setFailed(error.message); +}); diff --git a/src/packagist.ts b/src/packagist.ts new file mode 100644 index 0000000..46d6a3d --- /dev/null +++ b/src/packagist.ts @@ -0,0 +1,37 @@ +import * as cv from 'compare-versions'; +import * as fetch from './fetch'; + +type RS = Record; +type RSRS = Record; + +export async function search( + package_name: string, + php_version: string +): Promise { + const response = await fetch.fetch( + `https://repo.packagist.org/p2/${package_name}.json` + ); + if (response.error || response.data === '[]') { + return null; + } + + const data = JSON.parse(response['data']); + if (data && data.packages) { + const versions = data.packages[package_name]; + versions.sort((a: RS, b: RS) => cv.compareVersions(b.version, a.version)); + + const result = versions.find((versionData: RSRS) => { + if (versionData?.require?.php) { + return versionData?.require?.php + .split('|') + .some( + require => require && cv.satisfies(php_version + '.0', require) + ); + } + return false; + }); + + return result ? result.version : null; + } + return null; +} diff --git a/src/scripts/darwin.sh b/src/scripts/darwin.sh new file mode 100644 index 0000000..f6fe5ea --- /dev/null +++ b/src/scripts/darwin.sh @@ -0,0 +1,311 @@ +# Handle dependency extensions +handle_dependency_extensions() { + local formula=$1 + local extension=$2 + formula_file="${tap_dir:?}/$ext_tap/Formula/$extension@${version:?}.rb" + [ -e "$formula_file" ] || formula_file="$tap_dir/$ext_tap/Formula/$formula@$version.rb" + if [ -e "$formula_file" ]; then + IFS=" " read -r -a dependency_extensions <<< "$(grep -Eo "shivammathur.*@" "$formula_file" | xargs -I {} -n 1 basename '{}' | cut -d '@' -f 1 | tr '\n' ' ')" + for dependency_extension in "${dependency_extensions[@]}"; do + sudo sed -Ei '' "/=(.*\/)?\"?$dependency_extension(.so)?$/d" "${ini_file:?}" + done + fi + suffix="$(get_php_formula_suffix)" + if [[ -n "$suffix" ]]; then + brew_opts=(-sf) + patch_abstract_file >/dev/null 2>&1 + for dependency_extension in "${dependency_extensions[@]}"; do + safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$dependency_extension@$version" >/dev/null 2>&1 && + brew link --overwrite --force "$dependency_extension@$version" >/dev/null 2>&1 && + copy_brew_extensions "$dependency_extension" + done + fi +} + +# Helper function to disable an extension. +disable_extension_helper() { + local extension=$1 + local disable_dependents=${2:-false} + get_extension_map + if [ "$disable_dependents" = "true" ]; then + disable_extension_dependents "$extension" + fi + sudo sed -Ei '' "/=(.*\/)?\"?$extension(.so)?$/d" "${ini_file:?}" + sudo rm -rf "$scan_dir"/*"$extension"* /tmp/php"$version"_extensions + mkdir -p /tmp/extdisabled/"$version" + echo '' | sudo tee /tmp/extdisabled/"$version"/"$extension" >/dev/null 2>&1 +} + +# Function to get extension name from brew formula. +get_extension_from_formula() { + local formula=$1 + local extension + extension=$(grep -E "^$formula=" "$src"/configs/brew_extensions | cut -d '=' -f 2) + [[ -z "$extension" ]] && extension="$(echo "$formula" | sed -E "s/pecl_|php|[0-9]//g")" + echo "$extension" +} + +# Function to get renamed formula. +get_renamed_formula() { + local formula=$1 + formula_renames_json="$tap_dir/$ext_tap/formula_renames.json" + if [ -e "$formula_renames_json" ] && grep -q "$formula@$version\":" "$formula_renames_json"; then + grep "$formula@$version\":" "$formula_renames_json" | cut -d ':' -f 2 | tr -d ' ",' | cut -d '@' -f 1 + else + echo "$formula" + fi +} + +# Function to copy extension binaries to the extension directory. +copy_brew_extensions() { + local formula=$1 + formula_file="$tap_dir/$ext_tap/Formula/$formula@$version.rb" + deps="$(grep -Eo 'depends_on "shivammathur[^"]+' "$formula_file" | cut -d '/' -f 3 | tr '\n' ' ')" + IFS=' ' read -r -a deps <<< "$formula@$version $deps" + for dependency in "${deps[@]}"; do + extension_file="${brew_prefix:?}/opt/$dependency/$(get_extension_from_formula "${dependency%@*}").so" + [ -e "$extension_file" ] && sudo cp "$extension_file" "$ext_dir" + done + if [ -d "$brew_prefix"/Cellar/"$formula"@"$version" ]; then + sudo find -- "$brew_prefix"/Cellar/"$formula"@"$version" -name "*.dylib" -exec cp {} "$ext_dir" \; + fi +} + +# Function to install a php extension from shivammathur/extensions tap. +add_brew_extension() { + formula=$1 + prefix=$2 + extension="$(get_extension_from_formula "$formula")" + enable_extension "$extension" "$prefix" + if check_extension "$extension"; then + add_log "${tick:?}" "$extension" "Enabled" + else + add_brew_tap "$php_tap" + add_brew_tap "$ext_tap" + formula="$(get_renamed_formula "$formula")" + update_dependencies >/dev/null 2>&1 + handle_dependency_extensions "$formula" "$extension" >/dev/null 2>&1 + ( + safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$formula@$version" >/dev/null 2>&1 && + brew link --overwrite --force "$formula@$version" >/dev/null 2>&1 && + copy_brew_extensions "$formula" + ) || pecl_install "$extension" >/dev/null 2>&1 + add_extension_log "$extension" "Installed and enabled" + fi +} + +# Function to patch the abstract file in the extensions tap. +patch_abstract_file() { + abstract_path="$tap_dir"/"$ext_tap"/Abstract/abstract-php-extension.rb + if [[ -e "$abstract_path" && ! -e /tmp/abstract_patch ]]; then + echo '' | sudo tee /tmp/abstract_patch >/dev/null 2>&1 + sudo sed -i '' -e "s|php@#{\(.*\)}|php@#{\1}$suffix|g" -e "s|php_version /|\"#{php_version}$suffix\" /|g" "$abstract_path" + fi +} + +# Helper function to add an extension. +add_extension_helper() { + local extension=$1 + prefix=$2 + if [[ "$version" =~ ${old_versions:?} ]] && [ "$extension" = "imagick" ]; then + run_script "php5-darwin" "${version/./}" "$extension" >/dev/null 2>&1 + else + pecl_install "$extension" >/dev/null 2>&1 && + if [[ "$version" =~ ${old_versions:?} ]]; then echo "$prefix=$ext_dir/$extension.so" >>"$ini_file"; fi + fi + add_extension_log "$extension" "Installed and enabled" +} + +# Function to handle request to add phpize and php-config. +add_devtools() { + tool=$1 + add_log "${tick:?}" "$tool" "Added $tool $semver" +} + +# Function to handle request to add PECL. +add_pecl() { + enable_extension xml extension >/dev/null 2>&1 + configure_pecl >/dev/null 2>&1 + pear_version=$(get_tool_version "pecl" "version") + add_log "${tick:?}" "PECL" "Found PECL $pear_version" +} + +# Link opcache extension to extensions directory. +link_opcache() { + opcache_ini="$brew_prefix"/etc/php/"$version"/conf.d/ext-opcache.ini + if [ -e "$opcache_ini" ]; then + opcache_ext=$(grep -Eo "zend_extension.*opcache.*\.so" "$opcache_ini" | cut -d '"' -f 2) + sudo ln -sf "$opcache_ext" "$ext_dir" + fi +} + +# Patch brew to overwrite packages. +patch_brew() { + formula_installer="${brew_repo:?}"/Library/Homebrew/formula_installer.rb + code=" keg.link\(verbose: verbose\?" + sudo sed -Ei '' "s/$code.*/$code, overwrite: true\)/" "$formula_installer" + # shellcheck disable=SC2064 + trap "sudo sed -Ei '' 's/$code.*/$code, overwrite: overwrite?\)/' $formula_installer" exit +} + +# Function to update dependencies. +update_dependencies() { + patch_brew + if ! [ -e /tmp/update_dependencies ]; then + for repo in "$brew_repo" "${core_repo:?}"; do + if [ -e "$repo" ]; then + git_retry -C "$repo" fetch origin main && git -C "$repo" reset --hard origin/main + fi + done + echo '' | sudo tee /tmp/update_dependencies >/dev/null 2>&1 + fi +} + +# Function to get PHP version if it is already installed using Homebrew. +get_brewed_php() { + cellar="$brew_prefix"/Cellar + php_cellar="$cellar"/php + if [ -d "$cellar" ] && ! [[ "$(find "$cellar" -maxdepth 1 -name "php@$version*" | wc -l 2>/dev/null)" -eq 0 ]]; then + php_semver + elif [ -d "$php_cellar" ] && ! [[ "$(find "$php_cellar" -maxdepth 1 -name "$version*" | wc -l 2>/dev/null)" -eq 0 ]]; then + php_semver + else + echo 'false'; + fi +} + +# Function to setup PHP 5.6 and newer using Homebrew. +add_php() { + action=$1 + existing_version=$2 + suffix="$(get_php_formula_suffix)" + php_keg="php@$version$suffix" + php_formula="shivammathur/php/$php_keg" + if [[ "$existing_version" = "false" || -n "$suffix" || "$action" = "upgrade" ]]; then + update_dependencies + add_brew_tap "$php_tap" + fi + if [[ "$existing_version" != "false" && -z "$suffix" ]]; then + if [ "$action" = "upgrade" ]; then + safe_brew install --only-dependencies "$php_formula" + safe_brew upgrade -f --overwrite "$php_formula" + else + brew unlink "$php_keg" + fi + else + safe_brew install --only-dependencies "$php_formula" + safe_brew install --skip-link -f --overwrite "$php_formula" 2>/dev/null || safe_brew upgrade -f --overwrite "$php_formula" + fi + brew link --force --overwrite "$php_keg" || (sudo chown -R "$(id -un)":"$(id -gn)" "$brew_prefix" && brew link --force --overwrite "$php_keg") +} + +# Function to get formula suffix +get_php_formula_suffix() { + local suffix + [ "${debug:?}" = "debug" ] && suffix="-debug" + [ "${ts:?}" = "zts" ] && suffix="$suffix-zts" + echo "$suffix" +} + +# Function to get extra version. +php_extra_version() { + php_formula_file="$tap_dir"/"$php_tap"/Formula/php@"$version".rb + if [ -e "$php_formula_file" ] && ! grep -q "deprecate!" "$php_formula_file" && grep -Eq "archive/[0-9a-zA-Z]+" "$php_formula_file"; then + echo " ($(grep -Eo "archive/[0-9a-zA-Z]+" "$php_formula_file" | cut -d'/' -f 2))" + fi +} + +# Function to set php.ini +add_php_config() { + if ! [ -e "$ini_dir"/php.ini-development ]; then + sudo cp "$ini_dir"/php.ini "$ini_dir"/php.ini-development + fi + if [[ "$ini" = "production" || "$ini" = "development" ]]; then + sudo cp "$ini_dir"/php.ini-"$ini" "$ini_dir"/php.ini + elif [ "$ini" = "none" ]; then + echo '' | sudo tee "${ini_file[@]}" >/dev/null 2>&1 + fi +} + +# Function to get scan directory. +get_scan_dir() { + if [[ "$version" =~ ${old_versions:?} ]]; then + php --ini | grep additional | sed -e "s|.*: s*||" + else + echo "$ini_dir"/conf.d + fi +} + +# Function to handle self-hosted runner setup. +self_hosted_helper() { + sudo mkdir -p /opt/hostedtoolcache >/dev/null 2>&1 || true +} + +# Function to Setup PHP. +setup_php() { + step_log "Setup PHP" + php_config="$(command -v php-config 2>/dev/null)" + update=true + check_pre_installed + existing_version=$(get_brewed_php) + status="Found" + if [[ "$version" =~ ${old_versions:?} ]]; then + run_script "php5-darwin" "${version/./}" >/dev/null 2>&1 + status="Installed" + elif [ "${existing_version:0:3}" != "$version" ]; then + add_php "install" "$existing_version" >/dev/null 2>&1 + status="Installed" + elif [[ "${existing_version:0:3}" = "$version" && "${update:?}" = "true" ]]; then + brew_php_version="$(brew info --json "php@$version" 2>/dev/null | jq -r '.[].versions.stable')" + if [ "$brew_php_version" != "$existing_version" ]; then + add_php "upgrade" "$existing_version" >/dev/null 2>&1 + status="Upgraded" + fi + fi + php_config="$(command -v php-config)" + ext_dir="$(sed -n "s/.*extension_dir=['\"]\(.*\)['\"].*/\1/p" "$php_config")" + ini_dir="$(php_ini_path)" + scan_dir="$(get_scan_dir)" + ini_file="$ini_dir"/php.ini + sudo mkdir -m 777 -p "$ext_dir" "$HOME/.composer" + sudo chmod 777 "$ini_file" "${tool_path_dir:?}" + semver="$(php_semver)" + extra_version="$(php_extra_version)" + configure_php + link_opcache + set_output "php-version" "$semver" + if [ "${semver%.*}" != "$version" ]; then + add_log "${cross:?}" "PHP" "Could not setup PHP $version" + exit 1 + fi + + sudo cp "$src"/configs/pm/*.json "$RUNNER_TOOL_CACHE/" + add_log "$tick" "PHP" "$status PHP $semver$extra_version" +} + +# Variables +version=${1:-'8.5'} +ini=${2:-'production'} +src=${0%/*}/.. +php_formula=shivammathur/php/php@"$version" +scripts="$src"/scripts +ext_tap=shivammathur/homebrew-extensions +php_tap=shivammathur/homebrew-php +export HOMEBREW_CHANGE_ARCH_TO_ARM=1 +export HOMEBREW_NO_AUTO_UPDATE=1 +export HOMEBREW_NO_ENV_HINTS=1 +export HOMEBREW_NO_INSTALL_CLEANUP=1 +export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 +export HOMEBREW_NO_INSTALL_FROM_API=1 + +# shellcheck source=. +. "${scripts:?}"/unix.sh +. "${scripts:?}"/tools/brew.sh +. "${scripts:?}"/tools/retry.sh +. "${scripts:?}"/tools/add_tools.sh +. "${scripts:?}"/extensions/source.sh +. "${scripts:?}"/extensions/add_extensions.sh +configure_brew +read_env +self_hosted_setup +setup_php diff --git a/src/scripts/extensions/add_extensions.ps1 b/src/scripts/extensions/add_extensions.ps1 new file mode 100644 index 0000000..cdc2189 --- /dev/null +++ b/src/scripts/extensions/add_extensions.ps1 @@ -0,0 +1,264 @@ +# Function to check if extension is enabled. +Function Test-Extension() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + $extension_info = Get-PhpExtension -Path $php_dir | Where-Object { $_.Name -eq $extension -or $_.Handle -eq $extension } + return $null -ne $extension_info +} + +# Function to add extension log. +Function Add-ExtensionLog() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + $extension, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + $message + ) + if (Test-Extension $extension) { + Add-Log $tick $extension $message + } else { + Add-Log $cross $extension "Could not install $extension on PHP $( $installed.FullVersion )" + } +} + +# Function to link dependencies to PHP directory. +Function Set-ExtensionPrerequisites +{ + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension + ) + $deps_dir = "$ext_dir\$extension-vc$($installed.VCVersion)-$arch" + $deps = Get-ChildItem -Recurse -Path $deps_dir + if ($deps.Count -ne 0) { + # Symlink dependencies instead of adding the directory to PATH ... + # as other actions change the PATH thus breaking extensions. + $deps | ForEach-Object { + New-Item -Itemtype SymbolicLink -Path $php_dir -Name $_.Name -Target $_.FullName -Force > $null 2>&1 + } + } else { + Remove-Item $deps_dir -Recurse -Force + } +} + +# Function to enable extension. +Function Enable-Extension() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension + ) + Enable-ExtensionDependencies $extension + Enable-PhpExtension -Extension $extension -Path $php_dir + Set-ExtensionPrerequisites $extension + Add-Log $tick $extension "Enabled" +} + +# Function to add custom built PHP extension for nightly builds. +Function Add-ExtensionFromGithub { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension + ) + if($ts) { $ts_part = 'ts' } else { $ts_part = 'nts' } + $repo = "$github/shivammathur/php-extensions-windows" + $url = "$repo/releases/download/builds/php$version`_$ts_part`_$arch`_$extension.dll" + Get-File -Url $url -OutFile "$ext_dir\php_$extension.dll" + if(Test-Path "$ext_dir\php_$extension.dll") { + Enable-Extension $extension > $null + } else { + throw "Failed to download the $extension" + } +} + +# Function to add PHP extensions. +Function Add-Extension { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension, + [Parameter(Position = 1, Mandatory = $false)] + [ValidateNotNull()] + [ValidateSet('stable', 'beta', 'alpha', 'devel', 'snapshot')] + [string] + $stability = 'stable', + [Parameter(Position = 2, Mandatory = $false)] + [ValidateNotNull()] + [ValidatePattern('^\d+(\.\d+){0,3}$')] + [string] + $extension_version = '' + ) + try { + $extension_info = Get-PhpExtension -Path $php_dir | Where-Object { $_.Name -eq $extension -or $_.Handle -eq $extension } + $deps_dir = "$ext_dir\$extension-vc$($installed.VCVersion)-$arch" + New-Item $deps_dir -Type Directory -Force > $null 2>&1 + if ($null -ne $extension_info) { + switch ($extension_info.State) { + 'Builtin' { + Add-Log $tick $extension "Enabled" + } + 'Enabled' { + Add-Log $tick $extension "Enabled" + } + default { + Enable-Extension $extension_info.Handle + } + } + } + else { + if(($version -match $nightly_versions) -and (Select-String -Path $src\configs\windows_extensions -Pattern $extension -SimpleMatch -Quiet)) { + Add-ExtensionFromGithub $extension + } else { + # Patch till DLLs for PHP 8.1 and above are released as stable. + $minimumStability = $stability + if ($version -match '8.[1-4]' -and $stability -eq 'stable') { + $minimumStability = 'snapshot' + } + + $params = @{ Extension = $extension; MinimumStability = $minimumStability; MaximumStability = $stability; Path = $php_dir; AdditionalFilesPath = $deps_dir; NoDependencies = $true } + if ($extension_version -ne '') + { + $params["Version"] = $extension_version + } + # If extension for a different version exists + if(Test-Path $ext_dir\php_$extension.dll) { + Move-Item $ext_dir\php_$extension.dll $ext_dir\php_$extension.bak.dll -Force + } + Install-PhpExtension @params + Set-ExtensionPrerequisites $extension + } + Add-Log $tick $extension "Installed and enabled" + } + } catch { + Add-Log $cross $extension "Could not install $extension on PHP $( $installed.FullVersion )" + } +} + +# Function to get a map of extensions and their dependent shared extensions. +Function Get-ExtensionMap { + php -d'error_reporting=0' $src\scripts\extensions\extension_map.php $env:TEMP\map$version.orig +} + +# Function to enable extension dependencies which are also extensions. +Function Enable-ExtensionDependencies { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension + ) + if (-not(Test-Path $env:TEMP\extdisabled\$extension)) { + return + } + Get-ExtensionMap + $entry = findstr /r "$extension`:.*" $env:TEMP\map$version.orig + if($entry) { + $entry.split(':')[1].trim().split(' ') | ForEach-Object { + if (-not(php -m | findstr -i $_)) { + Enable-PhpExtension -Extension $_ -Path $php_dir + } + } + } + Remove-Item $env:TEMP\extdisabled\$extension -Force +} + +# Function to disable dependent extensions. +Function Disable-DependentExtensions() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension + ) + Select-String -Pattern ".*:.*\s$extension(\s|$)" $env:TEMP\map$version.orig | ForEach-Object { + $dependent = $_.Matches[0].Value.split(':')[0]; + Disable-ExtensionHelper -Extension $dependent -DisableDependents + Add-Log $tick ":$extension" "Disabled $dependent as it depends on $extension" + } +} + +# Helper function to disable an extension. +Function Disable-ExtensionHelper() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension, + [switch] $DisableDependents + ) + Get-ExtensionMap + if($DisableDependents) { + Disable-DependentExtensions $extension + } + Disable-PhpExtension -Extension $extension -Path $php_dir + New-Item $env:TEMP\extdisabled -Type Directory -Force > $null 2>&1 + New-Item $env:TEMP\extdisabled\$extension -Type File -Force > $null 2>&1 +} + +# Function to disable an extension. +Function Disable-Extension() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $extension, + [Parameter(Position = 1, Mandatory = $false)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $DisableDependents + ) + if(php -m | findstr -i $extension) { + if(Test-Path $ext_dir\php_$extension.dll) { + try { + $params = @{ Extension = $extension; DisableDependents = ($DisableDependents -ne 'false') } + Disable-ExtensionHelper @params + Add-Log $tick ":$extension" "Disabled" + } catch { + Add-Log $cross ":$extension" "Could not disable $extension on PHP $($installed.FullVersion)" + } + } else { + Add-Log $cross ":$extension" "Could not disable $extension on PHP $($installed.FullVersion) as it not a shared extension" + } + } elseif(Test-Path $ext_dir\php_$extension.dll) { + Add-Log $tick ":$extension" "Disabled" + } else { + Add-Log $tick ":$extension" "Could not find $extension on PHP $($installed.FullVersion)" + } +} + +# Function to disable shared extensions. +Function Disable-AllShared() { + Get-ExtensionMap + (Get-Content $php_dir\php.ini) | Where-Object {$_ -notmatch '^(zend_)?extension\s*='} | Set-Content $php_dir\php.ini + New-Item $env:TEMP\extdisabled\$version -Type Directory -Force > $null 2>&1 + Get-Childitem $ext_dir\*.dll | ForEach-Object { + New-Item ("$env:TEMP\extdisabled\$version\" + ($_.Name.split('.')[0].split('_')[1])) -Type File -Force > $null 2>&1 + } + Add-Log $tick "none" "Disabled all shared extensions" +} + +# Function to handle request to add PECL. +Function Add-Pecl() { + Add-Log $tick "PECL" "Use extensions input to setup PECL extensions on windows" +} diff --git a/src/scripts/extensions/add_extensions.sh b/src/scripts/extensions/add_extensions.sh new file mode 100644 index 0000000..b4e27b7 --- /dev/null +++ b/src/scripts/extensions/add_extensions.sh @@ -0,0 +1,240 @@ +# Function to log result of installing extension. +add_extension_log() { + if check_extension ${1%%-*}; then + add_log "${tick:?}" "$1" "$2" + else + add_log "${cross:?}" "$1" "${3:-Could not install $1 on PHP ${semver:?}}" + fi +} + +# Function to test if extension is loaded. +check_extension() { + local extension=$1 + local extension_list=/tmp/php${version:?}_extensions + if [ ! -e "$extension_list" ]; then + php -m > "$extension_list" + fi + if [ "$extension" != "mysql" ]; then + grep -i -q -w "$extension" "$extension_list" || php -m | grep -i -q -w "$extension" + else + grep -i -q "$extension" "$extension_list" || php -m | grep -i -q "$extension" + fi +} + +# Function to check if extension is shared +shared_extension() { + [ -e "${ext_dir:?}/$1.so" ] +} + +# Function to enable cached extension's dependencies. +enable_cache_extension_dependencies() { + if [ -d /tmp/extcache ] && shared_extension "$1"; then + cache_dir=$(find /tmp/extcache -maxdepth 1 -type d -regex ".*$1[0-9]*") + if [[ -n "$cache_dir" ]]; then + IFS=" " read -r -a deps <<<"$(find "$cache_dir" -maxdepth 1 -type f -name "*" -exec basename {} \; | tr '\n' ' ')" + IFS="#" read -r -a deps_enable <<<"$(printf -- "-d ${2}=%s.so#" "${deps[@]}")" + if [[ -n "${deps[*]}" ]] && php "${deps_enable[@]}" -d "${2}=$1.so" -m 2>/dev/null | grep -i -q "$1"; then + for ext in "${deps[@]}"; do + sudo rm -rf /tmp/extcache/"$ext" + enable_extension "$ext" "$2" + done + fi + fi + fi +} + +# Function to enable existing extensions. +enable_extension() { + if ! check_extension "$1" && shared_extension "$1"; then + modules_dir="/var/lib/php/modules/${version:?}" + [ -d "$modules_dir" ] && sudo find "$modules_dir" -path "*disabled*$1" -delete + enable_extension_dependencies "$1" "$2" + enable_cache_extension_dependencies "$1" "$2" + if ! [[ "${version:?}" =~ ${old_versions:?} ]] && command -v phpenmod >/dev/null 2>&1; then + sudo sed -Ei "/=(.*\/)?\"?$extension(.so)?\"?$/d" "$pecl_file" + mod="${ini_dir:?}"/../mods-available/"$1".ini + if ! [ -e "$mod" ]; then + priority="${3:-20}"; + mod_priority_line="$(grep -E "^$1=" "${src:?}/configs/mod_priority")"; + [ -n "$mod_priority_line" ] && priority=$(echo "$mod_priority_line" | cut -d'=' -f 2) + (echo "; priority=$priority"; echo "$2=${ext_dir:?}/$1.so") | sudo tee "$mod" >/dev/null + fi + sudo phpenmod -v "$version" "$1" >/dev/null 2>&1 + else + echo "$2=${ext_dir:?}/$1.so" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null + fi + fi +} + +# Function to enable array of extensions +enable_extensions() { + local extensions=("$@") + to_wait=() + for ext in "${extensions[@]}"; do + enable_extension "$ext" extension >/dev/null 2>&1 & + to_wait+=($!) + done + wait "${to_wait[@]}" +} + +# Function to get a map of extensions and their dependent shared extensions. +get_extension_map() { + php -d'error_reporting=0' "${src:?}"/scripts/extensions/extension_map.php /tmp/map"$version".orig >/dev/null 2>&1 +} + +# Function to enable extension dependencies which are also extensions. +enable_extension_dependencies() { + local extension=$1 + local prefix=$2 + [ -e /tmp/extdisabled/"$version"/"$extension" ] || return; + get_extension_map + for dependency in $(grep "$extension:" /tmp/map"$version".orig | cut -d ':' -f 2 | tr '\n' ' '); do + enable_extension "$dependency" "$prefix" + done + rm /tmp/extdisabled/"$version"/"$extension" +} + +# Function to disable dependent extensions. +disable_extension_dependents() { + local extension=$1 + for dependent in $(grep -E ".*:.*\s$extension(\s|$)" /tmp/map"$version".orig | cut -d ':' -f 1 | tr '\n' ' '); do + disable_extension_helper "$dependent" true + add_log "${tick:?}" ":$extension" "Disabled $dependent as it depends on $extension" + done +} + +# Function to disable an extension. +disable_extension() { + local extension=$1 + if check_extension "$extension"; then + if shared_extension "$extension"; then + disable_extension_helper "$extension" true + (! check_extension "$extension" && add_log "${tick:?}" ":$extension" "Disabled") || + add_log "${cross:?}" ":$extension" "Could not disable $extension on PHP ${semver:?}" + else + add_log "${cross:?}" ":$extension" "Could not disable $extension on PHP $semver as it not a shared extension" + fi + elif shared_extension "$extension"; then + add_log "${tick:?}" ":$extension" "Disabled" + else + add_log "${tick:?}" ":$extension" "Could not find $extension on PHP $semver" + fi +} + +# Function to disable shared extensions. +disable_all_shared() { + get_extension_map + sudo sed -i.orig -E -e "/^(zend_)?extension\s*=/d" "${ini_file[@]}" "$pecl_file" 2>/dev/null || true + sudo find "${ini_dir:-$scan_dir}"/.. -name "*.ini" -not -path "*php.ini" -not -path "*phar.ini" -not -path "*pecl.ini" -not -path "*mods-available*" -delete >/dev/null 2>&1 || true + mkdir -p /tmp/extdisabled/"$version" + sudo rm -f /tmp/php"$version"_extensions + sudo find "$ext_dir" -name '*.so' -print0 | xargs -0 -n 1 basename -s .so | xargs -I{} touch /tmp/extdisabled/"$version"/{} + add_log "${tick:?}" "none" "Disabled all shared extensions" +} + +# Function to configure PECL. +configure_pecl() { + [ -z "${pecl_file:-${ini_file[@]}}" ] && return + if ! [ -e /tmp/pecl_config ]; then + for script in pear pecl; do + sudo "$script" channel-update "$script".php.net + done + echo '' | sudo tee /tmp/pecl_config >/dev/null 2>&1 + fi +} + +# Function to add an extension. +add_extension() { + local extension=$1 + local prefix=$2 + enable_extension "$extension" "$prefix" + if check_extension "$extension"; then + add_log "${tick:?}" "$extension" "Enabled" + else + add_extension_helper "$extension" "$prefix" + fi +} + +# Function to get the PECL version of an extension. +get_pecl_version() { + local extension=$1 + states=("stable" "rc" "preview" "beta" "alpha" "snapshot") + stability="$(echo "$2" | grep -m 1 -Eio "($(IFS='|' ; echo "${states[*]}"))")" + IFS=' ' read -r -a states <<< "$(echo "${states[@]}" | grep -Eo "$stability.*")" + major_version=${3:-'[0-9]+'} + pecl_rest='https://pecl.php.net/rest/r/' + response=$(get -s -n "" "$pecl_rest$extension"/allreleases.xml) + for state in "${states[@]}"; do + pecl_version=$(echo "$response" | grep -m 1 -Eio "($major_version\.[0-9]+\.[0-9]+${state}[0-9]+<)" | cut -d '<' -f 1) + [ -z "$pecl_version" ] && pecl_version=$(echo "$response" | grep -m 1 -Eio "v>(.*)<\/v>.*$state<" | grep -m 1 -Eo "($major_version\.[0-9]+\.[0-9]+.*)<" | cut -d '<' -f 1) + [ -n "$pecl_version" ] && break; + done + [ -z "$pecl_version" ] && pecl_version=$(echo "$response" | grep -m 1 -Eo "($major_version\.[0-9]+\.[0-9]+)<" | cut -d '<' -f 1) + echo "$pecl_version" +} + +# Function to install PECL extensions and accept default options +pecl_install() { + local extension=$1 + local prefix=${2:-extension} + add_pecl >/dev/null 2>&1 + disable_extension_helper "${extension%-*}" >/dev/null 2>&1 + # Compare version with 8.3 so it runs only on 8.4 and above + # Install using the source interface as it allows for patching. + if [[ $(printf "%s\n%s" "${version:?}" "8.3" | sort -V | head -n1) != "$version" ]]; then + extension_version=${extension##*-}; + [ "$extension_version" = "${extension%-*}" ] && extension_version=$(get_pecl_version "$extension" "stable") + add_extension_from_source "${extension%-*}" https://pecl.php.net "${extension%-*}" "${extension%-*}" "$extension_version" "$prefix" pecl + check_extension "${extension%-*}" && return 0 || return 1; + else + cpu_count="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo '1')" + prefix_opts="$(parse_args "$extension" CONFIGURE_PREFIX_OPTS) MAKEFLAGS='-j $cpu_count'" + suffix_opts="$(parse_args "$extension" CONFIGURE_OPTS) $(parse_args "$extension" CONFIGURE_SUFFIX_OPTS)" + IFS=' ' read -r -a libraries <<<"$(parse_args "$extension" LIBS) $(parse_args "$extension" "$(uname -s)"_LIBS)" + (( ${#libraries[@]} )) && add_libs "${libraries[@]}" >/dev/null 2>&1 + if [ "$version" = "5.3" ]; then + yes '' 2>/dev/null | sudo "$prefix_opts" pecl install -f "$extension" >/dev/null 2>&1 + else + yes '' 2>/dev/null | sudo "$prefix_opts" pecl install -f -D "$(parse_pecl_configure_options "$suffix_opts")" "$extension" >/dev/null 2>&1 + fi + local exit_code=$? + sudo pecl info "$extension" | grep -iq 'zend extension' && prefix=zend_extension + enable_extension "${extension%-*}" "$prefix" + return "$exit_code" + fi +} + +# Function to install a specific version of PECL extension. +add_pecl_extension() { + local extension=$1 + local pecl_version=$2 + local prefix=$3 + enable_extension "$extension" "$prefix" + if [[ $pecl_version =~ .*(alpha|beta|rc|snapshot|preview).* ]]; then + pecl_version=$(get_pecl_version "$extension" "$pecl_version") + fi + ext_version=$(php -r "echo phpversion('$extension');") + if check_extension "$extension" && [[ -z "$pecl_version" || (-n "$pecl_version" && "${ext_version/-/}" == "$pecl_version") ]]; then + add_log "${tick:?}" "$extension" "Enabled" + else + [ -n "$pecl_version" ] && pecl_version="-$pecl_version" + pecl_install "$extension$pecl_version" || ( [ "${fail_fast:?}" = "false" ] && add_extension "$extension" "$(get_extension_prefix "$extension")" >/dev/null 2>&1) + extension_version="$(php -r "echo phpversion('$extension');")" + [ -n "$extension_version" ] && extension_version="-$extension_version" + add_extension_log "$extension$extension_version" "Installed and enabled" + fi +} + +# Function to setup pre-release extensions using PECL. +add_unstable_extension() { + local extension=$1 + local stability=$2 + local prefix=$3 + pecl_version=$(get_pecl_version "$extension" "$stability") + add_pecl_extension "$extension" "$pecl_version" "$prefix" +} + +# Function to get extension prefix +get_extension_prefix() { + echo "$1" | grep -Eq "xdebug([2-3])?$|opcache|ioncube|eaccelerator" && echo zend_extension || echo extension +} diff --git a/src/scripts/extensions/blackfire.ps1 b/src/scripts/extensions/blackfire.ps1 new file mode 100644 index 0000000..4afe8ed --- /dev/null +++ b/src/scripts/extensions/blackfire.ps1 @@ -0,0 +1,34 @@ +# Function to install blackfire extension. +Function Add-Blackfire() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + try { + $no_dot_version = $version.replace('.', '') + $extension_version = $extension.split('-')[1] + if ($extension_version -notmatch "\S") { + if($version -lt '7.0') { + $extension_version = '1.50.0' + } else { + $extension_version = (Invoke-RestMethod https://blackfire.io/api/v1/releases).probe.php + } + } + if (Test-Path $ext_dir\blackfire.dll) { + Enable-PhpExtension -Extension blackfire -Path $php_dir + $status="Enabled" + } else { + $nts = if (!$installed.ThreadSafe) { "_nts" } else { "" } + Get-File -Url "https://packages.blackfire.io/binaries/blackfire-php/${extension_version}/blackfire-php-windows_${arch}-php-${no_dot_version}${nts}.dll" -OutFile $ext_dir\blackfire.dll > $null 2>&1 + Disable-Extension xdebug > $null 2>&1 + Disable-Extension pcov > $null 2>&1 + Enable-PhpExtension -Extension blackfire -Path $php_dir + $status="Installed and enabled" + } + Add-Log $tick $extension $status + } catch { + Add-Log $cross $extension "Could not install $extension on PHP $($installed.FullVersion)" + } +} diff --git a/src/scripts/extensions/blackfire.sh b/src/scripts/extensions/blackfire.sh new file mode 100644 index 0000000..e06fa3a --- /dev/null +++ b/src/scripts/extensions/blackfire.sh @@ -0,0 +1,32 @@ +# Function to install blackfire extension. +add_blackfire() { + local extension=$1 + version=${version:?} + no_dot_version=${version/./} + platform=$(uname -s | tr '[:upper:]' '[:lower:]') + extension_version=$(echo "$extension" | cut -d '-' -f 2) + status='Enabled' + if ! shared_extension blackfire; then + status='Installed and enabled' + arch="$(uname -m)" + arch_name="amd64" + [[ "$arch" = "aarch64" || "$arch" = "arm64" ]] && arch_name="arm64" + [ "${ts:?}" = 'zts' ] && no_dot_version="${no_dot_version}-zts" + if [ "$extension_version" = "blackfire" ]; then + if [[ ${version:?} =~ 5.[3-6] ]]; then + extension_version='1.50.0' + else + extension_version=$(get -s -n "" https://blackfire.io/api/v1/releases | grep -Eo 'php":"([0-9]+.[0-9]+.[0-9]+)' | cut -d '"' -f 3) + fi + fi + get -q -n "${ext_dir:?}/blackfire.so" https://packages.blackfire.io/binaries/blackfire-php/"$extension_version"/blackfire-php-"$platform"_"$arch_name"-php-"$no_dot_version".so >/dev/null 2>&1 + fi + if [ -e "${ext_dir:?}/blackfire.so" ]; then + disable_extension xdebug >/dev/null 2>&1 + disable_extension pcov >/dev/null 2>&1 + enable_extension blackfire extension + add_extension_log blackfire "$status" + else + add_extension_log blackfire "Could not install blackfire on PHP ${semver:?}" + fi +} diff --git a/src/scripts/extensions/couchbase.sh b/src/scripts/extensions/couchbase.sh new file mode 100644 index 0000000..ef4b876 --- /dev/null +++ b/src/scripts/extensions/couchbase.sh @@ -0,0 +1,98 @@ +# Function to install libraries required by couchbase +add_couchbase_clibs() { + ext=$1 + trunk="https://github.com/couchbase/libcouchbase/releases" + if [[ "$ext" =~ couchbase-2.+ ]]; then + release="2.10.9" + else + release=$(get -s -n "" "$trunk"/latest | grep -Eo -m 1 "[0-9]+\.[0-9]+\.[0-9]+" | head -n 1) + fi + [ "$VERSION_ID" = "24.04" ] && vid=22.04 || vid="$VERSION_ID" + [ "$VERSION_CODENAME" = "noble" ] && vcn=jammy || vcn="$VERSION_CODENAME" + deb_url="$trunk/download/$release/libcouchbase-${release}_ubuntu${vid/./}_${vcn}_amd64.tar" + get -q -n /tmp/libcouchbase.tar "$deb_url" + if ! [ -e /tmp/libcouchbase.tar ] || ! file /tmp/libcouchbase.tar | grep -q 'tar archive'; then + deb_url="$trunk/download/$release/libcouchbase-${release}_ubuntu2004_focal_amd64.tar" + get -q -n /tmp/libcouchbase.tar "$deb_url" + add_old_libssl + fi + sudo tar -xf /tmp/libcouchbase.tar -C /tmp + install_packages libev4 libevent-dev + sudo dpkg -i /tmp/libcouchbase-*/*.deb +} + +add_old_libssl() { + if [[ "$VERSION_ID" = "24.04" ]]; then + get -q -n /tmp/libssl.deb http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb + [ -e /tmp/libssl.deb ] && sudo dpkg -i /tmp/libssl.deb || add_extension_log "couchbase" "Could not install libssl1.1" + fi +} + +add_couchbase_cxxlibs() { + if [ "${runner:?}" = "self-hosted" ]; then + add_list cmake https://apt.kitware.com/ubuntu/ https://apt.kitware.com/keys/kitware-archive-latest.asc "$VERSION_CODENAME" main + fi + install_packages cmake ccache +} + +get_couchbase_version() { + if [[ "${version:?}" =~ ${old_versions:?} ]]; then + echo couchbase-2.2.3 + elif [[ "${version:?}" =~ 5.6|7.[0-1] ]]; then + echo couchbase-2.6.2 + elif [ "${version:?}" = '7.2' ]; then + echo couchbase-3.0.4 + elif [ "${version:?}" = '7.3' ]; then + echo couchbase-3.2.2 + elif [ "${version:?}" = '7.4' ]; then + echo couchbase-4.1.1 + else + echo couchbase + fi +} + +# Function to add couchbase. +add_couchbase() { + ext=$1 + if [ "$(uname -s)" = "Linux" ]; then + if [ "$ext" = "couchbase" ]; then + ext=$(get_couchbase_version) + fi + if [[ "$ext" =~ couchbase-[2-3].+ ]]; then + add_couchbase_clibs "$ext" >/dev/null 2>&1 + else + add_couchbase_cxxlibs >/dev/null 2>&1 + fi + enable_extension "couchbase" "extension" + if check_extension "couchbase"; then + add_log "${tick:?}" "couchbase" "Enabled" + else + if [ "$ext" = "couchbase" ]; then + ext="couchbase-$(get_pecl_version "couchbase" "stable")" + n_proc="$(nproc)" + export COUCHBASE_SUFFIX_OPTS="CMAKE_BUILD_TYPE=Release" + export CMAKE_BUILD_PARALLEL_LEVEL="$n_proc" + add_extension_from_source couchbase https://pecl.php.net couchbase couchbase "${ext##*-}" extension pecl >/dev/null 2>&1 + else + pecl_install "${ext}" >/dev/null 2>&1 + fi + add_extension_log "couchbase" "Installed and enabled" + fi + else + if [ -e "${ext_dir:?}/couchbase.so" ]; then + couchbase_rpath="$(otool -l "${ext_dir:?}/couchbase.so" 2>/dev/null | awk '$1 == "path" && $2 ~ /\/couchbase@'"${version:?}"'\// {print $2; exit}')" + couchbase_rpath="${couchbase_rpath/@loader_path/${ext_dir:?}}" + otool -L "${ext_dir:?}/couchbase.so" 2>/dev/null | + awk -v rpath="$couchbase_rpath" '/libcouchbase_php.*\.dylib/ {if ($1 ~ /^@rpath\// && rpath != "") {sub(/^@rpath/, rpath, $1)}; print $1}' | + while read -r dylib; do + dylib="${dylib/@loader_path/${ext_dir:?}}" + [ -e "${ext_dir:?}/$(basename "$dylib")" ] || continue + sudo mkdir -p "$(dirname "$dylib")" + sudo cp "${ext_dir:?}/$(basename "$dylib")" "$dylib" + done + fi + add_brew_extension couchbase extension + find "${brew_prefix:?}/lib" "${brew_prefix:?}/opt/couchbase@${version:?}" "${brew_prefix:?}/Cellar/couchbase@${version:?}" \ + -name 'libcouchbase_php*.dylib' -exec sudo cp {} "${ext_dir:?}" \; >/dev/null 2>&1 + fi +} diff --git a/src/scripts/extensions/cubrid.sh b/src/scripts/extensions/cubrid.sh new file mode 100644 index 0000000..46e6030 --- /dev/null +++ b/src/scripts/extensions/cubrid.sh @@ -0,0 +1,51 @@ +# Function to log license details. +add_license_log() { + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "$ext" "Click to read the $ext related license information" + printf "Cubrid CCI package is required for %s extension.\n" "$ext" + printf "The extension %s and Cubrid CCI are provided under the license linked below.\n" "$ext" + printf "Refer to: \033[35;1m%s \033[0m\n" "https://github.com/CUBRID/cubrid-cci/blob/develop/COPYING" + echo "$END_GROUP" +} + +# Function to set cubrid repo for the extension. +set_cubrid_repo() { + case "${ext:?}" in + "cubrid") cubrid_repo="cubrid-php";; + "pdo_cubrid") cubrid_repo="cubrid-pdo";; + esac +} + +# Function to set cubrid branch for a PHP version. +set_cubrid_branch() { + case "${version:?}" in + 5.[3-6]) cubrid_branch="RB-9.3.0";; + *) cubrid_branch="develop";; + esac +} + +add_cubrid_helper() { + ext=$1 + enable_extension "$ext" extension + if ! check_extension "$ext"; then + status='Installed and enabled' + set_cubrid_repo + set_cubrid_branch + patch_phpize + read -r "${ext}_PREFIX_CONFIGURE_OPTS" <<< "CFLAGS=-Wno-implicit-function-declaration" + read -r "${ext}_CONFIGURE_OPTS" <<< "--with-php-config=$(command -v php-config)" + add_extension_from_source "$ext" https://github.com CUBRID "$cubrid_repo" "$cubrid_branch" extension + restore_phpize + fi +} + +# Function to add cubrid and pdo_cubrid. +add_cubrid() { + ext=$1 + status='Enabled' + add_cubrid_helper "$ext" >/dev/null 2>&1 + add_extension_log "$ext" "$status" + check_extension "$ext" && add_license_log +} + +# shellcheck source=. +. "${scripts:?}"/extensions/patches/phpize.sh diff --git a/src/scripts/extensions/event.sh b/src/scripts/extensions/event.sh new file mode 100644 index 0000000..71820b2 --- /dev/null +++ b/src/scripts/extensions/event.sh @@ -0,0 +1,50 @@ +# Function to get event configure options +get_event_configure_opts() { + event_opts=( + --with-event-core + --with-event-extra + --with-event-openssl + --enable-event-sockets + ) + if [ "$os" = 'Linux' ]; then + event_opts+=( + --with-openssl-dir=yes + --with-event-libevent-dir=/usr + ) + else + event_opts+=( + --with-openssl-dir="$(brew --prefix openssl@3)" + --with-event-libevent-dir="$(brew --prefix libevent)" + ) + fi +} + +# Helper function to compile and install event +add_event_helper() { + local ext=$1 + [[ "$ext" =~ ^event$ ]] && ext="event-$(get_pecl_version "event" "stable")" + event_opts=() && get_event_configure_opts + export EVENT_LINUX_LIBS='libevent-dev' + export EVENT_DARWIN_LIBS='libevent' + event_configure_opts="--with-php-config=$(command -v php-config) ${event_opts[*]}" + export EVENT_CONFIGURE_OPTS="$event_configure_opts" + add_extension_from_source event https://pecl.php.net event event "${ext##*-}" extension pecl +} + +# Function to add event +add_event() { + local ext=$1 + enable_extension "event" "extension" + if check_extension "event"; then + add_log "${tick:?}" "event" "Enabled" + else + if ! [[ "${version:?}" =~ ${old_versions:?} ]] && [ "$os" = "Darwin" ]; then + add_brew_extension event extension >/dev/null 2>&1 + else + add_event_helper "$ext" >/dev/null 2>&1 + fi + add_extension_log "event" "Installed and enabled" + fi +} + +os="$(uname -s)" diff --git a/src/scripts/extensions/extension_map.php b/src/scripts/extensions/extension_map.php new file mode 100644 index 0000000..075b6c5 --- /dev/null +++ b/src/scripts/extensions/extension_map.php @@ -0,0 +1,132 @@ +extension_dir = ini_get('extension_dir'); + $this->file_extension = (PHP_OS == 'WINNT' ? '.dll' : '.so'); + $this->file_prefix = (PHP_OS == 'WINNT' ? 'php_' : ''); + $this->map = array(); + } + + /** + * Function to read the extension map. + */ + private function parseMap($path) { + if(file_exists($path)) { + $handle = fopen($path, "r"); + if ($handle) { + while (($line = fgets($handle)) !== false) { + $line_parts = explode(':', $line); + $this->map[$line_parts[0]] = explode(' ', trim($line_parts[1])); + } + fclose($handle); + } + } + } + + /** + * Function to check if a shared extension file exists. + * + * @param string $extension + * @return bool + */ + private function checkSharedExtension($extension) { + $extension_file = $this->extension_dir. DIRECTORY_SEPARATOR . $this->file_prefix . $extension . $this->file_extension; + return file_exists($extension_file); + } + + /** + * Function to get all shared extensions. + * + * @return string[] + */ + private function getSharedExtensions() { + $files = scandir($this->extension_dir); + $extensions = array_diff($files, array('.','..')); + $filter_pattern = "/$this->file_extension|$this->file_prefix/"; + return array_map(function ($extension) use($filter_pattern) { + return preg_replace($filter_pattern, '', $extension); + }, $extensions); + } + + /** + * Function to patch dependencies if there are any bugs in Reflection data. + * + * @param string $extension + * @param array $dependencies + * @return array + */ + private function patchDependencies($extension, $dependencies) { + // memcached 2.2.0 has no dependencies in reflection data. + if($extension == 'memcached') { + $dependencies = array_unique(array_merge($dependencies, array('igbinary', 'json', 'msgpack'))); + } + return $dependencies; + } + + /** + * Function to add extension to the map. + * + * @param string $extension + * @throws ReflectionException + */ + private function addExtensionToMap($extension) { + if($this->map && array_key_exists($extension, $this->map) && !empty($this->map[$extension])) { + return; + } + // PHP 5.3 does not allow using $this. + $self = $this; + + $ref = new ReflectionExtension($extension); + $dependencies = array_keys(array_map('strtolower', $ref->getDependencies())); + $dependencies = $this->patchDependencies($extension, $dependencies); + $dependencies = array_filter($dependencies, function ($dependency) use ($self) { + return $self->checkSharedExtension($dependency); + }); + $self->map[$extension] = $dependencies; + } + + /** + * Function to write the map of shared extensions and their dependent extensions. + */ + public function write() { + $path = $_SERVER['argv'][1]; + $this->parseMap($path); + $extensions = array_map('strtolower', $this->getSharedExtensions()); + foreach ($extensions as $extension) { + try { + $this->addExtensionToMap($extension); + } catch (ReflectionException $e) { + + } + } + $map_string = ''; + foreach($this->map as $extension => $dependencies) { + $map_string .= $extension . ': ' . implode(' ', $dependencies) . PHP_EOL; + } + file_put_contents($path, $map_string); + } +} + +$extension_map = new ExtensionMap(); +$extension_map->write(); diff --git a/src/scripts/extensions/firebird.ps1 b/src/scripts/extensions/firebird.ps1 new file mode 100644 index 0000000..af9ed8e --- /dev/null +++ b/src/scripts/extensions/firebird.ps1 @@ -0,0 +1,20 @@ +Function Add-Choco() { + try { + if($null -eq (Get-Command -Name choco.exe -ErrorAction SilentlyContinue)) { + # Source: https://docs.chocolatey.org/en-us/choco/setup + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + } + } catch { } +} + +Function Add-Firebird() { + Add-Choco > $null 2>&1 + choco install firebird -params '/ClientAndDevTools' -y --force > $null 2>&1 + if((Get-ChildItem $env:ProgramFiles\**\**\fbclient.dll | Measure-Object).Count -eq 1) { + Add-Extension pdo_firebird + } else { + Add-Log $cross pdo_firebird "Could not install pdo_firebird on PHP $( $installed.FullVersion )" + } +} \ No newline at end of file diff --git a/src/scripts/extensions/firebird.sh b/src/scripts/extensions/firebird.sh new file mode 100644 index 0000000..d7acb93 --- /dev/null +++ b/src/scripts/extensions/firebird.sh @@ -0,0 +1,27 @@ +add_firebird_helper() { + firebird_dir=$1 + tag="$(php_src_tag)" + export PDO_FIREBIRD_CONFIGURE_PREFIX_OPTS="CFLAGS=-Wno-incompatible-function-pointer-types EXTRA_CFLAGS=-Wno-int-conversion" + export PDO_FIREBIRD_CONFIGURE_OPTS="--with-pdo-firebird=$firebird_dir" + export PDO_FIREBIRD_LINUX_LIBS="firebird-dev" + export PDO_FIREBIRD_PATH="ext/pdo_firebird" + add_extension_from_source pdo_firebird https://github.com php php-src "$tag" extension get +} + +add_firebird() { + enable_extension pdo_firebird extension + if check_extension pdo_firebird; then + add_log "${tick:?}" pdo_firebird Enabled + else + if [ "$(uname -s)" = "Linux" ]; then + if [[ "${version:?}" =~ 5.3|${php_builder_versions:?} ]]; then + add_firebird_helper /usr >/dev/null 2>&1 + else + add_pdo_extension firebird >/dev/null 2>&1 + fi + else + add_brew_extension pdo_firebird extension >/dev/null 2>&1 + fi + add_extension_log pdo_firebird "Installed and enabled" + fi +} diff --git a/src/scripts/extensions/gearman.sh b/src/scripts/extensions/gearman.sh new file mode 100644 index 0000000..bcef0bb --- /dev/null +++ b/src/scripts/extensions/gearman.sh @@ -0,0 +1,27 @@ +# Helper function to add gearman extension. +add_gearman_helper() { + install_packages libgearman-dev + enable_extension gearman extension + if ! check_extension gearman; then + status="Installed and enabled" + if [[ "${version:?}" =~ 5.[3-6] ]]; then + pecl_install gearman-1.1.2 + elif [[ "${version:?}" =~ 7.0 ]]; then + pecl_install gearman-2.1.3 + else + install_packages php"${version:?}"-gearman || pecl_install gearman + fi + enable_extension gearman extension + fi +} + +# Function to add gearman extension. +add_gearman() { + status="Enabled" + if [ "$(uname -s)" = 'Linux' ]; then + add_gearman_helper >/dev/null 2>&1 + add_extension_log "gearman" "$status" + else + add_brew_extension gearman extension + fi +} diff --git a/src/scripts/extensions/geos.sh b/src/scripts/extensions/geos.sh new file mode 100644 index 0000000..c685f86 --- /dev/null +++ b/src/scripts/extensions/geos.sh @@ -0,0 +1,17 @@ +# Helper function to compile and install geos +add_geos_helper() { + export GEOS_LINUX_LIBS='libgeos-dev' + export GEOS_DARWIN_LIBS='geos' + add_extension_from_source geos https://github.com libgeos php-geos 1.0.0 extension get +} + +# Function to add geos +add_geos() { + enable_extension "geos" "extension" + if check_extension "geos"; then + add_log "${tick:?}" "geos" "Enabled" + else + add_geos_helper >/dev/null 2>&1 + add_extension_log "geos" "Installed and enabled" + fi +} diff --git a/src/scripts/extensions/http.ps1 b/src/scripts/extensions/http.ps1 new file mode 100644 index 0000000..86b5c1e --- /dev/null +++ b/src/scripts/extensions/http.ps1 @@ -0,0 +1,53 @@ +Function Get-ICUUrl() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + $icu_version, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + $arch, + [Parameter(Position = 2, Mandatory = $true)] + [ValidateNotNull()] + $vs_version + ) + $trunk = "https://downloads.php.net" + $urls=@("${trunk}/~windows/php-sdk/deps/${vs_version}/${arch}/", "${trunk}/~windows/php-sdk/deps/archives/${vs_version}/${arch}/") + foreach ($url in $urls) { + try { + $web_content = Get-File -Url $url 2>$null + } catch { continue } + foreach ($link in $web_content.Links) { + if ($link.href -match ".*ICU-${icu_version}.*") { + return $url + $link.HREF + } + } + } +} + +Function Repair-ICU() { + $icu = deplister $ext_dir\php_http.dll | Select-String "icu[a-z]+(\d+).dll,([A-Z]+)" | Foreach-Object { $_.Matches } + if($icu -and $icu.Groups[2].Value -ne 'OK') { + $vs = "vs" + $installed.VCVersion + if ($installed.VCVersion -lt 16) { + $vs = "vc" + $installed.VCVersion + } + $zip_url = Get-ICUUrl $icu.Groups[1].Value $installed.Architecture $vs + if ($zip_url -ne '') { + New-Item -Path "$php_dir" -Name "icu" -ItemType "directory" -Force > $null 2>&1 + Get-File -Url $zip_url -OutFile "$php_dir\icu\icu.zip" + Expand-Archive -Path $php_dir\icu\icu.zip -DestinationPath $php_dir\icu -Force + Get-ChildItem $php_dir\icu\bin -Filter *.dll | Copy-Item -Destination $php_dir -Force + } + } +} + +Function Add-Http() { + Add-Extension iconv >$null 2>&1 + Add-Extension raphf >$null 2>&1 + if($version -lt '8.0') { + Add-Extension propro >$null 2>&1 + } + Add-Extension pecl_http >$null 2>&1 + Repair-ICU + Add-ExtensionLog http "Installed and enabled" +} \ No newline at end of file diff --git a/src/scripts/extensions/http.sh b/src/scripts/extensions/http.sh new file mode 100644 index 0000000..6880298 --- /dev/null +++ b/src/scripts/extensions/http.sh @@ -0,0 +1,113 @@ +# Function to get http version for a PHP version. +get_http_version() { + if [[ ${version:?} =~ 5.[3-6] ]]; then + echo "pecl_http-2.6.0" + elif [[ ${version:?} =~ 7.[0-4] ]]; then + echo "pecl_http-3.2.4" + else + echo "pecl_http-$(get_pecl_version "pecl_http" "stable")" + fi +} + +# Function to enable http extension. +enable_http() { + enable_extension iconv extension + enable_extension propro extension + enable_extension raphf extension + if (! [[ ${version:?} =~ ${jit_versions:?} ]] && check_extension iconv && check_extension propro && check_extension raphf) || + ( [[ ${version:?} =~ ${jit_versions:?} ]] && check_extension iconv && check_extension raphf); then + enable_extension http extension + fi +} + +# Function to install http dependencies. +add_http_dependencies() { + if [[ ${version:?} =~ ${old_versions:?} ]]; then + add_pecl_extension raphf 1.1.2 extension + add_pecl_extension propro 1.0.2 extension + elif [[ ${version:?} =~ 5.6|7.[0-4] ]]; then + add_extension iconv extension + add_extension propro extension + add_extension raphf extension + else + add_extension iconv extension + add_extension raphf extension + fi +} + +# Function to get configure options for http. +get_http_configure_opts() { + if [ "$os" = 'Linux' ]; then + for lib in zlib libbrotli libcurl libevent libicu libidn2 libidn libidnkit2 libidnkit; do + http_opts+=( "--with-http-$lib-dir=/usr" ) + done + else + http_opts+=( "--with-http-zlib-dir=$(xcrun --show-sdk-path)/usr" ) + http_opts+=( "--with-http-libbrotli-dir=$(brew --prefix brotli)" ) + http_opts+=( "--with-http-libcurl-dir=$(brew --prefix curl)" ) + http_opts+=( "--with-http-libicu-dir=$(brew --prefix icu4c)" ) + http_opts+=( "--with-http-libevent-dir=$(brew --prefix libevent)" ) + http_opts+=( "--with-http-libidn2-dir=$(brew --prefix libidn2)" ) + fi +} + +# Compile and install http explicitly. +# This is done as pecl compiles raphf and propro as well. +add_http_helper() { + ext=$1 + http_opts=() && get_http_configure_opts + export HTTP_PREFIX_CONFIGURE_OPTS="CFLAGS=-Wno-implicit-function-declaration" + http_configure_opts="--with-http --with-php-config=$(command -v php-config) ${http_opts[*]}" + export HTTP_CONFIGURE_OPTS="$http_configure_opts" + export HTTP_LINUX_LIBS="zlib1g libbrotli-dev libcurl4-openssl-dev libevent-dev libicu-dev libidn2-dev" + export HTTP_DARWIN_LIBS="brotli curl icu4c libevent libidn2" + if [[ "${version:?}" =~ ${nightly_versions:?} ]]; then + add_extension_from_source http https://github.com m6w6 ext-http master extension + else + add_extension_from_source pecl_http https://pecl.php.net http http "${ext##*-}" extension pecl + fi +} + +# Function to setup latest http extension. +add_http_latest() { + enable_http + if ! check_extension http; then + if [ "$os" = "Linux" ]; then + add_http_dependencies + package="php$version-http" + add_ppa ondrej/php >/dev/null 2>&1 || update_ppa ondrej/php + (check_package "$package" && install_packages "$package") || add_http_helper "$(get_http_version)" "$os" + else + if ! [[ "${version:?}" =~ ${old_versions:?} ]]; then + add_brew_extension pecl_http extension + fi + fi + status="Installed and enabled" + fi +} + +# Function to setup http extension given a version. +add_http_version() { + ext=$1 + enable_http + if [ "x$(php -r "echo phpversion('http');")" != "x${ext##*-}" ]; then + add_http_dependencies + disable_extension_helper http >/dev/null + add_http_helper pecl_http-"${ext##*-}" "$os" + status="Installed and enabled" + fi +} + +# Function to setup http extension +add_http() { + ext=$1 + status="Enabled" + if [[ "$ext" =~ ^(pecl_http|http)$ ]]; then + add_http_latest >/dev/null 2>&1 + else + add_http_version "$ext" >/dev/null 2>&1 + fi + add_extension_log "http" "$status" +} + +os="$(uname -s)" diff --git a/src/scripts/extensions/ibm.ps1 b/src/scripts/extensions/ibm.ps1 new file mode 100644 index 0000000..d09b67a --- /dev/null +++ b/src/scripts/extensions/ibm.ps1 @@ -0,0 +1,56 @@ +# Function to log license information for ibm extensions. +Function Add-LicenseLog() { + printf "$env:GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" $extension "Click to read the $extension related license information" + printf "IBM Db2 ODBC and CLI Driver is required for %s extension.\n" $extension + printf "It is provided under the IBM International Program License Agreement.\n" + printf "Refer to: \033[35;1m%s \033[0m\n" "https://www.ibm.com/support/pages/db2-odbc-cli-driver-download-and-installation-information" + $licensePath = "$php_dir\clidriver\license\odbc_notices.rtf" + if (Test-Path $licensePath) { + Add-Type -AssemblyName System.Windows.Forms + $rtBox = New-Object System.Windows.Forms.RichTextBox + $rtBox.Rtf = [System.IO.File]::ReadAllText($licensePath); + Write-Host $rtBox.Text; + } + Write-Output "$env:END_GROUP" +} + +# Function to install IBM Db2 CLI driver. +Function Add-IbmCli() { + $cliPath = "$php_dir\clidriver" + if (-not (Test-Path "$cliPath\bin")) { + $suffix = if ($arch -eq 'x86') { 'nt32' } else { 'ntx64' } + $archive = "$suffix`_odbc_cli.zip" + $destination = "$ENV:RUNNER_TOOL_CACHE\ibm_cli.zip" + Get-File -Url "https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/$archive" -OutFile $destination > $null 2>&1 + Expand-Archive -Path $destination -DestinationPath $php_dir -Force > $null 2>&1 + } + $env:IBM_DB_HOME = $cliPath + $env:LD_LIBRARY_PATH = "$cliPath\bin;$cliPath\lib;$env:LD_LIBRARY_PATH" + Add-Path "$cliPath\bin" + $env:PATH = "$cliPath\bin;$env:PATH" +} + +# Function to install ibm_db2 and pdo_ibm. +Function Add-Ibm() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateSet('ibm_db2', 'pdo_ibm')] + [string] + $extension + ) + try { + $status = 'Enabled' + Add-IbmCli + if (Test-Path "$ext_dir\php_$extension.dll") { + Enable-PhpExtension -Extension $extension -Path $php_dir + } else { + Add-Extension $extension + $status = 'Installed and enabled' + } + Add-ExtensionLog $extension $status + Add-LicenseLog + } catch { + Add-Log $cross $extension "Could not install $extension on PHP $( $installed.FullVersion )" + } +} diff --git a/src/scripts/extensions/ibm.sh b/src/scripts/extensions/ibm.sh new file mode 100644 index 0000000..cd2c625 --- /dev/null +++ b/src/scripts/extensions/ibm.sh @@ -0,0 +1,106 @@ +# Function to log license details for ibm extensions. +add_license_log() { + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "$ext" "Click to read the $ext related license information" + printf "IBM Db2 ODBC and CLI Driver is required for %s extension.\n" "$ext" + printf "Refer to: \033[35;1m%s \033[0m\n" "https://www.ibm.com/support/pages/db2-odbc-cli-driver-download-and-installation-information" + local license_file="$ibm_cli/license/odbc_notices.txt" + if [ -f "$license_file" ]; then + cat "$license_file" + fi + echo "$END_GROUP" +} + +# Function to determine the driver archive for the current platform. +get_cli_archive() { + local os=$1 + local arch=$2 + case $os in + Linux) + case $arch in + x86_64|amd64) echo "linuxx64_odbc_cli.tar.gz";; + i?86) echo "linuxia32_odbc_cli.tar.gz";; + *) return 1;; + esac + ;; + Darwin) + case $arch in + x86_64) echo "macos64_odbc_cli.tar.gz";; + arm64|aarch64) echo "macarm64_odbc_cli.tar.gz";; + *) return 1;; + esac + ;; + *) + return 1 + ;; + esac +} + +# Function to install IBM Db2 CLI driver. +add_cli_driver() { + local os arch archive url tmp libs + if [ -d "$ibm_cli" ]; then + return 0 + fi + os=$(uname -s) + arch=$(uname -m) + archive=$(get_cli_archive "$os" "$arch") || return 1 + url="https://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/$archive" + tmp=/tmp/$archive + get -q -n "$tmp" "$url" + sudo mkdir -p "$ibm_home" + sudo tar -xzf "$tmp" -C "$ibm_home" + sudo rm -f "$tmp" + if [ ! -d "$ibm_cli" ]; then + local extracted + extracted=$(find "$ibm_home" -maxdepth 1 -type d -name 'clidriver*' | head -n 1) + [ -n "$extracted" ] && sudo mv "$extracted" "$ibm_cli" + fi + if [ "$os" = "Linux" ]; then + echo "$ibm_cli/lib" | sudo tee /etc/ld.so.conf.d/ibm_db2.conf >/dev/null + sudo ldconfig + else + libs='/usr/local/lib' + sudo mkdir -p "$libs" + sudo ln -sf "$ibm_cli"/lib/*.dylib "$libs" >/dev/null 2>&1 || true + fi +} + +# Function to install ibm_db2 and pdo_ibm. +add_ibm_helper() { + if ! shared_extension "$ext"; then + status='Installed and enabled' + export IBM_DB_HOME="$ibm_cli" + export LD_LIBRARY_PATH="$IBM_DB_HOME/lib" + add_env DYLD_LIBRARY_PATH "$IBM_DB_HOME/lib" + local configure_flag + if [ "$ext" = 'ibm_db2' ]; then + configure_flag="--with-IBM_DB2=$IBM_DB_HOME" + else + configure_flag="--with-pdo-ibm=$IBM_DB_HOME" + fi + read -r "${ext}_CONFIGURE_OPTS" <<< "--with-php-config=$(command -v php-config) $configure_flag" + patch_phpize + add_extension_from_source "$ext" https://github.com php "pecl-database-$ext" master extension get + restore_phpize + else + enable_extension "$ext" extension + fi +} + +# Function to add ibm_db2 and pdo_ibm. +add_ibm() { + ext=$1 + status='Enabled' + ibm_home='/opt/ibm' + ibm_cli=$ibm_home/clidriver + if ! add_cli_driver >/dev/null 2>&1; then + add_log "${cross:?}" "$ext" "IBM Db2 CLI driver is not available on $(uname -s)/$(uname -m)" + return 1 + fi + add_ibm_helper >/dev/null 2>&1 + add_extension_log "$ext" "$status" + check_extension "$ext" && add_license_log +} + +# shellcheck source=. +. "${scripts:?}"/extensions/patches/phpize.sh diff --git a/src/scripts/extensions/intl.sh b/src/scripts/extensions/intl.sh new file mode 100644 index 0000000..d8faf1c --- /dev/null +++ b/src/scripts/extensions/intl.sh @@ -0,0 +1,28 @@ +# Function to install ICU +install_icu() { + icu=$1 + if [ "$(php -i | grep "ICU version =>" | sed -e "s|.*=> s*||")" != "$icu" ]; then + get -q -n /tmp/icu.tar.zst "https://github.com/shivammathur/icu-intl/releases/download/icu4c/icu4c-$icu$arch_suffix.tar.zst" + sudo tar -I zstd -xf /tmp/icu.tar.zst -C /usr/local + sudo cp -r /usr/local/icu/lib/* /usr/lib/"$(uname -m)"-linux-gnu/ + fi +} + +# Function to add ext-intl with the given version of ICU +add_intl() { + icu=$(echo "$1" | cut -d'-' -f 2) + supported_version=$(get -s -n "" https://api.github.com/repos/shivammathur/icu-intl/releases/tags/intl-"$icu" | grep -Po "php${version?}-intl-$icu" | head -n 1) + [ -z "$supported_version" ] && supported_version=$(get -s -n "" https://github.com/shivammathur/icu-intl/releases/expanded_assets/intl-"$icu" | grep -Po "php$version-intl-$icu" | head -n 1) + if [ "php$version-intl-$icu" != "$supported_version" ]; then + add_log "${cross:?}" "intl" "ICU $icu is not supported for PHP $version" + else + [ "${ts:?}" = 'zts' ] && suffix='-zts' + install_icu "$icu" >/dev/null 2>&1 + get -q -n "${ext_dir:?}/intl.so" "https://github.com/shivammathur/icu-intl/releases/download/intl-$icu/php${version:?}-intl-$icu$suffix$arch_suffix.so" + enable_extension intl extension + add_extension_log intl "Installed and enabled with ICU $icu" + fi +} + +arch="$(uname -m)" +[[ "$arch" = 'arm64' || "$arch" = 'aarch64' ]] && arch_suffix='-arm64' || arch_suffix='' diff --git a/src/scripts/extensions/ioncube.ps1 b/src/scripts/extensions/ioncube.ps1 new file mode 100644 index 0000000..88b09e6 --- /dev/null +++ b/src/scripts/extensions/ioncube.ps1 @@ -0,0 +1,33 @@ +# Function to log result of a operation. +Function Add-LicenseLog() { + printf "$env:GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "ioncube" "Click to read the ioncube loader license information" + Get-Content $ext_dir\ioncube\LICENSE.txt + Write-Output "$env:END_GROUP" +} + +# Function to add ioncube extension. +Function Add-Ioncube() { + try { + $status = 'Enabled' + if (-not(Test-Path $ext_dir\php_ioncube.dll)) { + $status = 'Installed and enabled' + $arch_part = $arch + if ($arch -eq 'x64') { + $arch_part = 'x86-64' + } + $vc = $installed.VCVersion + $ts_part = "" + if (-not($installed.ThreadSafe)) { + $ts_part = "_nonts" + } + Get-File -Url "https://downloads.ioncube.com/loader_downloads/ioncube_loaders_win$ts_part`_vc$vc`_$arch_part.zip" -OutFile $ext_dir\ioncube.zip + Expand-Archive -Path $ext_dir\ioncube.zip -DestinationPath $ext_dir -Force + Copy-Item $ext_dir\ioncube\ioncube_loader_win_$version.dll $ext_dir\php_ioncube.dll + } + "zend_extension=$ext_dir\php_ioncube.dll`r`n" + (Get-Content $php_dir\php.ini -Raw) | Set-Content $php_dir\php.ini + Add-Log $tick "ioncube" $status + Add-LicenseLog + } catch { + Add-Log $cross "ioncube" "Could not install ioncube on PHP $($installed.FullVersion)" + } +} diff --git a/src/scripts/extensions/ioncube.sh b/src/scripts/extensions/ioncube.sh new file mode 100644 index 0000000..eca3af7 --- /dev/null +++ b/src/scripts/extensions/ioncube.sh @@ -0,0 +1,34 @@ +# Function to log result of a operation. +add_license_log() { + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "ioncube" "Click to read the ioncube loader license information" + cat "${ext_dir:?}"/IONCUBE_LICENSE.txt + echo "$END_GROUP" +} + +# Function to install ioncube. +add_ioncube() { + status='Enabled' + if ! shared_extension ioncube; then + status='Installed and enabled' + arch="$(uname -m)" + if [ "$(uname -s)" = "Darwin" ]; then + [ "$arch" = "arm64" ] && os_suffix="dar_arm64" || os_suffix="mac_x86-64" + else + [[ "$arch" = "i386" || "$arch" = "i686" ]] && arch=x86 + [[ "$arch" = "x86_64" ]] && arch=x86-64 + os_suffix="lin_$arch" + fi + ts_part="" && [ "${ts:?}" = "zts" ] && ts_part="_ts" + get -s -n "" https://downloads.ioncube.com/loader_downloads/ioncube_loaders_"$os_suffix".tar.gz | tar -xzf - -C /tmp + loader_file=/tmp/ioncube/ioncube_loader_"${os_suffix%%_*}_${version:?}$ts_part".so + if [ -e "$loader_file" ]; then + sudo mv /tmp/ioncube/ioncube_loader_"${os_suffix%%_*}_${version:?}$ts_part".so "${ext_dir:?}/ioncube.so" + sudo cp /tmp/ioncube/LICENSE.txt "$ext_dir"/IONCUBE_LICENSE.txt + echo "zend_extension=$ext_dir/ioncube.so" | sudo tee "${scan_dir:?}/00-ioncube.ini" >/dev/null 2>&1 + fi + else + echo "zend_extension=$ext_dir/ioncube.so" | sudo tee "${scan_dir:?}/00-ioncube.ini" >/dev/null 2>&1 + fi + add_extension_log "ioncube" "$status" + check_extension "ioncube" && add_license_log +} diff --git a/src/scripts/extensions/oci.ps1 b/src/scripts/extensions/oci.ps1 new file mode 100644 index 0000000..033006d --- /dev/null +++ b/src/scripts/extensions/oci.ps1 @@ -0,0 +1,81 @@ +# Function to log license information. +Function Add-LicenseLog() { + printf "$env:GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" $extension "Click to read the $extension related license information" + printf "Oracle Instant Client package is required for %s extension.\n" $extension + printf "It is provided under the Oracle Technology Network Development and Distribution License.\n" + printf "Refer to: \033[35;1m%s \033[0m\n" "https://www.oracle.com/downloads/licenses/instant-client-lic.html" + Write-Output "$env:END_GROUP" +} + +# Function to get instantclinet. +Function Add-InstantClient() { + if (-not(Test-Path $php_dir\oci.dll)) { + $suffix = 'windows' + if ($arch -eq 'x86') { + $suffix = 'nt' + } + Get-File -Url https://download.oracle.com/otn_software/nt/instantclient/instantclient-basiclite-$suffix.zip -OutFile $php_dir\instantclient.zip + Expand-Archive -Path $php_dir\instantclient.zip -DestinationPath $php_dir -Force + Copy-Item $php_dir\instantclient*\* $php_dir + } +} + +# Function to oci8 extension URL. +Function Get-Oci8Url() { + if($version -lt '8.0') { + $ociVersion = '2.2.0' + if ($version -eq '7.0') { + $ociVersion = '2.1.8' + } elseif ($version -lt '7.0') { + $ociVersion = '2.0.12' + } + return Get-PeclArchiveUrl oci8 $ociVersion $installed + } else { + $ociUrl = ''; + Get-PeclPackageVersion oci8 -MinimumStability stable -MaximumStability stable | ForEach-Object { + $ociUrl = Get-PeclArchiveUrl oci8 $_ $installed + if($ociUrl) { + return $ociUrl + } + } + } +} + +# Function to get OCI8 DLL. +Function Get-Oci8DLL() { + Get-ChildItem $ext_dir\php_oci8*.dll | ForEach-Object { + if((Get-PhpExtension -Path $_).PhpVersion -eq $version) { + return $_ + } + } + return $null +} + +# Function to install oci8 and pdo_oci. +Function Add-Oci() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateSet('oci8', 'pdo_oci')] + [string] + $extension + ) + try { + $status = 'Enabled' + Add-InstantClient + if($version -lt '8.4') { + if($version -lt '5.6' -and $extension -eq 'oci8') { + Add-Content -Value "`r`nextension=php_oci8.dll" -Path $php_dir\php.ini + } else { + Enable-PhpExtension $extension -Path $php_dir + } + } else { + $status = 'Installed and enabled' + Add-Extension $extension >$null 2>&1 + } + Add-ExtensionLog $extension $status + Add-LicenseLog + } catch { + Add-Log $cross $extension "Could not install $extension on PHP $( $installed.FullVersion )" + } +} diff --git a/src/scripts/extensions/oci.sh b/src/scripts/extensions/oci.sh new file mode 100644 index 0000000..929ffc2 --- /dev/null +++ b/src/scripts/extensions/oci.sh @@ -0,0 +1,82 @@ +# Function to log result of a operation. +add_license_log() { + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "$ext" "Click to read the $ext related license information" + printf "Oracle Instant Client package is required for %s extension.\n" "$ext" + printf "It is provided under the Oracle Technology Network Development and Distribution License.\n" + printf "Refer to: \033[35;1m%s \033[0m\n" "https://www.oracle.com/downloads/licenses/instant-client-lic.html" + echo "$END_GROUP" +} + +# Function to install instantclient and SDK. +add_client() { + if [ ! -e "$oracle_client" ]; then + sudo mkdir -p -m 777 "$oracle_home" "$oracle_client" + arch="$(uname -m)" + for package in basiclite sdk; do + if [ "$os" = 'Linux' ]; then + libs='/usr/lib/' + os_name='linux' + [[ "$arch" = 'arm64' || "$arch" = 'aarch64' ]] && arch_suffix='linux-arm64' || arch_suffix='linuxx64' + lib_ext='so' + elif [ "$os" = 'Darwin' ]; then + libs='/usr/local/lib/' + os_name='mac' + arch_suffix='macos' + lib_ext='dylib' + fi + if [[ "$os" = 'Darwin' && ("$arch" = 'arm64' || "$arch" = 'aarch64') ]]; then + get -q -n "/opt/oracle/$package.dmg" "https://download.oracle.com/otn_software/$os_name/instantclient/instantclient-$package-macos-arm64.dmg" + sudo hdiutil attach "/opt/oracle/$package.dmg" + (cd /Volumes/instantclient-"$package"-macos.arm64-* && bash install_ic.sh) + sudo cp -a ~/Downloads/instantclient_* /opt/oracle/ + else + get -q -n "/opt/oracle/$package.zip" "https://download.oracle.com/otn_software/$os_name/instantclient/instantclient-$package-$arch_suffix.zip" + unzip -o "/opt/oracle/$package.zip" -d "$oracle_home" + fi + done + for icdir in /opt/oracle/instantclient_*; do + sudo mv "$icdir"/* "$oracle_client"/ + done + sudo mkdir -p "$libs" + sudo ln -sf /opt/oracle/instantclient/*."$lib_ext"* "$libs" + if [ "$os" = "Linux" ]; then + [ -e "$libs/$arch"-linux-gnu/libaio.so.1 ] || sudo ln -sf "$libs/$arch"-linux-gnu/libaio.so.1t64 "$libs/$arch"-linux-gnu/libaio.so.1 + fi + fi +} + +# Function to install oci8 and pdo_oci. +add_oci_helper() { + if ! shared_extension "$ext"; then + status='Installed and enabled' + read -r "${ext}_CONFIGURE_PREFIX_OPTS" <<< "CFLAGS=-Wno-incompatible-function-pointer-types" + read -r "${ext}_LINUX_LIBS" <<< "libaio-dev" + read -r "${ext}_CONFIGURE_OPTS" <<< "--with-php-config=$(command -v php-config) --with-${ext/_/-}=instantclient,$oracle_client" + patch_phpize + if [[ $(printf "%s\n%s" "${version:?}" "8.3" | sort -V | head -n1) != "$version" ]]; then + add_extension_from_source "$ext" https://github.com php pecl-database-"$ext" main extension get + else + read -r "${ext}_PATH" <<< "ext/$ext" + add_extension_from_source "$ext" https://github.com php php-src "$(php_src_tag)" extension get + fi + restore_phpize + else + enable_extension "$ext" extension + fi +} + +# Function to add oci extension oci8 and pdo_oci. +add_oci() { + ext=$1 + status='Enabled' + oracle_home='/opt/oracle' + oracle_client=$oracle_home/instantclient + os=$(uname -s) + add_client >/dev/null 2>&1 + add_oci_helper >/dev/null 2>&1 + add_extension_log "$ext" "$status" + check_extension "$ext" && add_license_log +} + +# shellcheck source=. +. "${scripts:?}"/extensions/patches/phpize.sh diff --git a/src/scripts/extensions/patches/amqp.sh b/src/scripts/extensions/patches/amqp.sh new file mode 100644 index 0000000..fed906d --- /dev/null +++ b/src/scripts/extensions/patches/amqp.sh @@ -0,0 +1,5 @@ +patch_amqp() { + if [[ $(printf '%s\n%s\n' "${version:?}" "8.5" | sort -V | head -n1) == "8.5" ]]; then + get -q -n amqp_connection_resource.c https://raw.githubusercontent.com/remicollet/php-amqp/977449987412a3d5c59a036dbab8b6d67764bb3e/amqp_connection_resource.c + fi +} \ No newline at end of file diff --git a/src/scripts/extensions/patches/common.sh b/src/scripts/extensions/patches/common.sh new file mode 100644 index 0000000..ec522a2 --- /dev/null +++ b/src/scripts/extensions/patches/common.sh @@ -0,0 +1,35 @@ +patch_84() { + sed -i.bak \ + -e '0,/#include.*\(php_lcg.h\|php_mt_rand.h\|php_rand.h\|standard\/php_random\.h\).*/s//#include /' \ + -e '/#include.*\(php_lcg.h\|php_mt_rand.h\|php_rand.h\|standard\/php_random\.h\)/d' \ + "$1" && rm -rf *.bak +} + +patch_85() { + sed -i.bak \ + -e 's#ext/standard/php_smart_string.h#Zend/zend_smart_string.h#g' \ + -e 's#ext/standard/php_smart_string_public.h#Zend/zend_smart_string.h#g' \ + -e 's#zend_exception_get_default(TSRMLS_C)#zend_ce_exception#g' \ + -e 's#zend_exception_get_default()#zend_ce_exception#g' \ + "$1" && rm -rf *.bak +} + +version_ge() { + ver=$1 + min=$2 + [[ $(printf '%s\n%s\n' "$ver" "$min" | sort -V | head -n1) == "$min" ]] +} + +if version_ge "${version:?}" "8.4"; then + while IFS= read -r file; do + patch_84 "$file" + done < <(grep -rlE 'php_lcg\.h|php_mt_rand\.h|php_rand\.h|standard/php_random\.h' \ + --include='*.c' --include='*.h' . || true) +fi + +if version_ge "${version:?}" "8.5"; then + while IFS= read -r file; do + patch_85 "$file" + done < <(grep -rlE 'ext/standard/php_smart_string(_public)?\.h|zend_exception_get_default' \ + --include='*.c' --include='*.h' . || true) +fi diff --git a/src/scripts/extensions/patches/firebird.sh b/src/scripts/extensions/patches/firebird.sh new file mode 100644 index 0000000..0007d61 --- /dev/null +++ b/src/scripts/extensions/patches/firebird.sh @@ -0,0 +1,11 @@ +patch_firebird() { + if [[ "${version:?}" =~ ${old_versions:?} ]]; then + sudo sed -i '' '/PHP_CHECK_PDO_INCLUDES/d' config.m4 2>/dev/null || sudo sed -i '/PHP_CHECK_PDO_INCLUDES/d' config.m4 + fi + lib_arch=$(gcc -dumpmachine) + lib_dir=/usr/lib/"$lib_arch" + if [ -d "$lib_dir" ]; then + sudo ln -sf "$lib_dir"/libfbclient.so.2 /usr/lib/libfbclient.so + sudo ln -sf "$lib_dir"/libib_util.so /usr/lib/ + fi +} diff --git a/src/scripts/extensions/patches/geos.sh b/src/scripts/extensions/patches/geos.sh new file mode 100644 index 0000000..170e1f4 --- /dev/null +++ b/src/scripts/extensions/patches/geos.sh @@ -0,0 +1,9 @@ +patch_geos() { + if [[ $(printf '%s\n%s\n' "${version:?}" "7.0" | sort -V | head -n1) == "7.0" ]]; then + sed -i~ -e "s/, ce->name/, ZSTR_VAL(ce->name)/; s/ulong /zend_ulong /" geos.c + fi + get -q -n /tmp/php8.patch https://git.remirepo.net/cgit/rpms/php/php-geos.git/plain/0003-add-all-arginfo-and-fix-build-with-PHP-8.patch + get -q -n /tmp/toString.patch https://git.remirepo.net/cgit/rpms/php/php-geos.git/plain/0006-fix-__toString-with-8.2.patch + patch -p1 < /tmp/php8.patch 2>/dev/null || true + patch -p1 < /tmp/toString.patch 2>/dev/null || true +} diff --git a/src/scripts/extensions/patches/http.sh b/src/scripts/extensions/patches/http.sh new file mode 100644 index 0000000..ca8bfac --- /dev/null +++ b/src/scripts/extensions/patches/http.sh @@ -0,0 +1,11 @@ +patch_pecl_http() { + if [ "$(uname -s)" = 'Darwin' ] && ! [[ ${version:?} =~ ${old_versions:?} ]]; then + if [[ ${version:?} =~ 5.6|7.[0-4] ]]; then + sed -i '' -e "s|ext/propro|$(brew --prefix propro@"${version:?}")/include/php/ext/propro@${version:?}|" "./src/php_http_api.h" + fi + sed -i '' -e "s|ext/raphf|$(brew --prefix raphf@"${version:?}")/include/php/ext/raphf@${version:?}|" "./src/php_http_api.h" + if [ "${version:?}" = "5.6" ]; then + sed -i '' -e "s|\$abs_srcdir|\$abs_srcdir ${brew_prefix:?}/include|" -e "s|/ext/propro|/php/ext/propro@5.6|" -e "s|/ext/raphf|/php/ext/raphf@5.6|" "./config9.m4" + fi + fi +} diff --git a/src/scripts/extensions/patches/pdo_oci.sh b/src/scripts/extensions/patches/pdo_oci.sh new file mode 100644 index 0000000..e353b2e --- /dev/null +++ b/src/scripts/extensions/patches/pdo_oci.sh @@ -0,0 +1,9 @@ +patch_pdo_oci() { + get -q -n config.m4 https://raw.githubusercontent.com/php/php-src/PHP-8.0/ext/pdo_oci/config.m4 + if [[ $(printf '%s\n%s\n' "${version:?}" "8.5" | sort -V | head -n1) == "8.5" ]]; then + get -q -n pdo_oci.c https://raw.githubusercontent.com/shivammathur/pecl-database-pdo_oci/a9cf2c53b6de46f9e5f523bcd11fd344e3beeb85/pdo_oci.c + fi + if [[ ${version:?} =~ 5.[3-6] ]]; then + sudo sed -i '' "/PHP_CHECK_PDO_INCLUDES/d" config.m4 2>/dev/null || sudo sed -i "/PHP_CHECK_PDO_INCLUDES/d" config.m4 + fi +} diff --git a/src/scripts/extensions/patches/pdo_sqlsrv.sh b/src/scripts/extensions/patches/pdo_sqlsrv.sh new file mode 100644 index 0000000..89feaf5 --- /dev/null +++ b/src/scripts/extensions/patches/pdo_sqlsrv.sh @@ -0,0 +1,5 @@ +if [[ $(printf '%s\n%s\n' "${version:?}" "8.5" | sort -V | head -n1) == "8.5" ]]; then + sed -i.bak -e 's/zval_ptr_dtor( &dbh->query_stmt_zval );/OBJ_RELEASE(dbh->query_stmt_obj);dbh->query_stmt_obj = NULL;/' php_pdo_sqlsrv_int.h + sed -i.bak -e 's/pdo_error_mode prev_err_mode/uint8_t prev_err_mode/g' pdo_dbh.cpp + rm -rf *.bak +fi diff --git a/src/scripts/extensions/patches/phpize.sh b/src/scripts/extensions/patches/phpize.sh new file mode 100644 index 0000000..35059f6 --- /dev/null +++ b/src/scripts/extensions/patches/phpize.sh @@ -0,0 +1,27 @@ +# Function to get phpize location on darwin. +get_phpize() { + if [[ "${version:?}" =~ 5.[3-5] ]]; then + echo '/opt/local/bin/phpize' + else + [ -n "$brew_prefix" ] && phpize_dir="$brew_prefix" || phpize_dir="/usr/local/bin" + echo "${phpize_dir}/bin/$(readlink ${phpize_dir}/bin/phpize)" + fi +} + +# Function to patch phpize to link to php headers on darwin. +patch_phpize() { + if [ "$(uname -s)" = "Darwin" ]; then + sudo cp "$phpize_orig" "$phpize_orig.bck" + sudo sed -i '' 's~includedir=.*~includedir="$(xcrun --show-sdk-path)/usr/include/php"~g' "$phpize_orig" + fi +} + +# Function to restore phpize. +restore_phpize() { + if [ "$os" = "Darwin" ]; then + sudo mv "$phpize_orig.bck" "$phpize_orig" || true + fi +} + +os="$(uname -s)" +phpize_orig="$(get_phpize)" diff --git a/src/scripts/extensions/patches/protobuf.sh b/src/scripts/extensions/patches/protobuf.sh new file mode 100644 index 0000000..1289115 --- /dev/null +++ b/src/scripts/extensions/patches/protobuf.sh @@ -0,0 +1,4 @@ +patch_protobuf() { + mkdir -p third_party/wyhash + cp ../../../../third_party/wyhash/* third_party/wyhash +} diff --git a/src/scripts/extensions/phalcon.ps1 b/src/scripts/extensions/phalcon.ps1 new file mode 100644 index 0000000..f442d48 --- /dev/null +++ b/src/scripts/extensions/phalcon.ps1 @@ -0,0 +1,128 @@ +# Function to get the url of the phalcon release asset. +Function Get-PhalconReleaseAssetUrl() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $Semver + ) + $domain = 'https://api.github.com/repos' + $releases = 'phalcon/cphalcon/releases' + $match = $null + if($extension_version -match '[3-4]') { + $nts = if (!$installed.ThreadSafe) { "_nts" } else { "" } + try { + $match = (Invoke-RestMethod -Uri "$domain/$releases/tags/v$Semver").assets | Select-String -Pattern "browser_download_url=.*(phalcon_${arch}_.*_php${version}_${extension_version}.*[0-9]${nts}.zip)" + } catch { } + if($null -eq $match) { + try { + $match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(phalcon_${arch}_.*_php${version}_${extension_version}.*[0-9]${nts}.zip)" + } catch { } + } + } else { + $nts = if (!$installed.ThreadSafe) { "-nts" } else { "-ts" } + try { + $match = (Invoke-RestMethod -Uri "$domain/$releases/tags/v$Semver").assets | Select-String -Pattern "browser_download_url=.*(php_phalcon-php${version}${nts}-windows.*-x64.zip)" + } catch { } + if($null -eq $match) { + try { + $match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(php_phalcon-php${version}${nts}-windows.*-x64.zip)" + } catch { } + } + if($null -eq $match) { + try { + $match = (Invoke-RestMethod -Uri "$domain/$releases/tags/v$Semver").assets | Select-String -Pattern "browser_download_url=.*(phalcon-php${version}${nts}-windows.*-x64.zip)" + } catch { } + } + if($null -eq $match) { + try { + $match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(phalcon-php${version}${nts}-windows.*-x64.zip)" + } catch { } + } + } + if($NULL -ne $match) { + return "$github/$releases/download/v$Semver/$($match.Matches[0].Groups[1].Value)" + } + return false; +} + +# Function to add phalcon using GitHub releases. +Function Add-PhalconFromGitHub() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $Semver + ) + $zip_url = Get-PhalconReleaseAssetUrl $Semver + if($zip_url) { + Get-File -Url $zip_url -OutFile $ENV:RUNNER_TOOL_CACHE\phalcon.zip > $null 2>&1 + Expand-Archive -Path $ENV:RUNNER_TOOL_CACHE\phalcon.zip -DestinationPath $ENV:RUNNER_TOOL_CACHE\phalcon -Force > $null 2>&1 + Copy-Item -Path "$ENV:RUNNER_TOOL_CACHE\phalcon\php_phalcon.dll" -Destination "$ext_dir\php_phalcon.dll" + Enable-PhpExtension -Extension phalcon -Path $php_dir + } else { + throw "Unable to get Phalcon release from the GitHub release" + } +} + +# Function to get phalcon semver. +Function Get-PhalconSemver() { + if($extension_version -eq '3') { + return '3.4.5' + } elseif (($extension_version -eq '4') -and ($version -eq '7.2')) { + return '4.1.0' + } elseif (($extension_version -eq '5') -and ($version -eq '7.4')) { + return '5.4.0' + } + return Get-PeclPackageVersion phalcon $extension_version stable stable | Select-Object -First 1 +} + +# Function to install phalcon +Function Add-PhalconHelper() { + $semver = Get-PhalconSemver + if ($extension_version -eq '3') { + Add-PhalconFromGitHub $semver + } else { + Add-Extension -Extension phalcon -Stability stable -Extension_version $semver + } +} + +# Function to add phalcon +Function Add-Phalcon() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateSet('phalcon3', 'phalcon4', 'phalcon5')] + [string] + $extension + ) + try { + $status = 'Enabled' + $extension_version = $extension.substring($extension.Length - 1) + + if($extension_version -eq '4') { + if (Test-Path $ext_dir\php_psr.dll) { + Enable-PhpExtension -Extension psr -Path $php_dir + } else { + Install-Phpextension -Extension psr -MinimumStability stable -Path $php_dir + } + } + + if(Test-Path $ext_dir\php_phalcon.dll) { + $phalcon = Get-PhpExtension $ext_dir\php_phalcon.dll + if($phalcon.Version[0] -eq $extension_version) { + Enable-PhpExtension -Extension phalcon -Path $php_dir + } else { + $status = 'Installed and enabled' + Remove-Item $ext_dir\php_phalcon.dll + Add-PhalconHelper + } + } else { + $status = 'Installed and enabled' + Add-PhalconHelper + } + Add-Log $tick $extension $status + } catch [Exception] { + Add-Log $cross $extension "Could not install $extension on PHP $($installed.FullVersion)" + } +} diff --git a/src/scripts/extensions/phalcon.sh b/src/scripts/extensions/phalcon.sh new file mode 100644 index 0000000..9f678fb --- /dev/null +++ b/src/scripts/extensions/phalcon.sh @@ -0,0 +1,100 @@ +# Helper function to get phalcon version +get_phalcon_version() { + if [ "$extension" = "phalcon5" ]; then + if [ "${version:?}" = "7.4" ]; then + echo '5.4.0' + else + get_pecl_version phalcon stable 5 + fi + elif [ "$extension" = "phalcon4" ]; then + echo '4.1.2' + elif [ "$extension" = "phalcon3" ]; then + echo '3.4.5' + fi +} + +# Function to add phalcon from repo. +add_phalcon_from_repo(){ + version=${version:?} + if [ "$extension" = "phalcon5" ]; then + PHALCON_PATH=build/phalcon + else + PHALCON_PATH=build/php"${version%.*}"/64bits + fi + PHALCON_CONFIGURE_OPTS="--enable-phalcon --with-php-config=$(command -v php-config)" + export PHALCON_PATH + export PHALCON_CONFIGURE_OPTS + add_extension_from_source phalcon https://github.com phalcon cphalcon v"$(get_phalcon_version)" extension +} + +# Helper function to add phalcon. +add_phalcon_helper() { + status='Installed and enabled' + if [ "$(uname -s)" = "Darwin" ]; then + add_brew_extension "$extension" extension + else + package="php${version:?}-$extension" + add_ppa ondrej/php >/dev/null 2>&1 || update_ppa ondrej/php + [[ "$extension" =~ phalcon[4|5] ]] && (install_packages "php${version:?}-psr" || pecl_install psr || pecl_install psr-1.1.0) + (check_package "$package" && install_packages "$package") || pecl_install phalcon-"$(get_phalcon_version)" || add_phalcon_from_repo + fi +} + +# Function to add phalcon3. +add_phalcon3() { + if shared_extension phalcon; then + phalcon_version=$(php -d="extension=phalcon.so" -r "echo phpversion('phalcon');" | cut -d'.' -f 1) + if [ "$phalcon_version" != "$extension_major_version" ]; then + add_phalcon_helper + else + enable_extension phalcon extension + fi + else + add_phalcon_helper + fi +} + +# Function to add phalcon4. +add_phalcon4() { + enable_extension psr extension + if shared_extension phalcon; then + if check_extension psr; then + phalcon_version=$(php -d="extension=phalcon" -r "echo phpversion('phalcon');" | cut -d'.' -f 1) + if [ "$phalcon_version" != "$extension_major_version" ]; then + add_phalcon_helper + else + enable_extension phalcon extension + fi + else + add_phalcon_helper + fi + else + add_phalcon_helper + fi +} + +# Function to add phalcon5. +add_phalcon5() { + if shared_extension phalcon; then + phalcon_version=$(php -d="extension=phalcon.so" -r "echo phpversion('phalcon');" | cut -d'.' -f 1) + if [ "$phalcon_version" != "$extension_major_version" ]; then + add_phalcon_helper + else + enable_extension phalcon extension + fi + else + add_phalcon_helper + fi +} + +# Function to add phalcon. +add_phalcon() { + local extension=$1 + status='Enabled' + [ "$extension" = "phalcon" ] && extension=phalcon5 + extension_major_version=${extension: -1} + if [[ "$extension_major_version" =~ [3-5] ]]; then + add_phalcon"$extension_major_version" >/dev/null 2>&1 + fi + add_extension_log "phalcon" "$status" +} diff --git a/src/scripts/extensions/relay.sh b/src/scripts/extensions/relay.sh new file mode 100644 index 0000000..08f0abe --- /dev/null +++ b/src/scripts/extensions/relay.sh @@ -0,0 +1,158 @@ +# Get relay version +get_relay_version() { + local ext=$1 + if [[ "$ext" =~ ^relay$ ]]; then + get -s -n "" "${relay_release:?}" + elif [[ $ext =~ ^relay-nightly$ ]]; then + echo "dev" + else + relay_version="${ext##*-}" + echo "v${relay_version/v//}" + fi +} + +# Get OS suffix in relay artifact URL. +get_os_suffix() { + if [ "$os" = "Linux" ]; then + if [[ "$ID" =~ ubuntu|debian ]]; then + echo debian + elif [ "$ID" = "centos" ]; then + echo centos"$VERSION_ID" + else + echo "$ID" + fi + else + echo darwin + fi +} + +# Get openssl suffix in relay artifact URL. +get_openssl_suffix() { + openssl_3=$(php -r "echo strpos(OPENSSL_VERSION_TEXT, 'SSL 3') !== false;") + [ "$openssl_3" = "1" ] && echo '+libssl3' || echo '' +} + +# Change library paths in relay binary. +change_library_paths() { + if [ "$os" = "Darwin" ]; then + otool -L "${ext_dir:?}"/relay.so | grep -q 'ssl.1' && openssl_version='1.1' || openssl_version='3' + [ -e "${brew_prefix:?}"/opt/openssl@"$openssl_version" ] || { + safe_brew install --skip-link openssl@"$openssl_version" && + brew link --overwrite --force openssl@"$openssl_version" + } + dylibs="$(otool -L "${ext_dir:?}"/relay.so | grep -Eo '.*\.dylib' | cut -f1 -d ' ')" + install_name_tool -change "$(echo "${dylibs}" | grep -E "libzstd.*dylib" | xargs)" "$brew_prefix"/opt/zstd/lib/libzstd.dylib "$ext_dir"/relay.so + install_name_tool -change "$(echo "${dylibs}" | grep -E "liblz4.*dylib" | xargs)" "$brew_prefix"/opt/lz4/lib/liblz4.dylib "$ext_dir"/relay.so + install_name_tool -change "$(echo "${dylibs}" | grep -E "libssl.*dylib" | xargs)" "$brew_prefix"/opt/openssl@"$openssl_version"/lib/libssl.dylib "$ext_dir"/relay.so + install_name_tool -change "$(echo "${dylibs}" | grep -E "libcrypto.*dylib" | xargs)" "$brew_prefix"/opt/openssl@"$openssl_version"/lib/libcrypto.dylib "$ext_dir"/relay.so + install_name_tool -change "$(echo "${dylibs}" | grep -E "libck.*dylib" | xargs)" "$brew_prefix"/opt/concurrencykit/lib/libck.dylib "$ext_dir"/relay.so + fi +} + +# Add relay dependencies +add_relay_dependencies() { + add_extension json + add_extension msgpack + add_extension igbinary + if [ "$os" = "Darwin" ]; then + . "${0%/*}"/tools/brew.sh + configure_brew + safe_brew install lz4 hiredis zstd concurrencykit + fi +} + +# Initialize relay extension ini configuration +init_relay_ini() { + relay_ini=$1 + if [ -e "$relay_ini" ]; then + if [[ -n "$RELAY_KEY" ]]; then + sudo sed -i.bak "s/^; relay.key =.*/relay.key = $RELAY_KEY/" "$relay_ini" + fi + if [[ -n "$RELAY_ENVIRONMENT" ]]; then + sudo sed -i.bak "s/^; relay.environment =.*/relay.environment = $RELAY_ENVIRONMENT/" "$relay_ini" + fi + if [[ -n "$RELAY_EVICTION_POLICY" ]]; then + sudo sed -i.bak "s/^; relay.eviction_policy =.*/relay.eviction_policy = $RELAY_EVICTION_POLICY/" "$relay_ini" + fi + if [[ -n "$RELAY_MAX_MEMORY" ]]; then + sudo sed -i.bak "s/^; relay.maxmemory =.*/relay.maxmemory = $RELAY_MAX_MEMORY/" "$relay_ini" + fi + sudo rm -rf "$relay_ini".bak + fi +} + +# Enable relay extension +enable_relay() { + relay_ini=$1 + if [ -e "$relay_ini" ]; then + init_relay_ini "$relay_ini" + if [ "$os" = "Linux" ]; then + sudo cp "$relay_ini" "${ini_dir:?}"/../mods-available/relay.ini + sudo phpenmod -v "${version:?}" relay + else + sudo cp "${relay_ini}" "${scan_dir:?}"/60-relay.ini + fi + fi +} + +# Patch binary id in relay extension +init_relay_binary_id() { + if [ -e "${ext_dir:?}"/relay.so ]; then + sudo LC_ALL=C sed -i.bak "s/00000000-0000-0000-0000-000000000000/$(uuidgen)/" "$ext_dir"/relay.so || true + fi +} + +# Configure relay extension +configure_relay() { + change_library_paths + init_relay_binary_id + enable_relay "${ext_dir}"/relay.ini +} + +# Helper function to add relay extension +add_relay_helper() { + local arch=$1 + os_suffix="$(get_os_suffix)" + openssl_suffix="$(get_openssl_suffix)" + artifact_file_name="relay-$relay_version-php${version:?}-$os_suffix-$arch$openssl_suffix.tar.gz" + url="$relay_trunk"/"$relay_version"/"$artifact_file_name" + get -q -n /tmp/relay.tar.gz "$url" + if (! [ -e /tmp/relay.tar.gz ] || ! file /tmp/relay.tar.gz | grep -q 'gzip'); then + if [ "$openssl_suffix" = '+libssl3' ]; then + get -q -n /tmp/relay.tar.gz "${url/+libssl3/}" + else + get -q -n /tmp/relay.tar.gz "${url/.tar/+libssl3.tar}" + fi + fi + if [ -e /tmp/relay.tar.gz ] && file /tmp/relay.tar.gz | grep -q 'gzip'; then + sudo tar --strip-components=1 -xzf /tmp/relay.tar.gz -C "${ext_dir:?}" + sudo mv "${ext_dir:?}"/relay-pkg.so "${ext_dir:?}"/relay.so + fi +} + +# Add relay extension +add_relay() { + local ext=$1 + local arch + local url + local message + local error + os=$(uname -s) + arch="$(uname -m | sed 's/_/-/')" + relay_release=https://builds.r2.relay.so/meta/latest + relay_trunk=https://builds.r2.relay.so + if [[ "$arch" = "x86-64" && "$os" = "Darwin" ]]; then + error="Relay extension is not available for macOS x86_64 architecture" + else + relay_version=$(get_relay_version "$ext") + add_relay_dependencies >/dev/null 2>&1 + if shared_extension relay; then + message="Enabled" + else + add_relay_helper "$arch" >/dev/null 2>&1 + message="Installed and enabled ${relay_version}" + fi + configure_relay >/dev/null 2>&1 + fi + add_extension_log relay "$message" "$error" +} diff --git a/src/scripts/extensions/source.sh b/src/scripts/extensions/source.sh new file mode 100644 index 0000000..e89c7bb --- /dev/null +++ b/src/scripts/extensions/source.sh @@ -0,0 +1,183 @@ +os="$(uname -s)" +os_lower=$(echo "$os" | tr '[:upper:]' '[:lower:]') +os_capital=$(echo "$os" | tr '[:lower:]' '[:upper:]') + +# Function to parse extension environment variables +parse_args() { + local extension=${1%-*} + suffix=$(echo "$2" | tr '[:lower:]' '[:upper:]') + up_ext_name=$(echo "$extension" | tr '[:lower:]' '[:upper:]') + var="${extension}_${suffix}" + up_var="${up_ext_name}_${suffix}" + ! [[ "$suffix" =~ .*PREFIX|LIBS|PATH.* ]] && hyp='-' + output=$(echo "${!var} ${!up_var}" | sed "s/, *$hyp/ $hyp/g" | sed -E "s/^,|,$//g") + echo "$output" | xargs -n 1 | sort | uniq | xargs +} + +# Function to parse configure options for pecl +# Make sure we have all options in name="value" form i.e XML properties. +parse_pecl_configure_options() { + configure_opts=$(echo "$1" | sed -E -e "s#['\"]|--##g") + IFS=' ' read -r -a opts_array <<< "$configure_opts" + output_opts=() + for opt in "${opts_array[@]}"; do + [ "${opt##*=}" != "${opt%=*}" ] && value="${opt##*=}" || value=yes + output_opts+=("${opt%=*}=\"$value\"") + done + echo "${output_opts[@]}" +} + +# Function to log if a library is installed +add_lib_log() { + local lib=$1 + if check_lib "$lib"; then + add_log "${tick:?}" "$lib" "Installed" + else + add_log "${cross:?}" "$lib" "Could not install $lib" + fi +} + +# Function to check if a library is installed +check_lib() { + local lib=$1 + if [ "$os" = "Linux" ]; then + [ "x$(dpkg -s "$lib" 2>/dev/null | grep Status)" != "x" ] + else + [ "x$(find "${brew_prefix:?}"/Cellar -maxdepth 1 -name "$lib")" != "x" ] + fi +} + +# Function to add a library on linux +add_linux_libs() { + local lib=$1 + if ! check_lib "$lib"; then + install_packages "$lib" >/dev/null 2>&1 || true + fi + add_lib_log "$lib" +} + +# Function to add a library on macOS +add_darwin_libs() { + local lib=$1 + if ! check_lib "$lib"; then + if [[ "$lib" = *@* ]]; then + safe_brew install --skip-link "$lib" >/dev/null 2>&1 || true + brew link --overwrite --force "$lib" >/dev/null 2>&1 || true + else + safe_brew install "$lib" >/dev/null 2>&1 || true + fi + fi + add_lib_log "$lib" +} + +# Function to add required libraries +add_libs() { + local all_libs=("$@") + for lib in "${all_libs[@]}"; do + if [ "$os" = "Linux" ]; then + add_linux_libs "$lib" + else + add_darwin_libs "$lib" + fi + done +} + +# Function to get required libraries for an extension +get_libraries() { + local extension=$1 + { + parse_args "$extension" LIBS + parse_args "$extension" "$os_capital"_LIBS + [ -r "${src:?}/configs/${os_lower}_libs" ] && \ + grep -E "^[[:space:]]*${extension}[[:space:]]*=" "${src:?}/configs/${os_lower}_libs" | \ + head -n1 | \ + sed -E "s/^[[:space:]]*${extension}[[:space:]]*=[[:space:]]*//" + } | xargs -n 1 2>/dev/null | sort -u | xargs 2>/dev/null +} + +# Function to run command in a group +run_group() { + local command=$1 + local log=$2 + echo "$command" | sudo tee ./run_group.sh >/dev/null 2>&1 + echo "$GROUP$log" + . ./run_group.sh + local status=$? + rm ./run_group.sh + echo "$END_GROUP" + return $status +} + +patch_extension() { + local extension=$1 + # shellcheck source=. + . "${scripts:?}"/extensions/patches/common.sh + if [ -e "${scripts:?}"/extensions/patches/"$extension".sh ]; then + # shellcheck source=. + . "${scripts:?}"/extensions/patches/"$extension".sh + patch_"${extension}" + fi +} + +fetch_extension() { + local extension=$1 + local fetch=$2 + if [ "$fetch" = "clone" ]; then + run_group "git clone -nv $url/$org/$repo /tmp/$repo-$release" "git clone" + cd /tmp/"$repo-$release" || exit 1 + git checkout -q "$release" + cd "$sub_dir" || exit 1 + if [ -e .gitmodules ]; then + jobs="$(grep -c "\[submodule" .gitmodules)" + run_group "git submodule update --jobs $jobs --init --recursive" "git submodule" + fi + elif [ "$fetch" = "get" ]; then + get -q -n /tmp/"$extension".tar.gz "$url/$org/$repo/archive/$release.tar.gz" + tar -xzf /tmp/"$extension".tar.gz -C /tmp + cd /tmp/"$repo"-"$release"/"$sub_dir" || exit + elif [ "$fetch" = "pecl" ]; then + source="pecl" + pecl_name=${extension/http/pecl_http} + capital_pecl_name=$(echo "$pecl_name" | tr '[:lower:]' '[:upper:]') + get -q -n /tmp/"$pecl_name".tgz https://pecl.php.net/get/"$pecl_name"-"$release".tgz https://pecl.php.net/get/"$capital_pecl_name"-"$release".tgz + tar -xzf /tmp/"$pecl_name".tgz -C /tmp + cd /tmp/"$pecl_name"-"$release" 2>/dev/null || cd /tmp/"$capital_pecl_name"-"$release" 2>/dev/null || exit + fi +} + +# Function to install extension from a git repository +add_extension_from_source() { + local extension="${1/pecl_/}" + local url=$2 + local org=$3 + local repo=$4 + local release=$5 + local prefix=$6 + local fetch=${7:-clone} + slug="$extension-$release" + source="$url/$org/$repo" + libraries="$(get_libraries "$extension")" + opts="$(parse_args "$extension" CONFIGURE_OPTS)" + prefix_opts="$(parse_args "$extension" CONFIGURE_PREFIX_OPTS)" + suffix_opts="$(parse_args "$extension" CONFIGURE_SUFFIX_OPTS)" + sub_dir="$(parse_args "$extension" PATH)" + step_log "Setup $slug" + ( + add_devtools phpize >/dev/null 2>&1 + disable_extension_helper "$extension" + fetch_extension "$extension" "$fetch" + if ! [ "$(find . -maxdepth 1 -name '*.m4' -exec grep -H 'PHP_NEW_EXTENSION' {} \; | wc -l)" != "0" ]; then + add_log "${cross:?}" "$source" "$source does not have a PHP extension" + else + [[ -n "${libraries// }" ]] && run_group "add_libs $libraries" "add libraries" + [ "${debug:?}" = "debug" ] && suffix_opts="$suffix_opts --enable-debug" + patch_extension "$extension" >/dev/null 2>&1 + run_group "phpize" "phpize" && \ + run_group "sudo $prefix_opts ./configure $suffix_opts $opts" "configure" && \ + run_group "sudo $prefix_opts make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)" "make" && \ + run_group "sudo make install" "make install" && \ + enable_extension "$extension" "$prefix" + fi + ) + add_extension_log "$slug" "Installed from $source and enabled" +} diff --git a/src/scripts/extensions/sqlsrv.ps1 b/src/scripts/extensions/sqlsrv.ps1 new file mode 100644 index 0000000..a35de62 --- /dev/null +++ b/src/scripts/extensions/sqlsrv.ps1 @@ -0,0 +1,80 @@ +# Function to get sqlsrv extension version. +Function Get-SqlsrvReleaseVersion() { + if ($version -le '7.2') { + # Use the releases from PECL for these versions + return null; + } elseif($version -eq '7.3') { + return '5.9.0' + } elseif ($version -eq '7.4') { + return '5.10.1' + } elseif ($version -eq '8.0') { + return '5.11.1' + } elseif ($version -match '8.[1-2]') { + return '5.12.0' + } else { + return 'latest' + } +} + +# Function to get sqlsrv extension release URL. +Function Get-SqlsrvReleaseUrl() +{ + $extensionVersion = Get-SqlsrvReleaseVersion + if($extensionVersion) { + $repo = "$github/microsoft/msphpsql" + if($extensionVersion -eq 'latest') { + return "$repo/releases/latest/download/Windows-$version.zip" + } else { + return "$repo/releases/download/v$extensionVersion/Windows-$version.zip" + } + } +} + +# Function to add sqlsrv extension from GitHub. +Function Add-SqlsrvFromMSGithub() +{ + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + try { + $zipUrl = SqlsrvReleaseUrl + if($zipUrl) { + $nts = if (!$installed.ThreadSafe) { "nts" } else { "ts" } + $noDotVersion = $version.replace('.', '') + $extensionFilePath = "Windows-$version\$arch\php_${extension}_${noDotVersion}_${nts}.dll" + Get-File -Url $zipUrl -OutFile $ENV:RUNNER_TOOL_CACHE\sqlsrv.zip > $null 2>&1 + Expand-Archive -Path $ENV:RUNNER_TOOL_CACHE\sqlsrv.zip -DestinationPath $ENV:RUNNER_TOOL_CACHE\sqlsrv -Force > $null 2>&1 + Copy-Item -Path "$ENV:RUNNER_TOOL_CACHE\sqlsrv\$extensionFilePath" -Destination "$ext_dir\php_$extension.dll" + Enable-PhpExtension -Extension $extension -Path $php_dir + } + } catch { } +} + +# Function to add sqlsrv extension. +Function Add-Sqlsrv() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + $status = 'Enabled' + if (Test-Path $ext_dir\php_$extension.dll) { + Enable-PhpExtension -Extension $extension -Path $php_dir + } else { + try { + Add-ExtensionFromGithub $extension > $null 2>&1 + } catch {} + if (-not(Test-Extension $extension)) { + Add-SqlsrvFromMSGithub $extension >$null 2>&1 + } + if (-not(Test-Extension $extension)) { + Add-Extension $extension >$null 2>&1 + } + $status = 'Installed and enabled' + } + Add-ExtensionLog $extension $status +} diff --git a/src/scripts/extensions/sqlsrv.sh b/src/scripts/extensions/sqlsrv.sh new file mode 100644 index 0000000..4976bdf --- /dev/null +++ b/src/scripts/extensions/sqlsrv.sh @@ -0,0 +1,27 @@ +# Function to get sqlsrv and pdo_sqlsrv version. +get_sqlsrv_version() { + if [[ "${version:?}" =~ 7.[0-3] ]]; then + echo '5.9.0' + elif [[ "${version:?}" =~ 7.4 ]]; then + echo '5.10.1' + elif [[ "${version:?}" =~ 8.0 ]]; then + echo '5.11.1' + elif [[ "${version:?}" =~ 8.[1-2] ]]; then + echo '5.12.0' + else + # Return an empty string so that pecl will install the latest version. + echo '' + fi +} + +# Function to install sqlsrv and pdo_sqlsrv. +add_sqlsrv() { + ext=$1 + ext_version=$(get_sqlsrv_version) + if [ "$(uname -s)" = 'Linux' ]; then + install_packages unixodbc-dev + add_pecl_extension "$ext" "$ext_version" extension + else + add_brew_extension "$ext" extension + fi +} diff --git a/src/scripts/extensions/zephir_parser.ps1 b/src/scripts/extensions/zephir_parser.ps1 new file mode 100644 index 0000000..75b6a1e --- /dev/null +++ b/src/scripts/extensions/zephir_parser.ps1 @@ -0,0 +1,87 @@ +# Function to get the url of the phalcon release asset. +Function Get-ZephirParserReleaseAssetUrl() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension_version + ) + $repo = 'zephir-lang/php-zephir-parser' + $zp_releases = "$github/$repo/releases" + $nts = if (!$installed.ThreadSafe) { "nts" } else { "ts" } + try { + $match = (Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/tags/$extension_version").assets | Select-String -Pattern "browser_download_url=.*(zephir_parser-php-${version}-$nts-windows.*.zip)" + } catch { + $match = (Get-File -Url "$zp_releases/expanded_assets/$extension_version").Links.href | Select-String -Pattern "(zephir_parser-php-${version}-$nts-windows.*.zip)" + } + if($NULL -ne $match) { + return "$zp_releases/download/$extension_version/$($match.Matches[0].Groups[1].Value)" + } + return false; +} + +# Function to get zephir parser version using GitHub releases. +Function Get-ZephirParserVersion() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + $repo = 'zephir-lang/php-zephir-parser' + $zp_releases = "$github/$repo/releases" + if($extension -eq 'zephir_parser') { + if($version -lt '7.2') { + return 'v1.6.1' + } + return (Get-File -Url $zp_releases/latest).BaseResponse.RequestMessage.RequestUri.Segments[-1] + } else { + return 'v' + ($extension.split('-')[1] -replace 'v') + } +} + +# Function to add zephir parser using GitHub releases. +Function Add-ZephirParserFromGitHub() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + $extension_version = Get-ZephirParserVersion $extension + $zip_url = Get-ZephirParserReleaseAssetUrl $extension_version + if($zip_url) { + Get-File -Url $zip_url -OutFile $ENV:RUNNER_TOOL_CACHE\zp.zip > $null 2>&1 + Expand-Archive -Path $ENV:RUNNER_TOOL_CACHE\zp.zip -DestinationPath $ENV:RUNNER_TOOL_CACHE\zp -Force > $null 2>&1 + Copy-Item -Path "$ENV:RUNNER_TOOL_CACHE\zp\php_zephir_parser.dll" -Destination "$ext_dir\php_zephir_parser.dll" + Enable-PhpExtension -Extension zephir_parser -Path $php_dir + } else { + throw "Unable to get zephir_parser release from the GitHub repo" + } +} + +# Function to add zephir parser. +Function Add-ZephirParser() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension + ) + try { + $status = 'Enabled' + if (Test-Path $ext_dir\php_zephir_parser.dll) { + Enable-PhpExtension -Extension zephir_parser -Path $php_dir + } else { + $status = 'Installed and enabled' + try { + Add-ZephirParserFromGitHub $extension + } catch { + Add-Extension $extension >$null 2>&1 + } + } + Add-ExtensionLog zephir_parser $status + } catch { + Add-Log $cross $extension "Could not install $extension on PHP $($installed.FullVersion)" + } +} \ No newline at end of file diff --git a/src/scripts/extensions/zephir_parser.sh b/src/scripts/extensions/zephir_parser.sh new file mode 100644 index 0000000..af8887d --- /dev/null +++ b/src/scripts/extensions/zephir_parser.sh @@ -0,0 +1,42 @@ +# Get zephir_parser version +get_zephir_parser_version() { + local ext=$1 + if [[ "$ext" =~ ^zephir_parser$ ]]; then + get -s -n "" "${zp_releases:?}"/latest 2<&1 | grep -m 1 -Eo "tag/(v?[0-9]+(\.[0-9]+)?(\.[0-9]+)?)" | head -n 1 | cut -d '/' -f 2 + else + zp_version="${ext##*-}" + echo "v${zp_version/v//}" + fi +} + +# Add zephir_parser helper +add_zephir_parser_helper() { + local ext=$1 + nts="${ts:?}" && nts="${nts/z/}" + ext_version=$(get_zephir_parser_version "$ext") + [ "$(uname -s)" = "Linux" ] && os_suffix=ubuntu || os_suffix=macos + build_name=$(get -s -n "" https://api.github.com/repos/"$repo"/releases/tags/"$ext_version" | grep -Eo "zephir_parser-php-${version:?}-$nts-$os_suffix-.*.zip" | head -n 1) + [ -z "$build_name" ] && build_name=$(get -s -n "" "$zp_releases"/expanded_assets/"$ext_version" | grep -Eo "zephir_parser-php-${version:?}-$nts-$os_suffix-.*.zip" | head -n 1) + if [ -n "$build_name" ]; then + get -q -e "/tmp/zp.zip" "$zp_releases"/download/"$ext_version"/"$build_name" + sudo unzip -o "/tmp/zp.zip" -d "${ext_dir:?}" + enable_extension zephir_parser extension + else + pecl_install zephir_parser + fi +} + +# Add zephir_parser +add_zephir_parser() { + ext=$1 + repo=zephir-lang/php-zephir-parser + zp_releases=https://github.com/"$repo"/releases + if ! shared_extension zephir_parser; then + message='Installed and enabled' + add_zephir_parser_helper "$ext" >/dev/null 2>&1 + else + message='Enabled' + enable_extension zephir_parser extension + fi + add_extension_log zephir_parser "$message" +} \ No newline at end of file diff --git a/src/scripts/linux.sh b/src/scripts/linux.sh new file mode 100644 index 0000000..9276484 --- /dev/null +++ b/src/scripts/linux.sh @@ -0,0 +1,353 @@ +# Function to add sudo +add_sudo() { + if ! command -v sudo >/dev/null; then + check_package sudo || apt-get update + apt-get install -y sudo || (apt-get update && apt-get install -y sudo) + fi +} + +# Function to link apt-fast to apt-get +link_apt_fast() { + if ! command -v apt-fast >/dev/null; then + sudo ln -sf /usr/bin/apt-get /usr/bin/apt-fast + trap "sudo rm -f /usr/bin/apt-fast 2>/dev/null" exit + fi +} + +# Function to setup environment for self-hosted runners. +self_hosted_helper() { + if ! command -v apt-fast >/dev/null; then + sudo ln -sf /usr/bin/apt-get /usr/bin/apt-fast + trap "sudo rm -f /usr/bin/apt-fast 2>/dev/null" exit + fi + sudo mkdir -p /opt/hostedtoolcache >/dev/null 2>&1 || true + install_packages apt-transport-https ca-certificates curl file make jq unzip autoconf automake gcc g++ gnupg +} + +# Function to fix broken packages. +fix_broken_packages() { + sudo apt --fix-broken install >/dev/null 2>&1 +} + +# Function to install a package +install_packages() { + packages=("$@") + if ! [ -e /etc/dpkg/dpkg.cfg.d/force-confnew ]; then + echo "force-confnew" | sudo tee /etc/dpkg/dpkg.cfg.d/force-confnew >/dev/null 2>&1 + trap "sudo rm -f /etc/dpkg/dpkg.cfg.d/force-confnew 2>/dev/null" exit + fi + $apt_install "${packages[@]}" >/dev/null 2>&1 || (update_lists && fix_broken_packages && $apt_install "${packages[@]}" >/dev/null 2>&1) +} + +# Function to disable an extension. +disable_extension_helper() { + local extension=$1 + local disable_dependents=${2:-false} + get_extension_map + if [ "$disable_dependents" = "true" ]; then + disable_extension_dependents "$extension" + fi + sudo sed -Ei "/=(.*\/)?\"?$extension(.so)?\"?$/d" "${ini_file[@]}" "$pecl_file" + sudo find "$ini_dir"/.. -name "*-$extension.ini" -not -path "*phar.ini" -not -path "*pecl.ini" -not -path "*mods-available*" -delete >/dev/null 2>&1 || true + sudo rm -f /tmp/php"$version"_extensions + mkdir -p /tmp/extdisabled/"$version" + echo '' | sudo tee /tmp/extdisabled/"$version"/"$extension" >/dev/null 2>&1 +} + +# Function to add PDO extension. +add_pdo_extension() { + pdo_ext="pdo_$1" + if check_extension "$pdo_ext"; then + add_log "${tick:?}" "$pdo_ext" "Enabled" + else + ext=$1 + ext_name=$1 + if shared_extension pdo; then + disable_extension_helper pdo + echo "extension=pdo.so" | sudo tee "${ini_file[@]/php.ini/conf.d/10-pdo.ini}" >/dev/null 2>&1 + fi + if [ "$ext" = "mysql" ]; then + enable_extension "mysqlnd" "extension" + ext_name='mysqli' + elif [ "$ext" = "dblib" ]; then + ext_name="sybase" + elif [ "$ext" = "firebird" ]; then + install_packages libfbclient2 >/dev/null 2>&1 + enable_extension "pdo_firebird" "extension" + ext_name="interbase" + elif [ "$ext" = "sqlite" ]; then + ext="sqlite3" + ext_name="sqlite3" + fi + add_extension "$ext_name" "extension" >/dev/null 2>&1 + add_extension "$pdo_ext" "extension" >/dev/null 2>&1 + add_extension_log "$pdo_ext" "Enabled" + fi +} + +# Function to check if a package exists +check_package() { + apt-cache policy "$1" 2>/dev/null | grep -q 'Candidate' +} + +# Helper function to add an extension. +add_extension_helper() { + local extension=$1 + packages=(php"$version"-"$extension") + add_ppa ondrej/php >/dev/null 2>&1 || update_ppa ondrej/php + [ "${debug:?}" = "debug" ] && check_package php"$version"-"$extension"-dbgsym && packages+=(php"$version"-"$extension"-dbgsym) + (check_package "${packages[0]}" && install_packages "${packages[@]}") || pecl_install "$extension" + add_extension_log "$extension" "Installed and enabled" + sudo chmod 777 "${ini_file[@]}" +} + +# Function to setup phpize and php-config. +add_devtools() { + tool=$1 + if ! command -v "$tool$version" >/dev/null; then + install_packages "php$version-dev" + fi + switch_version "phpize" "php-config" + add_extension xml extension >/dev/null 2>&1 + add_log "${tick:?}" "$tool" "Added $tool $semver" +} + +# Function to setup PHP from the shivammathur/php-builder builds. +setup_php_builder() { + run_script "php-builder" "${runner:?}" "$version" "${debug:?}" "${ts:?}" +} + +# Function to setup PHP 5.3, PHP 5.4 and PHP 5.5. +setup_old_versions() { + run_script "php5-ubuntu" "$version" +} + +# Function to setup PHP from the cached builds. +setup_cached_versions() { + run_script "php-ubuntu" "$version" "${debug:?}" "${ts:?}" +} + +# Function to get the link path for an alternative. +alternative_link() { + case "$1" in + php-cgi-bin) echo "/usr/lib/cgi-bin/php" ;; + php-fpm) echo "/usr/sbin/php-fpm" ;; + php-fpm.sock) echo "/run/php/php-fpm.sock" ;; + *) echo "/usr/bin/$1" ;; + esac +} + +# Function to get the target path for an alternative. +alternative_target() { + case "$1" in + php-cgi-bin) echo "/usr/lib/cgi-bin/php$version" ;; + php-fpm) echo "/usr/sbin/php-fpm$version" ;; + php-fpm.sock) echo "/run/php/php$version-fpm.sock" ;; + *) echo "/usr/bin/$1$version" ;; + esac +} + +# Function to register an alternative if the versioned binary exists but is missing. +register_alternative() { + local tool=$1 + local link target priority state_file + target="$(alternative_target "$tool")" + [ -e "$target" ] || return 0 + state_file="/var/lib/dpkg/alternatives/$tool" + if sudo test -r "$state_file" && sudo grep -Fxq "$target" "$state_file"; then + return 0 + fi + link="$(alternative_link "$tool")" + priority="${version//./}" + sudo update-alternatives --install "$link" "$tool" "$target" "$priority" >/dev/null 2>&1 +} + +# Function to register and switch an alternative. +set_alternative() { + local tool=$1 + local target + target="$(alternative_target "$tool")" + [ -e "$target" ] || return 0 + register_alternative "$tool" || return 1 + sudo update-alternatives --set "$tool" "$target" >/dev/null 2>&1 +} + +# Function to add PECL. +add_pecl() { + add_devtools phpize >/dev/null 2>&1 + if ! command -v pecl >/dev/null; then + install_packages php-pear + fi + configure_pecl >/dev/null 2>&1 + pear_version=$(get_tool_version "pecl" "version") + add_log "${tick:?}" "PECL" "Added PECL $pear_version" +} + +# Function to switch versions of PHP binaries. +switch_version() { + tools=("$@") + to_wait=() + if ! (( ${#tools[@]} )); then + tools+=(php-cgi-bin php-fpm php-fpm.sock pear pecl php phar phar.phar php-cgi php-config phpize phpdbg) + fi + for tool in "${tools[@]}"; do + set_alternative "$tool" & + to_wait+=($!) + done + wait "${to_wait[@]}" +} + +# Function to get packages to install +get_php_packages() { + sed "s/[^ ]*/php$version-&/g" "$src"/configs/php_packages | tr '\n' ' ' + if [ "${debug:?}" = "debug" ]; then + sed "s/[^ ]*/php$version-&-dbgsym/g" "$src"/configs/php_debug_packages | tr '\n' ' ' + fi +} + +# Function to install packaged PHP +add_packaged_php() { + add_ppa ondrej/php >/dev/null 2>&1 || update_ppa ondrej/php + IFS=' ' read -r -a packages <<<"$(get_php_packages)" + install_packages "${packages[@]}" +} + +# Function to update PHP. +update_php() { + initial_version="$(php_semver)$(php_extra_version)" + add_php + updated_version="$(php_semver)$(php_extra_version)" + if [ "$updated_version" != "$initial_version" ]; then + status="Updated to" + else + status="Found" + fi +} + +# Function to install PHP. +add_php() { + if [ "${runner:?}" = "self-hosted" ] || [ "${use_package_cache:-true}" = "false" ]; then + if [[ "$version" =~ ${php_builder_versions:?} || "$ts" = "zts" ]]; then + setup_php_builder + else + add_packaged_php + switch_version >/dev/null 2>&1 + add_pecl + fi + elif [[ "$version" =~ ${old_versions:?} ]]; then + setup_old_versions + else + setup_cached_versions + fi + status="Installed" +} + +# Function to ini file for pear and link it to each SAPI. +link_pecl_file() { + echo '' | sudo tee "$pecl_file" >/dev/null 2>&1 + for file in "${ini_file[@]}"; do + sapi_scan_dir="$(realpath -m "$(dirname "$file")")/conf.d" + if [ "$sapi_scan_dir" != "$scan_dir" ] && ! [ -h "$sapi_scan_dir" ]; then + sudo mkdir -p "$sapi_scan_dir" + sudo ln -sf "$pecl_file" "$sapi_scan_dir/99-pecl.ini" + fi + done +} + +# Function to get extra version. +php_extra_version() { + if [ -e /etc/php/"$version"/COMMIT ]; then + echo " ($(cat "/etc/php/$version/COMMIT"))" + fi +} + +# Function to set php.ini +add_php_config() { + php_lib_dir=/usr/lib/php/"$version" + current_ini="$php_lib_dir"/php.ini-current + current=$(cat "$current_ini" 2>/dev/null) + if [ "$current" = "$ini" ]; then + return; + fi + if [[ "$ini" = "production" && "x$current" != "xproduction" ]]; then + echo "${ini_file[@]}" | xargs -n 1 -P 6 sudo cp "$php_lib_dir"/php.ini-production + if [ -e "$php_lib_dir"/php.ini-production.cli ]; then + sudo cp "$php_lib_dir"/php.ini-production.cli "$ini_dir"/php.ini + fi + elif [ "$ini" = "development" ]; then + echo "${ini_file[@]}" | xargs -n 1 -P 6 sudo cp "$php_lib_dir"/php.ini-development + elif [ "$ini" = "none" ]; then + echo '' | sudo tee "${ini_file[@]}" >/dev/null 2>&1 + fi + echo "$ini" | sudo tee "$current_ini" >/dev/null 2>&1 +} + +# Function to Setup PHP +setup_php() { + step_log "Setup PHP" + sudo mkdir -m 777 -p /var/run /run/php + php_config="$(command -v php-config)" + check_pre_installed + if [[ -z "$php_config" ]] || [ "$(php_semver | cut -c 1-3)" != "$version" ]; then + if [ ! -e "/usr/bin/php$version" ] || [ ! -e "/usr/bin/php-config$version" ]; then + add_php >/dev/null 2>&1 + else + if ! [[ "$version" =~ ${old_versions:?} ]]; then + switch_version >/dev/null 2>&1 + fi + if [ "${update:?}" = "true" ]; then + update_php >/dev/null 2>&1 + else + status="Switched to" + fi + fi + php_config="$(command -v php-config)" + else + if [ "$update" = "true" ]; then + update_php >/dev/null 2>&1 + else + status="Found" + fi + fi + if ! command -v php"$version" >/dev/null; then + add_log "${cross:?}" "PHP" "Could not setup PHP $version" + exit 1 + fi + ext_dir="/usr/$(grep -Po "extension_dir=..[^/]*/\K[^'\"]*" "$php_config")" + ini_dir="$(php_ini_path)" + scan_dir="$ini_dir"/conf.d + pecl_file="$scan_dir"/99-pecl.ini + semver="$(php_semver)" + extra_version="$(php_extra_version)" + export ext_dir + mapfile -t ini_file < <(sudo find "$ini_dir/.." -name "php.ini" -exec readlink -m {} +) + link_pecl_file + configure_php + set_output "php-version" "$semver" + sudo rm -rf /usr/local/bin/phpunit >/dev/null 2>&1 + sudo chmod 777 "${ini_file[@]}" "$pecl_file" "${tool_path_dir:?}" + sudo cp "$src"/configs/pm/*.json "$RUNNER_TOOL_CACHE/" + add_log "${tick:?}" "PHP" "$status PHP $semver$extra_version" +} + +# Variables +version=${1:-'8.5'} +ini=${2:-'production'} +src=${0%/*}/.. +debconf_fix="DEBIAN_FRONTEND=noninteractive" +apt_install="sudo $debconf_fix apt-fast install -y --no-install-recommends" +scripts="$src"/scripts + +add_sudo >/dev/null 2>&1 +link_apt_fast >/dev/null 2>&1 + +. /etc/os-release +# shellcheck source=. +. "${scripts:?}"/unix.sh +. "${scripts:?}"/tools/ppa.sh +. "${scripts:?}"/tools/add_tools.sh +. "${scripts:?}"/extensions/source.sh +. "${scripts:?}"/extensions/add_extensions.sh +read_env +self_hosted_setup +setup_php diff --git a/src/scripts/tools/add_tools.ps1 b/src/scripts/tools/add_tools.ps1 new file mode 100644 index 0000000..b65487c --- /dev/null +++ b/src/scripts/tools/add_tools.ps1 @@ -0,0 +1,373 @@ +# Variables +$composer_home = "$env:APPDATA\Composer" +$composer_bin = "$composer_home\vendor\bin" +$composer_json = "$composer_home\composer.json" +$composer_lock = "$composer_home\composer.lock" + +# Function to configure composer. +Function Edit-ComposerConfig() { + Param( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $tool_path + ) + Copy-Item $tool_path -Destination "$tool_path.phar" + php -r "try {`$p=new Phar('$tool_path.phar', 0);exit(0);} catch(Exception `$e) {exit(1);}" + if ($? -eq $False) { + Add-Log "$cross" "composer" "Could not download composer" + Write-Error "Could not download composer" -ErrorAction Stop + } + New-Item -ItemType Directory -Path $composer_bin -Force > $null 2>&1 + if (-not(Test-Path $composer_json)) { + Set-Content -Path $composer_json -Value "{}" + } + Set-ComposerEnv + Add-Path $composer_bin + Set-ComposerAuth +} + +# Function to update auth.json. +Function Update-AuthJson { + [CmdletBinding()] + param( + [Parameter(Mandatory)][string[]] $ComposerAuth + ) + if (Test-Path $composer_home\auth.json) { + try { + $existing = Get-Content $composer_home\auth.json -Raw | ConvertFrom-Json + } catch { + $existing = [PSCustomObject]@{} + } + } else { + $existing = [PSCustomObject]@{} + } + foreach ($fragment in $ComposerAuth) { + $piece = ('{' + $fragment + '}') | ConvertFrom-Json + foreach ($prop in $piece.PSObject.Properties) { + if ($prop.Name -eq 'http-basic') { + if (-not $existing.'http-basic') { + $existing | Add-Member -MemberType NoteProperty -Name 'http-basic' -Value ([PSCustomObject]@{}) -Force + } + foreach ($domainProp in $prop.Value.PSObject.Properties) { + $existing.'http-basic' | Add-Member -MemberType NoteProperty -Name $domainProp.Name -Value $domainProp.Value -Force + } + } else { + $existing | Add-Member -MemberType NoteProperty -Name $prop.Name -Value $prop.Value -Force + } + } + } + Set-Content -Path $composer_home\auth.json -Value ($existing | ConvertTo-Json -Depth 5) +} + +function Test-GitHubPublicAccess { + param( + [Parameter(Mandatory=$true)] + [string]$Token + ) + try { + Invoke-RestMethod -Uri 'https://api.github.com/' -Headers @{ Authorization = "token $Token" } -ErrorAction Stop | Out-Null + return $true + } catch { + return $false + } +} + +# Function to setup authentication in composer. +Function Set-ComposerAuth() { + if(Test-Path env:COMPOSER_AUTH_JSON) { + if(Test-Json -JSON $env:COMPOSER_AUTH_JSON) { + Set-Content -Path $composer_home\auth.json -Value $env:COMPOSER_AUTH_JSON + } else { + Add-Log "$cross" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON" + } + } + $composer_auth = @() + if(Test-Path env:PACKAGIST_TOKEN) { + $composer_auth += '"http-basic": {"repo.packagist.com": { "username": "token", "password": "' + $env:PACKAGIST_TOKEN + '"}}' + } + $write_token = $true + $token = if ($env:COMPOSER_TOKEN) { $env:COMPOSER_TOKEN } else { $env:GITHUB_TOKEN } + if ($token) { + if ($env:GITHUB_SERVER_URL -ne "https://github.com" -and -not(Test-GitHubPublicAccess $token)) { + $write_token = $false + } + if($write_token) { + $composer_auth += '"github-oauth": {"github.com": "' + $token + '"}' + } + } + if($composer_auth.length) { + Update-AuthJson $composer_auth + } +} + +# Function to set composer environment variables. +Function Set-ComposerEnv() { + if ($env:COMPOSER_PROCESS_TIMEOUT) { + (Get-Content $src\configs\composer.env -Raw) -replace '(?m)^COMPOSER_PROCESS_TIMEOUT=.*$', "COMPOSER_PROCESS_TIMEOUT=$env:COMPOSER_PROCESS_TIMEOUT" | Set-Content $src\configs\composer.env + } + Add-EnvPATH $src\configs\composer.env + if($env:COMPOSER_ALLOW_PLUGINS) { + $env:COMPOSER_ALLOW_PLUGINS -split '\s*,\s*' | Where-Object { $_ } | ForEach-Object { + & composer global config --no-plugins "allow-plugins.$_" true > $null 2>&1 + } + } +} + +# Function to identify latest-like URLs that should bypass the persistent cache. +Function Test-MutableToolUrl() { + Param( + [Parameter(Position = 0, Mandatory = $true)] + [string] + $Url + ) + $mutableUrlRegex = '(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/' + $versionLikeRegex = '(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*' + return ($Url -match $mutableUrlRegex) -or (($Url -match '\.phar([?#].*)?$') -and -not ($Url -match $versionLikeRegex)) +} + +# Function to extract tool version. +Function Get-ToolVersion() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + $tool, + [Parameter(Position = 1, Mandatory = $false)] + $param + ) + $alp = "[a-zA-Z0-9\.]" + $version_regex = "[0-9]+((\.{1}$alp+)+)(\.{0})(-$alp+){0,1}" + if($tool -eq 'composer') { + $composer_branch_alias = Select-String -Pattern "const\sBRANCH_ALIAS_VERSION" -Path $bin_dir\composer -Raw | Select-String -Pattern $version_regex | ForEach-Object { $_.matches.Value } + if ($composer_branch_alias) { + $composer_version = $composer_branch_alias + '+' + (Select-String -Pattern "const\sVERSION" -Path $bin_dir\composer -Raw | Select-String -Pattern "[a-zA-Z0-9]+" -AllMatches | ForEach-Object { $_.matches[2].Value }) + } else { + $composer_version = Select-String -Pattern "const\sVERSION" -Path $bin_dir\composer -Raw | Select-String -Pattern $version_regex | ForEach-Object { $_.matches.Value } + } + Set-Variable -Name 'composer_version' -Value $composer_version -Scope Global + return "$composer_version" + } + if($null -ne $param) { + return . $tool $param 2> $null | ForEach-Object { $_ -replace "composer $version_regex", '' } | Select-String -Pattern $version_regex | Select-Object -First 1 | ForEach-Object { $_.matches.Value } + } +} + +# Helper function to configure tools. +Function Add-ToolsHelper() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + $tool + ) + $extensions = @(); + if($tool -eq "box") { + $extensions += @('iconv', 'mbstring', 'phar', 'sodium') + } elseif($tool -eq "codeception") { + $extensions += @('json', 'mbstring') + Copy-Item $env:codeception_bin\codecept.bat -Destination $env:codeception_bin\codeception.bat + } elseif($tool -eq "composer") { + Edit-ComposerConfig $bin_dir\$tool + } elseif($tool -eq "cs2pr") { + (Get-Content $bin_dir/cs2pr).replace('exit(9)', 'exit(0)') | Set-Content $bin_dir/cs2pr + } elseif($tool -eq "deployer") { + Copy-Item $bin_dir\deployer.bat -Destination $bin_dir\dep.bat + } elseif($tool -eq "phan") { + $extensions += @('fileinfo', 'ast') + } elseif($tool -eq "phinx") { + $extensions += @('mbstring') + } elseif($tool -eq "phive") { + $extensions += @('curl', 'mbstring', 'xml') + } elseif($tool -match "phpc(df|s)") { + $extensions += @('tokenizer', 'xmlwriter', 'simplexml') + } elseif($tool -match "php-cs-fixer") { + $extensions += @('json', 'tokenizer') + } elseif($tool -eq "phpDocumentor") { + $extensions+=('ctype', 'hash', 'json', 'fileinfo', 'iconv', 'mbstring', 'simplexml', 'xml') + Add-Extension fileinfo >$null 2>&1 + Copy-Item $bin_dir\phpDocumentor.bat -Destination $bin_dir\phpdoc.bat + } elseif($tool -eq "phpunit") { + $extensions += @('dom', 'json', 'libxml', 'mbstring', 'xml', 'xmlwriter') + } elseif($tool -eq "phpunit-bridge") { + $extensions += @('dom', 'pdo', 'tokenizer', 'xmlwriter') + } elseif($tool -eq "vapor-cli") { + $extensions += @('fileinfo', 'json', 'mbstring', 'zip', 'simplexml') + Copy-Item $env:vapor_cli_bin\vapor.bat -Destination $env:vapor_cli_bin\vapor-cli.bat + } elseif($tool -eq "wp-cli") { + Copy-Item $bin_dir\wp-cli.bat -Destination $bin_dir\wp.bat + } + foreach($extension in $extensions) { + Add-Extension $extension >$null 2>&1 + } +} + +# Function to add tools. +Function Add-Tool() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + $urls, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + $tool, + [Parameter(Position = 2, Mandatory = $false)] + $ver_param + ) + $urls = $urls -split ',' + $tool_path = "$bin_dir\$tool" + $is_exe = ((($urls[0] | Split-Path -Extension).ToLowerInvariant()) -eq '.exe') + if ($is_exe) { $tool_path = "$tool_path.exe" } + $tool_ext = if ($is_exe) { '.exe' } else { '' } + $url_stream = [System.IO.MemoryStream]::New([System.Text.Encoding]::UTF8.GetBytes($urls[0])) + $cache_key = (Get-FileHash -InputStream $url_stream -Algorithm SHA256).Hash.Substring(0, 16) + $cache_path = "$env:TEMP\$tool-$cache_key$tool_ext" + $use_cache = -not (Test-MutableToolUrl $urls[0]) + $status_code = 200 + if ($use_cache -and (Test-Path $cache_path -PathType Leaf)) { + Copy-Item $cache_path -Destination $tool_path -Force + } else { + $backup_path = "$tool_path.bak" + if (Test-Path $tool_path) { Copy-Item $tool_path -Destination $backup_path -Force } + foreach ($url in $urls){ + try { + $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode + } catch { + if($url -match '.*github.com.*releases.*latest.*') { + try { + $url = $url.replace("releases/latest/download", "releases/download/" + ([regex]::match((Get-File -Url ($url.split('/release')[0] + "/releases")).Content, "([0-9]+\.[0-9]+\.[0-9]+)/" + ($url.Substring($url.LastIndexOf("/") + 1))).Groups[0].Value).split('/')[0]) + $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode + } catch { + $status_code = 0 + } + } else { + $status_code = 0 + } + } + if($status_code -eq 200 -and (Test-Path $tool_path)) { + if ($use_cache) { + Copy-Item $tool_path -Destination $cache_path -Force + } + break + } + } + if ($status_code -ne 200 -and (Test-Path $backup_path)) { + Copy-Item $backup_path -Destination $tool_path -Force + } + Remove-Item $backup_path -Force -ErrorAction SilentlyContinue + } + + $escaped_tool = [regex]::Escape($tool) + if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$escaped_tool(\.exe|\.phar)?$").Count -gt 0)) { + $bat_content = @() + $bat_content += "@ECHO off" + $bat_content += "setlocal DISABLEDELAYEDEXPANSION" + $bat_content += "SET BIN_TARGET=%~dp0/" + $tool + $bat_content += "php %BIN_TARGET% %*" + Set-Content -Path $bin_dir\$tool.bat -Value $bat_content + Add-ToolsHelper $tool + Add-ToProfile $current_profile $tool "New-Alias $tool $bin_dir\$tool.bat" >$null 2>&1 + $tool_version = Get-ToolVersion $tool $ver_param + Add-Log $tick $tool "Added $tool $tool_version" + } else { + if($tool -eq "composer") { + $env:fail_fast = 'true' + } + Add-Log $cross $tool "Could not add $tool" + } +} + +Function Add-ComposerToolHelper() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [string] + $tool, + [Parameter(Position = 1, Mandatory = $true)] + [string] + $release, + [Parameter(Position = 2, Mandatory = $true)] + [string] + $prefix, + [Parameter(Position = 3, Mandatory = $true)] + [string] + $scope, + [Parameter(Position = 4, Mandatory = $false)] + [string] + $composer_args + ) + $tool_version = $release.split(':')[1] + if($NULL -eq $tool_version) { + $tool_version = '*' + } + if($scope -eq 'global') { + if(Test-Path $composer_lock) { + Remove-Item -Path $composer_lock -Force + } + if((composer global show $prefix$tool $tool_version -a 2>&1 | findstr '^type *: *composer-plugin') -and ($composer_args -ne '')) { + composer global config --no-plugins allow-plugins."$prefix$tool" true >$null 2>&1 + } + composer global require $prefix$release $composer_args >$null 2>&1 + return composer global show $prefix$tool 2>&1 | findstr '^versions' + } else { + $release_stream = [System.IO.MemoryStream]::New([System.Text.Encoding]::ASCII.GetBytes($release)) + $scoped_dir_suffix = (Get-FileHash -InputStream $release_stream -Algorithm sha256).Hash + $scoped_dir = "$composer_bin\_tools\$tool-$scoped_dir_suffix" + $unix_scoped_dir = $scoped_dir.replace('\', '/') + if(-not(Test-Path $scoped_dir)) { + New-Item -ItemType Directory -Force -Path $scoped_dir > $null 2>&1 + Set-Content -Path $scoped_dir\composer.json -Value "{}" + if((composer show $prefix$tool $tool_version -d $unix_scoped_dir -a 2>&1 | findstr '^type *: *composer-plugin') -and ($composer_args -ne '')) { + composer config -d $unix_scoped_dir --no-plugins allow-plugins."$prefix$tool" true >$null 2>&1 + } + composer require $prefix$release -d $unix_scoped_dir $composer_args >$null 2>&1 + } + [System.Environment]::SetEnvironmentVariable(($tool.replace('-', '_') + '_bin'), "$scoped_dir\vendor\bin") + Add-Path $scoped_dir\vendor\bin + return composer show $prefix$tool -d $unix_scoped_dir 2>&1 | findstr '^versions' + } +} + +# Function to setup a tool using composer. +Function Add-ComposerTool() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $tool, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $release, + [Parameter(Position = 2, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $prefix, + [Parameter(Position = 3, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $scope + ) + $composer_args = "" + if($composer_version.split('.')[0] -ne "1") { + $composer_args = "--ignore-platform-req=ext-*" + if($tool -match "prestissimo|composer-prefetcher") { + Write-Output "::warning:: Skipping $tool, as it does not support Composer $composer_version. Specify composer:v1 in tools to use $tool" + Add-Log $cross $tool "Skipped" + Return + } + } + Enable-PhpExtension -Extension curl, mbstring, openssl -Path $php_dir + $log = Add-ComposerToolHelper $tool $release $prefix $scope $composer_args + if(Test-Path $composer_bin\composer) { + Copy-Item -Path "$bin_dir\composer" -Destination "$composer_bin\composer" -Force + } + Add-ToolsHelper $tool + if($log) { + $tool_version = Get-ToolVersion "Write-Output" "$log" + Add-Log $tick $tool "Added $tool $tool_version" + } else { + Add-Log $cross $tool "Could not setup $tool" + } +} diff --git a/src/scripts/tools/add_tools.sh b/src/scripts/tools/add_tools.sh new file mode 100644 index 0000000..294a151 --- /dev/null +++ b/src/scripts/tools/add_tools.sh @@ -0,0 +1,288 @@ +# Variables +export composer_home="$HOME/.composer" +export composer_bin="$composer_home/vendor/bin" +export composer_json="$composer_home/composer.json" +export composer_lock="$composer_home/composer.lock" + +# Function to extract tool version. +get_tool_version() { + tool=$1 + param=$2 + alp="[a-zA-Z0-9\.]" + version_regex="[0-9]+((\.{1}$alp+)+)(\.{0})(-$alp+){0,1}" + if [ "$tool" = "composer" ]; then + composer_alias_version="$(grep -Ea "const\sBRANCH_ALIAS_VERSION" "${tool_path_dir:?}/composer" | grep -Eo "$version_regex")" + if [[ -n "$composer_alias_version" ]]; then + composer_version="$composer_alias_version+$(grep -Ea "const\sVERSION" "$tool_path_dir/composer" | grep -Eo "$alp+" | tail -n 1)" + else + composer_version="$(grep -Ea "const\sVERSION" "$tool_path_dir/composer" | grep -Eo "$version_regex")" + fi + echo "$composer_version" | sudo tee /tmp/composer_version + elif [ -n "$param" ]; then + $tool "$param" 2>/dev/null | sed -Ee "s/[Cc]omposer(.)?$version_regex//g" | grep -Eo "$version_regex" | head -n 1 + fi +} + +# Function to configure composer +configure_composer() { + tool_path=$1 + sudo ln -sf "$tool_path" "$tool_path.phar" + php -r "try {\$p=new Phar('$tool_path.phar', 0);exit(0);} catch(Exception \$e) {exit(1);}" + if [ $? -eq 1 ]; then + add_log "${cross:?}" "composer" "Could not download composer" + exit 1 + fi + if ! [ -d "$composer_home" ]; then + sudo -u "$(id -un)" -g "$(id -gn)" mkdir -p -m=00755 "$composer_home" + else + sudo chown -R "$(id -un)":"$(id -gn)" "$composer_home" + fi + if ! [ -e "$composer_json" ]; then + echo '{}' | tee "$composer_json" >/dev/null + chmod 644 "$composer_json" + fi + set_composer_env + add_path "$composer_bin" + set_composer_auth +} + +# Function to merge auth.json fragments. +update_auth_json() { + local auth_file="$composer_home/auth.json" + local merged + [[ -f "$auth_file" ]] && merged=$(<"$auth_file") || merged='{}' + for frag in "$@"; do + local obj="{$frag}" + merged=$(jq -n --argjson b "$merged" --argjson n "$obj" ' + if $n|has("http-basic") then + (($b["http-basic"]//{}) + $n["http-basic"]) as $hb + | ($b + $n) | .["http-basic"] = $hb + else + $b + $n + end + ') + done + printf '%s' "$merged" > "$composer_home/auth.json" +} + +# Function to check if public GitHub token authentication is possible. +can_access_public_github() { + curl --fail -s -H "Authorization: token $1" 'https://api.github.com/' >/dev/null 2>&1 +} + +# Function to setup authentication in composer. +set_composer_auth() { + if [ -n "$COMPOSER_AUTH_JSON" ]; then + if php -r "json_decode('$COMPOSER_AUTH_JSON'); if(json_last_error() !== JSON_ERROR_NONE) { throw new Exception('invalid json'); }"; then + echo "$COMPOSER_AUTH_JSON" | tee "$composer_home/auth.json" >/dev/null + else + add_log "${cross:?}" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON" + fi + fi + composer_auth=() + if [ -n "$PACKAGIST_TOKEN" ]; then + composer_auth+=( '"http-basic": {"repo.packagist.com": { "username": "token", "password": "'"$PACKAGIST_TOKEN"'"}}' ) + fi + token="${COMPOSER_TOKEN:-$GITHUB_TOKEN}" + if [ -n "$token" ]; then + write_token=true + if [ "$GITHUB_SERVER_URL" != "https://github.com" ]; then + can_access_public_github "$token" || write_token=false + fi + if [ "$write_token" = 'true' ]; then + composer_auth+=( '"github-oauth": {"github.com": "'"$token"'"}' ) + fi + fi + if ((${#composer_auth[@]})); then + update_auth_json "${composer_auth[@]}" + fi +} + +# Function to set composer environment variables. +set_composer_env() { + composer_env="${src:?}"/configs/composer.env + if [ -n "$COMPOSER_PROCESS_TIMEOUT" ]; then + sed_arg="s/COMPOSER_PROCESS_TIMEOUT.*/COMPOSER_PROCESS_TIMEOUT=$COMPOSER_PROCESS_TIMEOUT/" + sed -i "$sed_arg" "$composer_env" 2>/dev/null || sed -i '' "$sed_arg" "$composer_env" + fi + add_env_path "$composer_env" + if [ -n "$COMPOSER_ALLOW_PLUGINS" ]; then + echo "$COMPOSER_ALLOW_PLUGINS" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v '^$' | while IFS= read -r plugin; do + composer global config --no-plugins "allow-plugins.$plugin" true >/dev/null 2>&1 + done + fi +} + +# Function to identify latest-like URLs that should bypass the persistent cache. +is_mutable_tool_url() { + local tool_url=$1 + local mutable_url_regex='(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/' + local version_like_regex='(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*' + [[ "$tool_url" =~ $mutable_url_regex ]] && return 0 + [[ "$tool_url" =~ \.phar([?#].*)?$ && ! "$tool_url" =~ $version_like_regex ]] && return 0 + return 1 +} + +# Helper function to configure tools. +add_tools_helper() { + tool=$1 + extensions=() + if [ "$tool" = "blackfire-player" ]; then + extensions+=(uuid) + elif [ "$tool" = "box" ]; then + extensions+=(iconv mbstring phar sodium) + elif [ "$tool" = "codeception" ]; then + extensions+=(json mbstring) + sudo ln -s "$scoped_dir"/vendor/bin/codecept "$scoped_dir"/vendor/bin/codeception 2>/dev/null || true + elif [ "$tool" = "composer" ]; then + configure_composer "$tool_path" + elif [ "$tool" = "cs2pr" ]; then + sudo sed -i 's/\r$//; s/exit(9)/exit(0)/' "$tool_path" 2>/dev/null || + sudo sed -i '' 's/\r$//; s/exit(9)/exit(0)/' "$tool_path" + elif [ "$tool" = "deployer" ]; then + sudo ln -s "$tool_path" "$tool_path_dir"/deployer 2>/dev/null || true + sudo ln -s "$tool_path" "$tool_path_dir"/dep 2>/dev/null || true + elif [ "$tool" = "phan" ]; then + extensions+=(fileinfo ast) + elif [ "$tool" = "phinx" ]; then + extensions+=(mbstring) + elif [ "$tool" = "phive" ]; then + extensions+=(curl mbstring xml) + elif [[ "$tool" =~ phpc(bf|s) ]]; then + extensions+=(tokenizer simplexml xmlwriter) + elif [[ "$tool" =~ phpc(bf|s) ]]; then + extensions+=(tokenizer xmlwriter simplexml) + elif [ "$tool" = "php-cs-fixer" ]; then + extensions+=(json tokenizer) + elif [ "$tool" = "phpDocumentor" ]; then + extensions+=(ctype hash json fileinfo iconv mbstring simplexml xml) + sudo ln -s "$tool_path" "$tool_path_dir"/phpdocumentor 2>/dev/null || true + sudo ln -s "$tool_path" "$tool_path_dir"/phpdoc 2>/dev/null || true + elif [ "$tool" = "phpunit" ]; then + extensions+=(dom json libxml mbstring xml xmlwriter) + elif [ "$tool" = "phpunit-bridge" ]; then + extensions+=(dom pdo tokenizer xmlwriter xmlreader) + elif [[ "$tool" =~ phpunit(-polyfills)?$ ]]; then + if [ -e "$tool_path_dir"/phpunit ] && [ -d "$composer_bin" ]; then + sudo cp "$tool_path_dir"/phpunit "$composer_bin" + fi + elif [ "$tool" = "vapor-cli" ]; then + extensions+=(fileinfo json mbstring zip simplexml) + sudo ln -s "$scoped_dir"/vendor/bin/vapor "$scoped_dir"/vendor/bin/vapor-cli 2>/dev/null || true + elif [ "$tool" = wp-cli ]; then + sudo ln -s "$tool_path" "$tool_path_dir"/"${tool%-*}" 2>/dev/null || true + fi + for extension in "${extensions[@]}"; do + add_extension "$extension" extension >/dev/null 2>&1 + done +} + +# Function to setup a remote tool. +add_tool() { + url=$1 + tool=$2 + ver_param=$3 + tool_path="$tool_path_dir/$tool" + if ! [ -d "$tool_path_dir" ]; then + sudo mkdir -p "$tool_path_dir" + fi + if ! [ -d "$tool_cache_path_dir" ]; then + sudo mkdir -p "$tool_cache_path_dir" + fi + add_path "$tool_path_dir" verify + add_path "$tool_cache_path_dir" + IFS="," read -r -a url <<<"$url" + cache_key=$(get_sha256 "${url[0]}" | head -c 16) + cache_path="$tool_cache_path_dir/${tool}-${cache_key}" + use_cache=true + is_mutable_tool_url "${url[0]}" && use_cache=false + status_code="200" + if [ "$use_cache" = "true" ] && [ -f "$cache_path" ]; then + sudo cp -a "$cache_path" "$tool_path" + else + [ -f "$tool_path" ] && sudo cp -a "$tool_path" "$tool_path.bak" + status_code=$(get -v -e "$tool_path" "${url[@]}") + if [ "$status_code" != "200" ] && [[ "${url[0]}" =~ .*github.com.*releases.*latest.* ]]; then + url[0]="${url[0]//releases\/latest\/download/releases/download/$(get -s -n "" "$(echo "${url[0]}" | cut -d '/' -f '1-5')/releases" | grep -Eo -m 1 "([0-9]+\.[0-9]+\.[0-9]+)/$(echo "${url[0]}" | sed -e "s/.*\///")" | cut -d '/' -f 1)}" + status_code=$(get -v -e "$tool_path" "${url[0]}") + fi + if [ "$status_code" = "200" ] && [ "$use_cache" = "true" ]; then + sudo cp -a "$tool_path" "$cache_path" + elif [ -f "$tool_path.bak" ]; then + sudo mv "$tool_path.bak" "$tool_path" + fi + sudo rm -f "$tool_path.bak" + fi + if [ "$status_code" = "200" ]; then + add_tools_helper "$tool" + [ -L "$tool_cache_path_dir/$tool" ] || sudo ln -s "$tool_path" "$tool_cache_path_dir/$tool" 2>/dev/null || true + tool_version=$(get_tool_version "$tool" "$ver_param") + add_log "${tick:?}" "$tool" "Added $tool $tool_version" + else + if [ "$tool" = "composer" ]; then + export fail_fast=true + fi + if [ "$status_code" = "404" ]; then + add_log "$cross" "$tool" "Failed to download $tool from ${url[*]}" + else + add_log "$cross" "$tool" "Could not setup $tool" + fi + fi +} + +# Function to setup a tool using composer in a different scope. +add_composer_tool_helper() { + tool=$1 + release=$2 + prefix=$3 + scope=$4 + composer_args=$5 + enable_extensions curl mbstring openssl + tool_version=${release##*:}; [ "$tool_version" = "$tool" ] && tool_version="*" + if [ "$scope" = "global" ]; then + sudo rm -f "$composer_lock" >/dev/null 2>&1 || true + if composer global show "$prefix$tool" "$tool_version" -a 2>&1 | grep -qE '^type *: *composer-plugin' && [ -n "$composer_args" ]; then + composer global config --no-plugins allow-plugins."$prefix$tool" true >/dev/null 2>&1 + fi + composer global require "$prefix$release" "$composer_args" >/dev/null 2>&1 + composer global show "$prefix$tool" 2>&1 | grep -E ^versions | sudo tee /tmp/composer.log >/dev/null 2>&1 + else + scoped_dir="$composer_bin/_tools/$tool-$(echo -n "$release" | shasum -a 256 | cut -d ' ' -f 1)" + if ! [ -d "$scoped_dir" ]; then + mkdir -p "$scoped_dir" + echo '{}' | tee "$scoped_dir/composer.json" >/dev/null + if composer show "$prefix$tool" "$tool_version" -d "$scoped_dir" -a 2>&1 | grep -qE '^type *: *composer-plugin' && [ -n "$composer_args" ]; then + composer config -d "$scoped_dir" --no-plugins allow-plugins."$prefix$tool" true >/dev/null 2>&1 + fi + composer require "$prefix$release" -d "$scoped_dir" "$composer_args" >/dev/null 2>&1 + composer show "$prefix$tool" -d "$scoped_dir" 2>&1 | grep -E ^versions | sudo tee /tmp/composer.log >/dev/null 2>&1 + fi + add_path "$scoped_dir"/vendor/bin + fi +} + +# Function to setup a tool using composer. +add_composer_tool() { + tool=$1 + release=$2 + prefix=$3 + scope=$4 + composer_args= + composer_major_version=$(cut -d'.' -f 1 /tmp/composer_version) + if [ "$composer_major_version" != "1" ]; then + composer_args="--ignore-platform-req=ext-*" + if [[ "$tool" =~ prestissimo|composer-prefetcher ]]; then + echo "::warning:: Skipping $tool, as it does not support Composer $composer_version. Specify composer:v1 in tools to use $tool" + add_log "$cross" "$tool" "Skipped" + return + fi + fi + add_composer_tool_helper "$tool" "$release" "$prefix" "$scope" "$composer_args" + tool_version=$(get_tool_version cat /tmp/composer.log) + ([ -s /tmp/composer.log ] && add_log "$tick" "$tool" "Added $tool $tool_version" + ) || add_log "$cross" "$tool" "Could not setup $tool" + add_tools_helper "$tool" + if [ -e "$composer_bin/composer" ]; then + sudo cp -a "$tool_path_dir/composer" "$composer_bin" + fi +} diff --git a/src/scripts/tools/blackfire.ps1 b/src/scripts/tools/blackfire.ps1 new file mode 100644 index 0000000..4427ef7 --- /dev/null +++ b/src/scripts/tools/blackfire.ps1 @@ -0,0 +1,19 @@ +# Function to add blackfire cli. +Function Add-Blackfire() { + $arch_name ='amd64' + if(-not([Environment]::Is64BitOperatingSystem) -or $version -lt '7.0') { + $arch_name = '386' + } + $cli_version = (Invoke-RestMethod https://blackfire.io/api/v1/releases).cli + $url = "https://packages.blackfire.io/binaries/blackfire/${cli_version}/blackfire-windows_${arch_name}.zip" + Get-File -Url $url -OutFile $bin_dir\blackfire.zip >$null 2>&1 + Expand-Archive -Path $bin_dir\blackfire.zip -DestinationPath $bin_dir -Force >$null 2>&1 + Add-ToProfile $current_profile 'blackfire' "New-Alias blackfire $bin_dir\blackfire.exe" + if ((Test-Path env:BLACKFIRE_SERVER_ID) -and (Test-Path env:BLACKFIRE_SERVER_TOKEN)) { + blackfire agent:config --server-id=$env:BLACKFIRE_SERVER_ID --server-token=$env:BLACKFIRE_SERVER_TOKEN >$null 2>&1 + } + if ((Test-Path env:BLACKFIRE_CLIENT_ID) -and (Test-Path env:BLACKFIRE_CLIENT_TOKEN)) { + blackfire client:config --client-id=$env:BLACKFIRE_CLIENT_ID --client-token=$env:BLACKFIRE_CLIENT_TOKEN --ca-cert=$php_dir\ssl\cacert.pem >$null 2>&1 + } + Add-Log $tick "blackfire" "Added blackfire $cli_version" +} diff --git a/src/scripts/tools/blackfire.sh b/src/scripts/tools/blackfire.sh new file mode 100644 index 0000000..b13c831 --- /dev/null +++ b/src/scripts/tools/blackfire.sh @@ -0,0 +1,40 @@ +add_blackfire_linux() { + sudo mkdir -p /var/run/blackfire /etc/blackfire + add_list debian/blackfire http://packages.blackfire.io/debian https://packages.blackfire.io/gpg.key any main + install_packages blackfire + sudo chmod 777 /etc/blackfire/agent +} + +add_blackfire_darwin() { + sudo mkdir -p /usr/local/var/run + add_brew_tap blackfireio/homebrew-blackfire + safe_brew install blackfire +} + +blackfire_config() { + if [[ -n $BLACKFIRE_SERVER_ID ]] && [[ -n $BLACKFIRE_SERVER_TOKEN ]]; then + blackfire agent:config --server-id="$BLACKFIRE_SERVER_ID" --server-token="$BLACKFIRE_SERVER_TOKEN" + if [ "$os" = "Linux" ]; then + if [ -d /run/systemd/system ]; then + sudo systemctl start blackfire-agent + else + sudo service blackfire-agent start + fi + elif [ "$os" = "Darwin" ]; then + brew services start blackfire + fi + fi + if [[ -n $BLACKFIRE_CLIENT_ID ]] && [[ -n $BLACKFIRE_CLIENT_TOKEN ]]; then + blackfire client:config --client-id="$BLACKFIRE_CLIENT_ID" --client-token="$BLACKFIRE_CLIENT_TOKEN" + fi +} + +# Function to add blackfire cli. +add_blackfire() { + os="$(uname -s)" + [ "$os" = "Linux" ] && add_blackfire_linux >/dev/null 2>&1 + [ "$os" = "Darwin" ] && add_blackfire_darwin >/dev/null 2>&1 + blackfire_config >/dev/null 2>&1 + tool_version=$(get_tool_version "blackfire" "version") + add_log "${tick:?}" "blackfire" "Added blackfire $tool_version" +} diff --git a/src/scripts/tools/brew.sh b/src/scripts/tools/brew.sh new file mode 100644 index 0000000..089e897 --- /dev/null +++ b/src/scripts/tools/brew.sh @@ -0,0 +1,214 @@ +# Function to fetch a brew tap. +fetch_brew_tap() { + tap=$1 + tap_user=$(dirname "$tap") + tap_name=$(basename "$tap") + mkdir -p "$tap_dir/$tap_user" + branch="$(git ls-remote --symref "https://github.com/$tap" HEAD | grep -Eo 'refs/heads/.*' | tr '\t' '\n' | head -1 | cut -d '/' -f 3)" + get -s -n "" "https://github.com/$tap/archive/$branch.tar.gz" | sudo tar -xzf - -C "$tap_dir/$tap_user" + sudo mv "$tap_dir/$tap_user/$tap_name-$branch" "$tap_dir/$tap_user/$tap_name" +} + +# Function to add a brew tap. +add_brew_tap() { + tap=$1 + if ! [ -d "$tap_dir/$tap" ]; then + if [ "${runner:?}" = "self-hosted" ]; then + brew tap "$tap" >/dev/null 2>&1 + else + fetch_brew_tap "$tap" >/dev/null 2>&1 + if ! [ -d "$tap_dir/$tap" ]; then + brew tap "$tap" >/dev/null 2>&1 + fi + fi + fi +} + +# Function to get brew prefix. +get_brew_prefix() { + if [ "$(uname -s)" = "Linux" ]; then + echo /home/linuxbrew/.linuxbrew + else + if [ "$(uname -m)" = "arm64" ]; then + echo /opt/homebrew + else + echo /usr/local + fi + fi +} + +# Function to add brew's bin directories to the PATH. +add_brew_bins_to_path() { + local brew_prefix=${1:-$(get_brew_prefix)} + add_path "$brew_prefix"/bin + add_path "$brew_prefix"/sbin +} + +# Function to get file modification time. +get_file_mtime() { + local file=$1 + if [ "$(uname -s)" = "Darwin" ]; then + stat -f "%m" "$file" 2>/dev/null || echo 0 + else + stat -c "%Y" "$file" 2>/dev/null || echo 0 + fi +} + +# Function to terminate a process and its direct children. +terminate_process_tree() { + local pid=$1 + local children child + children=$(pgrep -P "$pid" 2>/dev/null || true) + kill -TERM "$pid" >/dev/null 2>&1 || true + for child in $children; do + terminate_process_tree "$child" + done + sleep 2 + kill -KILL "$pid" >/dev/null 2>&1 || true + for child in $children; do + terminate_process_tree "$child" + done +} + +# Function to run a command with an inactivity watchdog. +run_with_inactivity_watchdog() { + local timeout_secs="${SETUP_PHP_BREW_INACTIVITY_TIMEOUT:-180}" + local poll_secs="${SETUP_PHP_BREW_WATCHDOG_POLL:-5}" + local tmp_dir stdout_fifo stderr_fifo stdout_log stderr_log timeout_file + local command_pid stdout_reader_pid stderr_reader_pid monitor_pid exit_code + tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/setup-php-brew.XXXXXX")" || return 1 + stdout_fifo="$tmp_dir/stdout.fifo" + stderr_fifo="$tmp_dir/stderr.fifo" + stdout_log="$tmp_dir/stdout.log" + stderr_log="$tmp_dir/stderr.log" + timeout_file="$tmp_dir/timed_out" + mkfifo "$stdout_fifo" "$stderr_fifo" || { + rm -rf "$tmp_dir" + return 1 + } + : >"$stdout_log" + : >"$stderr_log" + + ("$@" >"$stdout_fifo" 2>"$stderr_fifo") & + command_pid=$! + + ( + while IFS= read -r line || [ -n "$line" ]; do + printf '%s\n' "$line" + printf '%s\n' "$line" >>"$stdout_log" + done <"$stdout_fifo" + ) & + stdout_reader_pid=$! + + ( + while IFS= read -r line || [ -n "$line" ]; do + printf '%s\n' "$line" >&2 + printf '%s\n' "$line" >>"$stderr_log" + done <"$stderr_fifo" + ) & + stderr_reader_pid=$! + + ( + local last_activity current_activity current_err_activity now + last_activity=$(get_file_mtime "$stdout_log") + current_err_activity=$(get_file_mtime "$stderr_log") + [ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity" + while kill -0 "$command_pid" >/dev/null 2>&1; do + sleep "$poll_secs" + current_activity=$(get_file_mtime "$stdout_log") + [ "$current_activity" -gt "$last_activity" ] && last_activity="$current_activity" + current_err_activity=$(get_file_mtime "$stderr_log") + [ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity" + now=$(date +%s) + if [ $((now - last_activity)) -ge "$timeout_secs" ]; then + printf "\nsetup-php: brew produced no output for %ss; terminating and retrying...\n" "$timeout_secs" >&2 + : >"$timeout_file" + terminate_process_tree "$command_pid" + break + fi + done + ) & + monitor_pid=$! + + wait "$command_pid" + exit_code=$? + wait "$stdout_reader_pid" 2>/dev/null || true + wait "$stderr_reader_pid" 2>/dev/null || true + kill "$monitor_pid" >/dev/null 2>&1 || true + wait "$monitor_pid" 2>/dev/null || true + + if [ -e "$timeout_file" ]; then + rm -rf "$tmp_dir" + return 124 + fi + + rm -rf "$tmp_dir" + return "$exit_code" +} + +# Function to run brew with retries and an inactivity watchdog. +safe_brew() { + local max_attempts="${SETUP_PHP_BREW_RETRY_ATTEMPTS:-3}" + local attempt=1 + local exit_code=0 + + if [ "${SETUP_PHP_BREW_WATCHDOG:-true}" = "false" ]; then + brew "$@" + return $? + fi + + while [ "$attempt" -le "$max_attempts" ]; do + run_with_inactivity_watchdog brew "$@" && return 0 + exit_code=$? + + if [ "$attempt" -ge "$max_attempts" ]; then + return "$exit_code" + fi + + printf "setup-php: retrying brew command (attempt %s/%s, exit %s)\n" "$((attempt + 1))" "$max_attempts" "$exit_code" >&2 + sleep "$((attempt * 5))" + attempt=$((attempt + 1)) + done + + return "$exit_code" +} + +# Function to add brew. +add_brew() { + brew_prefix="$(get_brew_prefix)" + if ! [ -d "$brew_prefix"/bin ]; then + step_log "Setup Brew" + get -s "" "/tmp/install.sh" "https://raw.githubusercontent.com/Homebrew/install/main/install.sh" | bash -s >/dev/null 2>&1 + add_log "${tick:?}" "Brew" "Installed Homebrew" + fi + add_brew_bins_to_path "$brew_prefix" +} + +# Function to configure brew constants. +configure_brew() { + brew_path="$(command -v brew)" + if [ -z "$brew_path" ]; then + add_brew + brew_path="$(command -v brew)" + fi + brew_opts=(-f) + brew_path_dir="$(dirname "$brew_path")" + brew_prefix="$brew_path_dir"/.. + brew_repo="$brew_path_dir/$(dirname "$(readlink "$brew_path")")"/.. + tap_dir="$brew_repo"/Library/Taps + core_repo="$tap_dir"/homebrew/homebrew-core + + export HOMEBREW_CHANGE_ARCH_TO_ARM=1 + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_ENV_HINTS=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 + export HOMEBREW_DOWNLOAD_CONCURRENCY="${HOMEBREW_DOWNLOAD_CONCURRENCY:-6}" + export brew_opts + export brew_path + export brew_path_dir + export brew_prefix + export brew_repo + export tap_dir + export core_repo +} diff --git a/src/scripts/tools/grpc_php_plugin.ps1 b/src/scripts/tools/grpc_php_plugin.ps1 new file mode 100644 index 0000000..2bdaa23 --- /dev/null +++ b/src/scripts/tools/grpc_php_plugin.ps1 @@ -0,0 +1,27 @@ +Function Add-Msys2() { + $msys_location = 'C:\msys64' + if (-not(Test-Path $msys_location)) { + choco install msys2 -y >$null 2>&1 + $msys_location = 'C:\tools\msys64' + } + return $msys_location +} + +Function Add-GrpcPhpPlugin() { + $msys_location = Add-Msys2 + $arch = arch + if($arch -eq 'arm64' -or $arch -eq 'aarch64') { + $grpc_package = 'mingw-w64-clang-aarch64-grpc' + } else { + $grpc_package = 'mingw-w64-x86_64-grpc' + } + $logs = . $msys_location\usr\bin\bash -l -c "pacman -S --noconfirm $grpc_package" >$null 2>&1 + $grpc_version = Get-ToolVersion 'Write-Output' "$logs" + Add-Path $msys_location\mingw64\bin + Set-Output grpc_php_plugin_path "$msys_location\mingw64\bin\grpc_php_plugin.exe" + Add-ToProfile $current_profile 'grpc_php_plugin' "New-Alias grpc_php_plugin $msys_location\mingw64\bin\grpc_php_plugin.exe" + Add-Log $tick "grpc_php_plugin" "Added grpc_php_plugin $grpc_version" + printf "$env:GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "grpc_php_plugin" "Click to read the grpc_php_plugin related license information" + Write-Output (Invoke-WebRequest https://raw.githubusercontent.com/grpc/grpc/master/LICENSE).Content + Write-Output "$env:END_GROUP" +} diff --git a/src/scripts/tools/grpc_php_plugin.sh b/src/scripts/tools/grpc_php_plugin.sh new file mode 100644 index 0000000..9d8bd24 --- /dev/null +++ b/src/scripts/tools/grpc_php_plugin.sh @@ -0,0 +1,62 @@ +add_bazel() { + if ! command -v bazel; then + if [ "$(uname -s)" = "Linux" ]; then + add_list bazel/apt https://storage.googleapis.com/bazel-apt https://bazel.build/bazel-release.pub.gpg stable jdk1.8 + install_packages bazel + else + safe_brew install bazel + fi + fi +} + +get_grpc_tag() { + if [ "$grpc_tag" = "latest" ]; then + grpc_tag=$(get -s -n "" https://github.com/grpc/grpc/releases/latest | grep -Eo -m 1 "v[0-9]+\.[0-9]+\.[0-9]+" | head -n 1) + else + if [[ ${grpc_tag:0:1} != "v" ]] ; then grpc_tag="v$grpc_tag"; fi + status_code=$(get -v -n /tmp/grpc.tmp "https://github.com/grpc/grpc/releases/tag/$grpc_tag") + if [ "$status_code" != "200" ]; then + grpc_tag=$(get -s -n "" https://github.com/grpc/grpc/releases/latest | grep -Eo -m 1 "v[0-9]+\.[0-9]+\.[0-9]+" | head -n 1) + fi + fi +} + +add_grpc_php_plugin_brew() { + . "${0%/*}"/tools/brew.sh + configure_brew + [ -e /usr/local/bin/protoc ] && sudo mv /usr/local/bin/protoc /tmp/protoc && sudo mv /usr/local/include/google /tmp + safe_brew install grpc + brew link --force --overwrite grpc >/dev/null 2>&1 + [ -e /tmp/protoc ] && sudo mv /tmp/protoc /usr/local/bin/protoc && sudo mv /tmp/google /usr/local/include/ + grpc_tag="v$(brew info grpc | grep "grpc:" | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+")" + license_path="$(brew --prefix grpc)/LICENSE" +} + +add_grpc_php_plugin_compile() { + get_grpc_tag + get -s -n "" "https://github.com/grpc/grpc/archive/$grpc_tag.tar.gz" | tar -xz -C /tmp + export DISABLE_BAZEL_WRAPPER=1 + ( + cd "/tmp/grpc-${grpc_tag:1}" || exit + add_bazel + ./tools/bazel build src/compiler:grpc_php_plugin + sudo mv ./bazel-bin/src/compiler/grpc_php_plugin /usr/local/bin/grpc_php_plugin + sudo chmod a+x /usr/local/bin/grpc_php_plugin + license_path="/tmp/grpc-${grpc_tag:1}/LICENSE" + ) +} + +add_grpc_php_plugin() { + grpc_tag=$1 + license_path="" + if [ "$grpc_tag" = "latest" ]; then + add_grpc_php_plugin_brew >/dev/null 2>&1 + else + add_grpc_php_plugin_compile >/dev/null 2>&1 + fi + set_output grpc_php_plugin_path "$(command -v grpc_php_plugin)" + add_log "${tick:?}" "grpc_php_plugin" "Added grpc_php_plugin ${grpc_tag:1}" + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "grpc_php_plugin" "Click to read the grpc_php_plugin related license information" + cat "$license_path" + echo "$END_GROUP" +} diff --git a/src/scripts/tools/mago.ps1 b/src/scripts/tools/mago.ps1 new file mode 100644 index 0000000..5eeb392 --- /dev/null +++ b/src/scripts/tools/mago.ps1 @@ -0,0 +1,36 @@ +Function Get-MagoTag() { + $releases = 'https://github.com/carthage-software/mago/releases' + if("$mago_tag" -eq "latest") { + $mago_tag = (Get-File -Url $releases/latest).BaseResponse.RequestMessage.RequestUri.Segments[-1] + } else { + try { + [net.httpWebRequest] $request = [net.webRequest]::create("$releases/tag/$mago_tag") + $request.Method = "HEAD" + [net.httpWebResponse] $response = $request.getResponse() + $response.Close() + $mago_tag = "$mago_tag" + } catch { + $mago_tag = (Get-File -Url $releases/latest).BaseResponse.RequestMessage.RequestUri.Segments[-1] + } + } + return $mago_tag +} + +Function Add-Mago() { + param( + [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'The mago version to be installed')] + [ValidatePattern('^latest$|^\d+\.\d+\.\d+$')] + [string] $mago_tag + ) + $mago_tag = Get-MagoTag + $arch_name = 'x86_64' + if(-not([Environment]::Is64BitOperatingSystem)) { + $arch_name = 'i686' + } + $url = "https://github.com/carthage-software/mago/releases/download/$mago_tag/mago-$mago_tag-$arch_name-pc-windows-msvc.zip" + Get-File -Url $url -OutFile $bin_dir\mago.zip >$null 2>&1 + Expand-Archive -Path $bin_dir\mago.zip -DestinationPath $bin_dir\mago -Force >$null 2>&1 + Move-Item -Path $bin_dir\mago\mago-$mago_tag-$arch_name-pc-windows-msvc\mago.exe -Destination $bin_dir\mago.exe -Force + Add-ToProfile $current_profile 'mago' "New-Alias mago $bin_dir\mago.exe" + Add-Log $tick "mago" "Added mago $mago_tag" +} \ No newline at end of file diff --git a/src/scripts/tools/mago.sh b/src/scripts/tools/mago.sh new file mode 100644 index 0000000..6be2428 --- /dev/null +++ b/src/scripts/tools/mago.sh @@ -0,0 +1,29 @@ +get_mago_tag() { + if [ "$mago_tag" = "latest" ]; then + mago_tag=$(get -s -n "" https://github.com/carthage-software/mago/releases/latest 2<&1 | grep -m 1 -Eo "tag/([0-9]+(\.[0-9]+)?(\.[0-9]+)?)" | head -n 1 | cut -d '/' -f 2) + else + status_code=$(get -v -n /tmp/mago.tmp "https://github.com/carthage-software/mago/releases/tag/$mago_tag") + if [ "$status_code" = "200" ]; then + mago_tag="$mago_tag" + else + mago_tag=$(get -s -n "" https://github.com/carthage-software/mago/releases/latest 2<&1 | grep -m 1 -Eo "tag/([0-9]+(\.[0-9]+)?(\.[0-9]+)?)" | head -n 1 | cut -d '/' -f 2) + fi + fi +} + +add_mago() { + mago_tag=$1 + get_mago_tag + ( + platform='unknown-linux-gnu' + [ "$(uname -s)" = "Darwin" ] && platform='apple-darwin' + arch="$(uname -m)" + [[ "$arch" = 'arm64' || "$arch" = 'aarch64' ]] && arch='aarch64' + [[ "$arch" = 'x86_64' || "$arch" = 'amd64' ]] && arch='x86_64' + get -q -n /tmp/mago.tar.gz "https://github.com/carthage-software/mago/releases/download/$mago_tag/mago-$mago_tag-$arch-$platform.tar.gz" + sudo tar -xzf /tmp/mago.tar.gz -C /tmp/ + sudo mv /tmp/mago-$mago_tag-$arch-$platform/mago /usr/local/bin/mago + sudo chmod +x /usr/local/bin/mago + ) >/dev/null 2>&1 + add_log "${tick:?}" "mago" "Added mago $mago_tag" +} \ No newline at end of file diff --git a/src/scripts/tools/ppa.sh b/src/scripts/tools/ppa.sh new file mode 100644 index 0000000..0a70b83 --- /dev/null +++ b/src/scripts/tools/ppa.sh @@ -0,0 +1,414 @@ +# Function to try to set ubuntu or debian version. +set_base_version_id() { + [[ "$ID" =~ ubuntu|debian ]] && return; + if ! [ -d "$dist_info_dir" ]; then + sudo mkdir -p "$dist_info_dir" + get -q -n "$dist_info_dir"/os_releases.csv https://raw.githubusercontent.com/step-security/setup-php/release/src/configs/os_releases.csv + fi + for base in ubuntu debian; do + [[ "$ID_LIKE" =~ $base ]] && ID="$base" && VERSION_ID="$(grep -hr -m 1 "$VERSION_CODENAME" /usr/share/distro-info | cut -d ',' -f 1 | cut -d ' ' -f 1)" && break + done +} + +# Function to try to set ubuntu or debian codename. +set_base_version_codename() { + [[ "$ID" =~ ubuntu|debian ]] && return; + if [[ "$ID_LIKE" =~ ubuntu ]]; then + [[ -n "$UBUNTU_CODENAME" ]] && VERSION_CODENAME="$UBUNTU_CODENAME" && return; + [ -e "$upstream_lsb" ] && VERSION_CODENAME=$(grep 'CODENAME' "$upstream_lsb" | cut -d '=' -f 2) && return; + VERSION_CODENAME=$(grep -E -m1 'deb .*ubuntu.com' "$list_file" | cut -d ' ' -f 3) && VERSION_CODENAME=${VERSION_CODENAME%-*} + elif [[ "$ID_LIKE" =~ debian ]] || command -v dpkg >/dev/null; then + ID_LIKE=debian + [[ -n "$DEBIAN_CODENAME" ]] && VERSION_CODENAME="$DEBIAN_CODENAME" && return; + update_lists && VERSION_CODENAME=$(apt-cache show tzdata | grep -m 1 Provides | cut -d '-' -f 2) + fi +} + +# Function to set base os details +set_base_version() { + if [ -e /tmp/os-release ]; then + . /tmp/os-release + else + set_base_version_codename + set_base_version_id + printf "ID=%s\nVERSION_ID=%s\nVERSION_CODENAME=%s\n" "$ID" "$VERSION_ID" "$VERSION_CODENAME" | tee /tmp/os-release >/dev/null 2>&1 + fi +} + +# Helper function to update package lists. +update_lists_helper() { + list=$1 + command -v sudo >/dev/null && SUDO=sudo + if [[ -n "$list" ]]; then + ${SUDO} apt-get update -o Dir::Etc::sourcelist="$list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + else + ${SUDO} apt-get update + fi +} + +# Function to update the package lists. +update_lists() { + local ppa=${1:-} + local ppa_search=${2:-} + local status_token=${3:-$ppa_search} + local list= + local status_file=/tmp/os_lists + local hash_cmd + if [[ -n "$ppa" && -n "$ppa_search" ]]; then + if [ -f "$ppa_search" ]; then + list="$ppa_search" + else + list="$(grep -Elr "$ppa_search" "$list_dir" 2>/dev/null | head -n 1)" + fi + hash_cmd="$(command -v sha256sum || command -v shasum)" + if [ -n "$status_token" ] && [ -n "$hash_cmd" ]; then + status_file=/tmp/os_lists_"$(echo -n "$status_token" | $hash_cmd | awk '{print $1}')" + elif [ -n "$status_token" ]; then + status_file=/tmp/os_lists_$(date +%s) + fi + elif [ -e "$list_file" ] && grep -Eq '^deb |^Types: *deb' "$list_file"; then + list="$list_file" + fi + if [ ! -e "$status_file" ]; then + update_lists_helper "$list" >/dev/null 2>&1 + echo '' | tee "$status_file" >/dev/null 2>&1 + fi +} + +# Determine whether deb822 sources are the default on this system. +get_sources_format() { + if [ -n "$sources_format" ]; then + echo "$sources_format" + return + fi + sources_format=deb + if [ -e "$list_dir"/ubuntu.sources ] || [ -e "$list_dir"/debian.sources ]; then + sources_format="deb822" + elif ! [[ "$ID" =~ ubuntu|debian ]]; then + find "$list_dir" -type f -name '*.sources' | grep -q . && sources_format="deb822" + fi + echo "$sources_format" +} + +# Function to get sources file extension. +get_sources_extension() { + [ "$1" = "deb822" ] && echo "sources" || echo "list" +} + +# Function to escape regex special characters. +escape_regex() { + printf '%s' "$1" | sed -e 's/[][\.^$*+?{}()|\/]/\\&/g' +} + +# Function to merge two components strings. +merge_components() { + local out=() t + for t in $1 $2; do [[ $t && " ${out[*]} " != *" $t "* ]] && out+=("$t"); done + printf '%s\n' "${out[*]}" +} + +# Function to merge components from a file. +merge_components_from_file() { + local path=$1 + local incoming=$2 + local current= + if [ -n "$path" ] && [ -e "$path" ]; then + if grep -Eq '^Components:' "$path"; then + current="$(grep -E '^Components:' "$path" | head -n 1 | cut -d ':' -f 2 | xargs)" + else + current="$(sed -E -n 's/^deb[[:space:]]+(\[[^]]*\][[:space:]]+)?[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+//p' "$path" | head -n 1 | xargs)" + fi + fi + local merged + merged="$(merge_components "$current" "$incoming")" + if [ -z "$merged" ] || [ "$merged" = "$current" ]; then + return 1 + fi + printf '%s\n' "$merged" +} + +# Function to get repo patterns based on format. +get_repo_patterns() { + local list_format=$1 + local ppa_url=$2 + local package_dist=$3 + local branches=$4 + local escaped_url + local escaped_dist + local escaped_branches + escaped_url="$(escape_regex "$ppa_url")" + escaped_dist="$(escape_regex "$package_dist")" + escaped_branches="$(escape_regex "$branches")" + local deb_primary="^deb[[:space:]]+(\\[[^]]*\\][[:space:]]+)?${escaped_url}[[:space:]]+${escaped_dist}[[:space:]]" + local deb_secondary="^deb[[:space:]]+(\\[[^]]*\\][[:space:]]+)?${escaped_url}[[:space:]]+${escaped_dist}[[:space:]]+.*${escaped_branches}([[:space:]]|$)" + local deb822_primary="^URIs: ${escaped_url}$" + local deb822_secondary="^Suites: ${escaped_dist}$" + if [ "$list_format" = "deb822" ]; then + printf '%s|%s\n' "$deb822_primary" "$deb822_secondary" + else + printf '%s|%s\n' "$deb_primary" "$deb_secondary" + fi +} + +# Function to get fingerprint from an Ubuntu PPA. +ubuntu_fingerprint() { + ppa="$1" + ppa_uri="~${ppa%/*}/+archive/ubuntu/${ppa##*/}" + get -s -n "" "${lp_api[0]}/$ppa_uri" | jq -er '.signing_key_fingerprint' 2>/dev/null \ + || get -s -n "" "${lp_api[1]}/$ppa_uri" | jq -er '.signing_key_fingerprint' 2>/dev/null \ + || get -s -n "" "$ppa_sp/keys/$ppa.fingerprint" +} + + +# Function to get fingerprint from a Debian PPA. +debian_fingerprint() { + ppa=$1 + ppa_url=$2 + package_dist=$3 + release_pub=/tmp/"${ppa/\//-}".gpg + get -q -n "$release_pub" "$ppa_url"/dists/"$package_dist"/Release.gpg + gpg --list-packets "$release_pub" | grep -Eo 'fpr\sv4\s.*[a-zA-Z0-9]+' | head -n 1 | cut -d ' ' -f 3 +} + +# Function to add a GPG key. +add_key() { + ppa=${1:-ondrej/php} + ppa_url=$2 + package_dist=$3 + key_source=$4 + key_file=$5 + key_urls=("$key_source") + if [[ "$key_source" =~ launchpadcontent.net|debian.org ]]; then + fingerprint="$("${ID}"_fingerprint "$ppa" "$ppa_url" "$package_dist")" + sks_params="op=get&options=mr&exact=on&search=0x$fingerprint" + key_urls=("${sks[@]/%/\/pks\/lookup\?"$sks_params"}") + fi + key_urls+=("$ppa_sp/keys/$ppa.gpg") + [ ! -e "$key_source" ] && get -q -n "$key_file" "${key_urls[@]}" + if [[ "$(file "$key_file")" =~ .*('Public-Key (old)'|'Secret-Key') ]]; then + sudo gpg --batch --yes --dearmor "$key_file" >/dev/null 2>&1 && sudo mv "$key_file".gpg "$key_file" + fi +} + +# Function to handle existing list files. +handle_existing_list() { + local ppa=$1 + local list_format=$2 + local branches=$3 + local merged_components + if [ -z "$check_lists_file" ]; then + echo "Repository $ppa ($branches) already exists" && return 1 + fi + if merged_components="$(merge_components_from_file "$check_lists_file" "$branches")"; then + sudo rm -f "$check_lists_file" && printf '%s\n' "$merged_components" && return 0 + fi + if [[ "$list_format" = "deb822" && "$check_lists_file" = *.list ]]; then + sudo rm -f "$check_lists_file" && printf '%s\n' "$branches" && return 0 + fi + echo "Repository $ppa ($branches) already exists" && return 1 +} + +# Function to write a list file. +write_list() { + local type=$1 + local ppa=$2 + local url=$3 + local suite=$4 + local components=$5 + local key_file=$6 + local list_basename="${ppa%%/*}"-"$ID"-"${ppa#*/}"-"$suite" + local arch + arch="$(dpkg --print-architecture)" + sudo rm -f "$list_dir"/"${ppa/\//-}".list "$list_dir"/"${ppa/\//-}".sources "$list_dir"/"$list_basename".list "$list_dir"/"$list_basename".sources || true + if [ "$type" = "deb822" ]; then + cat </dev/null +Types: deb +URIs: $url +Suites: $suite +Components: $components +Architectures: $arch +Signed-By: $key_file +EOF + else + echo "deb [arch=$arch signed-by=$key_file] $url $suite $components" | sudo tee "$list_dir"/"$list_basename".list >/dev/null 2>&1 + fi +} + +# Function to check if a PPA and its lists exist +check_lists() { + local ppa=$1 + local primary=${2:-} + local secondary=${3:-} + local status_token=${4:-$primary} + local match_file= + check_lists_file= + if [ -n "$primary" ]; then + match_file=$(grep -Elr "$primary" "$list_dir" 2>/dev/null | head -n 1) + fi + if [ -z "$match_file" ] && [ -n "$secondary" ]; then + local candidate + candidate=$(grep -Elr "$secondary" "$list_dir" 2>/dev/null | head -n 1) + if [ -n "$candidate" ] && { [ -z "$primary" ] || grep -Eq "$primary" "$candidate"; }; then + match_file="$candidate" + fi + fi + if [ -n "$match_file" ]; then + local list_count + list_count="$(sudo find /var/lib/apt/lists -type f -name "*${ppa/\//_}*" | wc -l)" + if [ "$list_count" = "0" ]; then + update_lists "$ppa" "$match_file" "$status_token" + fi + check_lists_file="$match_file" + return 0 + fi + return 1 +} + +# Function to add a sources list. +add_list() { + ppa=${1-ondrej/php} + ppa_url=${2:-"$lpc_ppa/$ppa/ubuntu"} + key_source=${3:-"$ppa_url"} + package_dist=${4:-"$VERSION_CODENAME"} + branches=${5:-main} + local list_format + local list_extension + local status_token + local resolved_branches + local list_path= + list_format="$(get_sources_format)" + list_extension="$(get_sources_extension "$list_format")" + status_token="${ppa_url}|${package_dist}|${branches}" + IFS='|' read -r primary_pattern secondary_pattern <<< "$(get_repo_patterns "$list_format" "$ppa_url" "$package_dist" "$branches")" + if check_lists "$ppa" "$primary_pattern" "$secondary_pattern" "$status_token"; then + list_path="$check_lists_file" + if resolved_branches="$(handle_existing_list "$ppa" "$list_format" "$branches")"; then + branches="$resolved_branches" + else + [ -n "$resolved_branches" ] && echo "$resolved_branches" && return 1 + fi + check_lists_file= + IFS='|' read -r primary_pattern secondary_pattern <<< "$(get_repo_patterns "$list_format" "$ppa_url" "$package_dist" "$branches")" + status_token="${ppa_url}|${package_dist}|${branches}" + fi + [ -e "$key_source" ] && key_file=$key_source || key_file="$key_dir"/"${ppa/\//-}"-keyring.gpg + add_key "$ppa" "$ppa_url" "$package_dist" "$key_source" "$key_file" + write_list "$list_format" "$ppa" "$ppa_url" "$package_dist" "$branches" "$key_file" + list_path="$list_dir"/"${ppa%%/*}"-"$ID"-"${ppa#*/}"-"$package_dist"."$list_extension" + update_lists "$ppa" "$list_path" "$status_token" + . /etc/os-release + return 0; +} + +# Function to check if a PPA exists +check_ppa() { + ppa=$1 + ppa_url=${2:-"$lpc_ppa/$ppa/ubuntu"} + package_dist=${3:-"$VERSION_CODENAME"} + branches=${4:-main} + local list_format + list_format="$(get_sources_format)" + IFS='|' read -r primary_pattern secondary_pattern <<< "$(get_repo_patterns "$list_format" "$ppa_url" "$package_dist" "$branches")" + local status_token + status_token="${ppa_url}|${package_dist}|${branches}" + if check_lists "$ppa" "$primary_pattern" "$secondary_pattern" "$status_token"; then + return 0; + else + return 1; + fi +} + +# Function to remove a PPA. +remove_list() { + ppa=${1-ondrej/php} + [ -n "$2" ] && ppa_urls=("$2") || ppa_urls=("$lp_ppa/$ppa/ubuntu" "$lpc_ppa/$ppa/ubuntu") + for ppa_url in "${ppa_urls[@]}"; do + grep -lr "$ppa_url" "$list_dir" | xargs -n1 sudo rm -f + done + sudo rm -f "$key_dir"/"${ppa/\//-}"-keyring /tmp/os_lists* || true +} + +# Function to check if ubuntu ppa is up +is_ubuntu_ppa_up() { + ppa=${1:-ondrej/php} + curl -s --connect-timeout 10 --max-time 10 --head --fail "$lpc_ppa/$ppa/ubuntu/dists/$VERSION_CODENAME/Release" > /dev/null +} + +# Function to add the PPA mirror. +add_ppa_sp_mirror() { + ppa=$1 + ppa_name="$(basename "$ppa")" + remove_list "$ppa" || true + [ "${debug:?}" = "debug" ] && add_list sp/"$ppa_name" "$ppa_sp/$ppa/ubuntu" "$ppa_sp/$ppa/ubuntu/key.gpg" "$VERSION_CODENAME" "main/debug" + add_list sp/"$ppa_name" "$ppa_sp/$ppa/ubuntu" "$ppa_sp/$ppa/ubuntu/key.gpg" +} + +# Function to add a PPA. +add_ppa() { + set_base_version + ppa=${1:-ondrej/php} + if [[ "$ID" = "ubuntu" || "$ID_LIKE" =~ ubuntu ]] && [[ "$ppa" =~ "ondrej/" ]]; then + if is_ubuntu_ppa_up "$ppa" ; then + [ "${runner:?}" = "self-hosted" ] && find "$list_dir" -type f -name 'sp*' -exec grep -qF "${sp/https:\/\/}" {} \; -delete + [ "${debug:?}" = "debug" ] && add_list "$ppa" "$lpc_ppa/$ppa/ubuntu" "$lpc_ppa/$ppa/ubuntu" "$VERSION_CODENAME" "main/debug" + add_list "$ppa" + elif [ "$ppa" = "ondrej/php" ]; then + add_ppa_sp_mirror "$ppa" + else + add_log "${cross:?}" "$ppa" "PPA $ppa is not available" + fi + elif [[ "$ID" = "debian" || "$ID_LIKE" =~ debian ]] && [[ "$ppa" =~ "ondrej/" ]]; then + [ "${debug:?}" = "debug" ] && add_list "$ppa" "$sury"/"${ppa##*/}"/ "$sury"/"${ppa##*/}"/apt.gpg "$VERSION_CODENAME" "main/debug" + add_list "$ppa" "$sury"/"${ppa##*/}"/ "$sury"/"${ppa##*/}"/apt.gpg + else + add_list "$ppa" + fi + exit_code="$?" + . /etc/os-release + return $exit_code +} + +# Function to update a PPA. +update_ppa() { + set_base_version + ppa=${1:-ondrej/php} + ppa_url=${2:-"$lpc_ppa/$ppa/ubuntu"} + package_dist=${4:-"$VERSION_CODENAME"} + branches=${5:-main} + local list_format + list_format="$(get_sources_format)" + IFS='|' read -r primary_pattern secondary_pattern <<< "$(get_repo_patterns "$list_format" "$ppa_url" "$package_dist" "$branches")" + local list_path + list_path="$(grep -Elr "$primary_pattern" "$list_dir" 2>/dev/null | head -n 1)" + if [ -z "$list_path" ] && [ -n "$secondary_pattern" ]; then + list_path="$(grep -Elr "$secondary_pattern" "$list_dir" 2>/dev/null | head -n 1)" + fi + local status_token + status_token="${ppa_url}|${package_dist}|${branches}" + update_lists "$ppa" "${list_path:-$primary_pattern}" "$status_token" + . /etc/os-release +} + +# Variables +sources_format= +check_lists_file= +list_dir='/etc/apt/sources.list.d' +list_file="/etc/apt/sources.list.d/$ID.sources" +[ -e "$list_file" ] || list_file='/etc/apt/sources.list' +upstream_lsb='/etc/upstream-release/lsb-release' +lp_api=( + 'https://api.launchpad.net/1.0' + 'https://api.launchpad.net/devel' +) +lp_ppa='http://ppa.launchpad.net' +lpc_ppa='https://ppa.launchpadcontent.net' +key_dir='/usr/share/keyrings' +dist_info_dir='/usr/share/distro-info' +sury='https://packages.sury.org' +ppa_sp='https://ppa.setup-php.com' +sp='https://setup-php.com' +sks=( + 'https://keyserver.ubuntu.com' + 'https://pgp.mit.edu' + 'https://keys.openpgp.org' +) diff --git a/src/scripts/tools/protoc.ps1 b/src/scripts/tools/protoc.ps1 new file mode 100644 index 0000000..a216695 --- /dev/null +++ b/src/scripts/tools/protoc.ps1 @@ -0,0 +1,40 @@ +Function Get-ProtobufTag() { + $releases = 'https://github.com/protocolbuffers/protobuf/releases' + if("$protobuf_tag" -eq "latest") { + $protobuf_tag = (Get-File -Url $releases/latest).BaseResponse.RequestMessage.RequestUri.Segments[-1] + } else { + try { + $protobuf_tag = $protobuf_tag -replace '^v', '' + [net.httpWebRequest] $request = [net.webRequest]::create("$releases/tag/v$protobuf_tag") + $request.Method = "HEAD" + [net.httpWebResponse] $response = $request.getResponse() + $response.Close() + $protobuf_tag = "v$protobuf_tag" + } catch { + $protobuf_tag = (Get-File -Url $releases/latest).BaseResponse.RequestMessage.RequestUri.Segments[-1] + } + } + return $protobuf_tag +} + +Function Add-Protoc() { + param( + [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'The PHP version to be installed')] + [ValidatePattern('^latest$|^(v?)\d+\.\d+(\.\d+)?$')] + [string] $protobuf_tag + ) + $protobuf_tag = Get-ProtobufTag + $arch_num = '64' + if(-not([Environment]::Is64BitOperatingSystem)) { + $arch_num = '32' + } + $url = "https://github.com/protocolbuffers/protobuf/releases/download/$protobuf_tag/protoc-$($protobuf_tag -replace 'v', '')-win$arch_num.zip" + Get-File -Url $url -OutFile $bin_dir\protoc.zip >$null 2>&1 + Expand-Archive -Path $bin_dir\protoc.zip -DestinationPath $bin_dir\protoc -Force >$null 2>&1 + Move-Item -Path $bin_dir\protoc\bin\protoc.exe -Destination $bin_dir\protoc.exe + Add-ToProfile $current_profile 'protoc' "New-Alias protoc $bin_dir\protoc.exe" + Add-Log $tick "protoc" "Added protoc $($protobuf_tag -replace 'v', '')" + printf "$env:GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "protoc" "Click to read the protoc related license information" + Write-Output (Invoke-WebRequest https://raw.githubusercontent.com/protocolbuffers/protobuf/main/LICENSE).Content + Write-Output "$env:END_GROUP" +} diff --git a/src/scripts/tools/protoc.sh b/src/scripts/tools/protoc.sh new file mode 100644 index 0000000..92d7ca5 --- /dev/null +++ b/src/scripts/tools/protoc.sh @@ -0,0 +1,30 @@ +get_protobuf_tag() { + if [ "$protobuf_tag" = "latest" ]; then + protobuf_tag=$(get -s -n "" https://github.com/protocolbuffers/protobuf/releases/latest 2<&1 | grep -m 1 -Eo "tag/(v[0-9]+(\.[0-9]+)?(\.[0-9]+)?)" | head -n 1 | cut -d '/' -f 2) + else + status_code=$(get -v -n /tmp/protobuf.tmp "https://github.com/protocolbuffers/protobuf/releases/tag/v$protobuf_tag") + if [ "$status_code" = "200" ]; then + protobuf_tag="v$protobuf_tag" + else + protobuf_tag=$(get -s -n "" https://github.com/protocolbuffers/protobuf/releases/latest 2<&1 | grep -m 1 -Eo "tag/(v[0-9]+(\.[0-9]+)?(\.[0-9]+)?)" | head -n 1 | cut -d '/' -f 2) + fi + fi +} + +add_protoc() { + protobuf_tag=$1 + get_protobuf_tag + ( + platform='linux' + [ "$(uname -s)" = "Darwin" ] && platform='osx' + arch="$(uname -m)" + [[ "$arch" = 'arm64' || "$arch" = 'aarch64' ]] && arch='aarch_64' + get -q -n /tmp/protobuf.zip "https://github.com/protocolbuffers/protobuf/releases/download/$protobuf_tag/protoc-${protobuf_tag:1}-$platform-$arch.zip" + sudo unzip /tmp/protobuf.zip -d /usr/local/ + sudo chmod -R 777 /usr/local/bin/protoc /usr/local/include/google + ) >/dev/null 2>&1 + add_log "${tick:?}" "protoc" "Added protoc ${protobuf_tag:1}" + printf "$GROUP\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" "protoc" "Click to read the protoc related license information" + curl "${curl_opts[@]:?}" https://raw.githubusercontent.com/protocolbuffers/protobuf/main/LICENSE + echo "$END_GROUP" +} diff --git a/src/scripts/tools/retry.sh b/src/scripts/tools/retry.sh new file mode 100644 index 0000000..b2fa320 --- /dev/null +++ b/src/scripts/tools/retry.sh @@ -0,0 +1,20 @@ +function retry { + local try=0 + + until "$@"; do + exit_code="$?" + try=$((try + 1)) + + if [ $try -lt 10 ]; then + sleep "$((2 ** try))" + else + return $exit_code + fi + done + + return 0 +} + +function git_retry { + retry git "$@" +} \ No newline at end of file diff --git a/src/scripts/tools/symfony.ps1 b/src/scripts/tools/symfony.ps1 new file mode 100644 index 0000000..78c5bd3 --- /dev/null +++ b/src/scripts/tools/symfony.ps1 @@ -0,0 +1,32 @@ +Function Add-Symfony() { + param( + [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Symfony version to be installed')] + [string] $protobuf_tag + ) + $protobuf_tag = $protobuf_tag.replace('v', '') + if($protobuf_tag -ne 'latest' -and $protobuf_tag -notmatch '^\d+(\.\d+)*$') { + Add-Log $cross "symfony-cli" "Invalid symfony version: $protobuf_tag" + } else { + $arch_name = 'amd64' + if (-not ([Environment]::Is64BitOperatingSystem) -or $version -lt '7.0') { + $arch_name = '386' + } + $symfony_releases = "https://github.com/symfony-cli/symfony-cli/releases" + if ($protobuf_tag -eq 'latest') { + $url = "$symfony_releases/latest/download/symfony-cli_windows_${arch_name}.zip" + } else { + $url = "$symfony_releases/download/v$protobuf_tag/symfony-cli_windows_${arch_name}.zip" + } + Get-File -Url $url -OutFile $bin_dir\symfony.zip > $null 2>&1 + Expand-Archive -Path $bin_dir\symfony.zip -DestinationPath $bin_dir -Force > $null 2>&1 + if (Test-Path $bin_dir\symfony.exe) { + Copy-Item -Path $bin_dir\symfony.exe -Destination $bin_dir\symfony-cli.exe > $null 2>&1 + Add-ToProfile $current_profile 'symfony' "New-Alias symfony $bin_dir\symfony.exe" + Add-ToProfile $current_profile 'symfony_cli' "New-Alias symfony-cli $bin_dir\symfony-cli.exe" + $tool_version = Get-ToolVersion symfony "-V" + Add-Log $tick "symfony-cli" "Added symfony-cli $tool_version" + } else { + Add-Log $cross "symfony-cli" "Could not setup symfony-cli" + } + } +} diff --git a/src/scripts/tools/symfony.sh b/src/scripts/tools/symfony.sh new file mode 100644 index 0000000..f0f7888 --- /dev/null +++ b/src/scripts/tools/symfony.sh @@ -0,0 +1,44 @@ +get_symfony_artifact_url() { + local symfony_tag=$1 + local os + local arch + os="$(uname -s | tr '[:upper:]' '[:lower:]')" + arch="$(uname -m)" + case "$arch" in + arm|armv6*|armv7*) arch="armv6" ;; + aarch64*|armv8*|arm64) arch="arm64" ;; + i[36]86) arch="386" ;; + x86_64|amd64) arch="amd64" ;; + esac + [ "$os" = "darwin" ] && arch="all" + symfony_releases="https://github.com/symfony-cli/symfony-cli/releases" + if [ "$symfony_tag" = "latest" ]; then + echo "$symfony_releases/latest/download/symfony-cli_${os}_${arch}.tar.gz" + else + echo "$symfony_releases/download/v$symfony_tag/symfony-cli_${os}_${arch}.tar.gz" + fi +} + +add_symfony_helper() { + local install_dir=/usr/local/bin + [ "$(uname -s)" = "Darwin" ] && install_dir=${brew_prefix:?}/bin + get -s -n "" "$(get_symfony_artifact_url "$symfony_tag")" | sudo tar -xz -C "$install_dir" 2>/dev/null + sudo chmod a+x "$install_dir"/symfony +} + +add_symfony() { + local symfony_tag="${1/v/}" + if ! [[ "$symfony_tag" =~ ^[0-9]+(\.[0-9]+)*$ || "$symfony_tag" == 'latest' ]]; then + add_log "${cross:?}" "symfony-cli" "Version '$symfony_tag' is not valid for symfony-cli" + else + add_symfony_helper "$symfony_tag" >/dev/null 2>&1 + symfony_path="$(command -v symfony)" + if [[ -n "$symfony_path" ]]; then + sudo ln -s "$symfony_path" "${tool_path_dir:?}"/symfony-cli + tool_version=$(get_tool_version "symfony" "-V") + add_log "${tick:?}" "symfony-cli" "Added symfony-cli $tool_version" + else + add_log "${cross:?}" "symfony-cli" "Could not setup symfony-cli" + fi + fi +} diff --git a/src/scripts/unix.sh b/src/scripts/unix.sh new file mode 100644 index 0000000..f0f45fe --- /dev/null +++ b/src/scripts/unix.sh @@ -0,0 +1,277 @@ +# Variables +export tick="✓" +export cross="✗" +export curl_opts=(-sL) +export old_versions="5.[3-5]" +export jit_versions="8.[0-9]" +export php_builder_versions="8.[3-9]" +export nightly_versions="8.[6-9]" +export xdebug3_versions="7.[2-4]|8.[0-9]" +export latest="releases/latest/download" +export github="https://github.com/shivammathur" +export jsdeliver="https://cdn.jsdelivr.net/gh/shivammathur" +export setup_php="https://setup-php.com" + +if [ -n "${GITHUB_ACTIONS}" ]; then + export GROUP='::group::' + export END_GROUP='::endgroup::' +else + export GROUP='' + export END_GROUP='' +fi + +# Function to log start of a operation. +step_log() { + local message=$1 + printf "\n\033[90;1m==> \033[0m\033[37;1m%s\033[0m\n" "$message" +} + +# Function to log result of a operation. +add_log() { + local mark=$1 + local subject=$2 + local message=$3 + if [ "$mark" = "$tick" ]; then + printf "\033[32;1m%s \033[0m\033[34;1m%s \033[0m\033[90;1m%s\033[0m\n" "$mark" "$subject" "$message" + else + printf "\033[31;1m%s \033[0m\033[34;1m%s \033[0m\033[90;1m%s\033[0m\n" "$mark" "$subject" "$message" + [ "$fail_fast" = "true" ] && exit 1 + fi +} + +# Function to set output on GitHub Actions. +set_output() { + name=$1 + value=$2 + if [ "${GITHUB_ACTIONS}" = "true" ]; then + echo "${name}=${value}" | tee -a "$GITHUB_OUTPUT" >/dev/null 2>&1 + fi +} + +# Function to read env inputs. +read_env() { + update="${update:-${UPDATE:-false}}" + [ "${debug:-${DEBUG:-false}}" = "true" ] && debug=debug && update=true || debug=release + [[ "${phpts:-${PHPTS:-nts}}" = "ts" || "${phpts:-${PHPTS:-nts}}" = "zts" ]] && ts=zts && update=true || ts=nts + fail_fast="${fail_fast:-${FAIL_FAST:-false}}" + [[ ( -z "$ImageOS" && -z "$ImageVersion" ) || + ( -n "$RUNNER_ENVIRONMENT" && "$RUNNER_ENVIRONMENT" = "self-hosted" ) || + -n "$ACT" || -n "$CONTAINER" ]] && _runner=self-hosted || _runner=github + runner="${runner:-${RUNNER:-$_runner}}" + tool_path_dir="${setup_php_tools_dir:-${SETUP_PHP_TOOLS_DIR:-/usr/local/bin}}" + tool_cache_path_dir="${setup_php_tool_cache_dir:-${SETUP_PHP_TOOL_CACHE_DIR:-${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}/setup-php/tools}}" + + if [[ "$runner" = "github" && $_runner = "self-hosted" ]]; then + fail_fast=true + add_log "$cross" "Runner" "Runner set as github in self-hosted environment" + fi + + # Set Update to true if the ubuntu github image does not have PHP PPA. + if [[ "$runner" = "github" && "${ImageOS}" =~ ubuntu.* ]]; then + if ! check_ppa ondrej/php; then + update=true + echo '' | sudo tee /tmp/sp_update >/dev/null 2>&1 + elif [ -e /tmp/sp_update ]; then + update=true + fi + fi + + export fail_fast + export runner + export update + export ts + export tool_path_dir + export tool_cache_path_dir +} + +# Function to create a lock. +acquire_lock() { + lock_path="$1" + while true; do + if sudo mkdir "$lock_path" 2>/dev/null; then + echo $$ | sudo tee "$lock_path/pid" >/dev/null + return 0 + else + if sudo test -f "$lock_path/pid"; then + lock_pid=$(sudo cat "$lock_path/pid") + if ! ps -p "$lock_pid" >/dev/null 2>&1; then + sudo rm -rf "$lock_path" + continue + fi + fi + sleep 1 + fi + done +} + +# Function to release the lock. +release_lock() { + lock_path="$1" + sudo rm -rf "$lock_path" +} + +# Function to get the SHA256 hash of a string. +get_sha256() { + local input=$1 + if command -v sha256sum >/dev/null; then + printf '%s' "$input" | sha256sum | cut -d' ' -f1 + elif command -v shasum >/dev/null; then + printf '%s' "$input" | shasum -a 256 | cut -d' ' -f1 + elif command -v openssl >/dev/null; then + printf '%s' "$input" | openssl dgst -sha256 | cut -d' ' -f2 + fi +} + +# Function to download a file using cURL. +# mode: -s pipe to stdout, -v save file and return status code +# execute: -e save file as executable +get() { + mode=$1 + execute=$2 + file_path=$3 + shift 3 + links=("$@") + if [ "$mode" = "-s" ]; then + sudo curl "${curl_opts[@]}" "${links[0]}" + else + if [ "$runner" = "self-hosted" ]; then + lock_path="/tmp/sp-lck-$(get_sha256 "$file_path")" + acquire_lock "$lock_path" + if [ "$execute" = "-e" ]; then + until [ -z "$(fuser "$file_path" 2>/dev/null)" ]; do + sleep 1 + done + fi + trap 'release_lock "$lock_path"' EXIT SIGINT SIGTERM + fi + for link in "${links[@]}"; do + status_code=$(sudo curl -w "%{http_code}" -o "$file_path" "${curl_opts[@]}" "$link") + [ "$status_code" = "200" ] && break + done + [[ "$execute" = "-e" && -e "$file_path" ]] && sudo chmod a+x "$file_path" + [ "$mode" = "-v" ] && echo "$status_code" + [ "$runner" = "self-hosted" ] && release_lock "$lock_path" + fi +} + +# Function to get shell profile. +get_shell_profile() { + case "$SHELL" in + *bash*) + echo "${HOME}/.bashrc" + ;; + *zsh*) + echo "${HOME}/.zshrc" + ;; + *) + echo "${HOME}/.profile" + ;; + esac +} + +# Function to add a path to the PATH variable. +add_path() { + path_to_add=$1 + action=$2 + [[ "$action" == "verify" && ":$PATH:" == *":$path_to_add:"* ]] && return + if [[ -n "$GITHUB_PATH" ]]; then + printf '%s\n%s' "$path_to_add" "$(grep -v "^${path_to_add}$" "$GITHUB_PATH" 2>/dev/null)" > "$GITHUB_PATH" + else + profile=$(get_shell_profile) + ([ -e "$profile" ] && grep -q ":$path_to_add\"" "$profile" 2>/dev/null) || echo "export PATH=\"\${PATH:+\${PATH}:}\"$path_to_add" | sudo tee -a "$profile" >/dev/null 2>&1 + fi + [[ ":$PATH:" == *":$path_to_add:"* ]] || export PATH="${PATH:+${PATH}:}$path_to_add" +} + +# Function to add environment variables using a PATH. +add_env_path() { + env_path=$1 + [ -e "$env_path" ] || return + if [[ -n "$GITHUB_ENV" ]]; then + cat "$env_path" >> "$GITHUB_ENV" + else + profile=$(get_shell_profile) + cat "$env_path" >> "$profile" + fi +} + +# Function to add an environment variable. +add_env() { + env_name=$1 + env_value=$2 + if [[ -n "$GITHUB_ENV" ]]; then + echo "$env_name=$env_value" | tee -a "$GITHUB_ENV" >/dev/null 2>&1 + else + profile=$(get_shell_profile) + echo "export $env_name=\"$env_value\"" | sudo tee -a "$profile" >/dev/null 2>&1 + fi + export "$env_name"="$env_value" +} + +# Function to download and run scripts from GitHub releases with jsdeliver fallback. +run_script() { + repo=$1 + shift + args=("$@") + get -q -e /tmp/install.sh "$github/$repo/$latest/install.sh" "$jsdeliver/$repo@main/scripts/install.sh" "$setup_php/$repo/install.sh" + bash /tmp/install.sh "${args[@]}" +} + +# Function to install required packages on self-hosted runners. +self_hosted_setup() { + if [ "$runner" = "self-hosted" ]; then + if [[ "${version:?}" =~ $old_versions ]]; then + add_log "$cross" "PHP" "PHP $version is not supported on self-hosted runner" + exit 1 + else + self_hosted_helper >/dev/null 2>&1 + add_env RUNNER_TOOL_CACHE /opt/hostedtoolcache + fi + fi +} + +# Function to check pre-installed PHP +check_pre_installed() { + if [ "$version" = "pre" ]; then + if [ -n "$php_config" ]; then + version="$(php_semver | cut -c 1-3)" + update=false + else + fail_fast=true + add_log "$cross" "PHP" "No pre-installed PHP version found" + fi + fi +} + +# Function to configure PHP +configure_php() { + add_php_config + ini_config_dir="${src:?}"/configs/ini + ini_config_files=("$ini_config_dir"/php.ini) + arch="$(uname -m)" + [[ "$arch" = "arm64" || "$arch" = "aarch64" ]] && jit_ini="$ini_config_dir"/jit_aarch64.ini || jit_ini="$ini_config_dir"/jit.ini + jit_config_files=("$jit_ini") + [[ "$version" =~ $xdebug3_versions ]] && ini_config_files+=("$ini_config_dir"/xdebug.ini) + cat "${ini_config_files[@]}" | sudo tee -a "${ini_file[@]:?}" >/dev/null 2>&1 + [[ "$version" =~ $jit_versions ]] && cat "${jit_config_files[@]}" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1 +} + +# Function to get PHP version in semver format. +php_semver() { + grep -Eo 'version="[0-9]+(\.[0-9]+){2}((-?[a-zA-Z]+([0-9]+)?)?){2}' "${php_config:?}" | cut -d '"' -f 2 +} + +# Function to get ini_path. +php_ini_path() { + cut -d '"' -f 2 < <(grep "ini_path=" "$php_config" || php --ini | grep '(php.ini)' | sed -e "s|.*: s*||") +} + +# Function to get the tag for a php version. +php_src_tag() { + commit=$(php_extra_version | grep -Eo "[0-9a-zA-Z]+") + if [[ -n "${commit}" ]]; then + echo "$commit" + else + echo "php-${semver:?}" + fi +} diff --git a/src/scripts/win32.ps1 b/src/scripts/win32.ps1 new file mode 100644 index 0000000..1fb43b2 --- /dev/null +++ b/src/scripts/win32.ps1 @@ -0,0 +1,460 @@ +param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $version = '8.4', + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $ini = 'production' +) + +# Function to log start of a operation. +Function Step-Log($message) { + printf "\n\033[90;1m==> \033[0m\033[37;1m%s \033[0m\n" $message +} + +# Function to log result of a operation. +Function Add-Log($mark, $subject, $message) { + if ($mark -eq $tick) { + printf "\033[32;1m%s \033[0m\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" $mark $subject $message + } else { + printf "\033[31;1m%s \033[0m\033[34;1m%s \033[0m\033[90;1m%s \033[0m\n" $mark $subject $message + if($env:fail_fast -eq 'true') { + Write-Error $message -ErrorAction Stop + } + } +} + +# Function to set output on GitHub Actions. +Function Set-Output() { + param( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $output, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $value + ) + if ($env:GITHUB_ACTIONS -eq 'true') { + Add-Content "$output=$value" -Path $env:GITHUB_OUTPUT -Encoding utf8 + } +} + +# Function to add a line to a powershell profile safely. +Function Add-ToProfile { + param( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $input_profile, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $search, + [Parameter(Position = 2, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $value + ) + if($null -eq (Get-Content $input_profile | findstr $search)) { + Add-Content -Path $input_profile -Value $value + } +} + +# Function to fetch PATH from the registry. +Function Get-PathFromRegistry { + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","User") + ";" + + [System.Environment]::GetEnvironmentVariable("Path","Machine") + Add-ToProfile $current_profile 'Get-PathFromRegistry' 'Function Get-PathFromRegistry { $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "User") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "Machine") }; Get-PathFromRegistry' +} + +# Function to add a location to PATH. +Function Add-Path { + param( + [string]$PathItem, + [switch]$Force + ) + if(-not($Force) -and "$env:PATH;".contains("$PathItem;")) { + return + } + if ($env:GITHUB_PATH) { + Add-Content $PathItem -Path $env:GITHUB_PATH -Encoding utf8 + $env:PATH += "$PathItem;" + } else { + $newPath = (Get-ItemProperty -Path 'hkcu:\Environment' -Name PATH).Path.replace("$PathItem;", '') + $newPath = $PathItem + ';' + $newPath + Set-ItemProperty -Path 'hkcu:\Environment' -Name Path -Value $newPath + Get-PathFromRegistry + } +} + +# Function to add an environment variable. +Function Add-Env { + param( + [string]$EnvName, + [string]$EnvValue + ) + if ($env:GITHUB_ENV) { + Add-Content "$EnvName=$EnvValue" -Path $env:GITHUB_ENV -Encoding utf8 + } else { + Set-ItemProperty -Path 'hkcu:\Environment' -Name $EnvName -Value $EnvValue + Add-ToProfile $current_profile $EnvName "`$env:$EnvName=`"$EnvValue`"" + } +} + +# Function to add environment variables using a PATH. +Function Add-EnvPATH { + param( + [string]$EnvPATH + ) + if(-not(Test-Path $EnvPATH)) { + return + } + $env_file = $env:GITHUB_ENV + $env_data = Get-Content -Path $EnvPATH + if (-not($env:GITHUB_ENV)) { + $env_file = $current_profile + $env_data = $env_data | ForEach-Object { '$env:' + $_ } + } + $env_data | Add-Content -Path $env_file -Encoding utf8 +} + +# Function to fetch a file from a URL. +Function Get-File { + param ( + [string]$Url, + [string]$FallbackUrl, + [string]$OutFile = '', + [int]$Retries = 3, + [int]$TimeoutSec = 0 + ) + + for ($i = 0; $i -lt $Retries; $i++) { + try { + if($OutFile -ne '') { + Invoke-WebRequest -Uri $Url -OutFile $OutFile -TimeoutSec $TimeoutSec + } else { + Invoke-WebRequest -Uri $Url -TimeoutSec $TimeoutSec + } + break; + } catch { + if ($i -eq ($Retries - 1)) { + if($FallbackUrl) { + try { + if($OutFile -ne '') { + Invoke-WebRequest -Uri $FallbackUrl -OutFile $OutFile -TimeoutSec $TimeoutSec + } else { + Invoke-WebRequest -Uri $FallbackUrl -TimeoutSec $TimeoutSec + } + } catch { + throw "Failed to download the assets from $Url and $FallbackUrl" + } + } else { + throw "Failed to download the assets from $Url" + } + } + } + } +} + +# Function to make sure printf is in PATH. +Function Add-Printf { + if (-not(Test-Path "C:\Program Files\Git\usr\bin\printf.exe")) { + if(Test-Path "C:\msys64\usr\bin\printf.exe") { + New-Item -Path $bin_dir\printf.exe -ItemType SymbolicLink -Value C:\msys64\usr\bin\printf.exe -Force > $null 2>&1 + } else { + Get-File -Url "$github/shivammathur/printf/releases/latest/download/printf-x64.zip" -OutFile "$bin_dir\printf.zip" + Expand-Archive -Path $bin_dir\printf.zip -DestinationPath $bin_dir -Force + } + } else { + New-Item -Path $bin_dir\printf.exe -ItemType SymbolicLink -Value "C:\Program Files\Git\usr\bin\printf.exe" -Force > $null 2>&1 + } +} + +# Function to get a clean Powershell profile. +Function Get-CleanPSProfile { + if(-not(Test-Path -LiteralPath $profile)) { + New-Item -Path $profile -ItemType "file" -Force > $null 2>&1 + } + Set-Content $current_profile -Value '' + Add-ToProfile $profile $current_profile.replace('\', '\\') ". $current_profile" +} + +# Function to install a powershell package from GitHub. +Function Install-PSPackage() { + param( + [Parameter(Position = 0, Mandatory = $true)] + $package, + [Parameter(Position = 1, Mandatory = $true)] + $psm1_path, + [Parameter(Position = 2, Mandatory = $true)] + $url, + [Parameter(Position = 3, Mandatory = $true)] + $cmdlet + ) + $module_path = "$bin_dir\$psm1_path.psm1" + if(-not (Test-Path $module_path -PathType Leaf)) { + $zip_file = "$bin_dir\$package.zip" + Get-File -Url $url -OutFile $zip_file + Expand-Archive -Path $zip_file -DestinationPath $bin_dir -Force + } + Import-Module $module_path + if($null -eq (Get-Command $cmdlet -ErrorAction SilentlyContinue)) { + Install-Module -Name $package -Force + } else { + Add-ToProfile $current_profile "$package-search" "Import-Module $module_path" + } +} + +# Function to add CA certificates to PHP. +Function Add-PhpCAInfo { + try { + Update-PhpCAInfo -Path $php_dir -Source Curl + } catch { + Add-Log $cross PHP "Could not fetch CA certificate bundle from Curl" + Update-PhpCAInfo -Path $php_dir -Source CurrentUser + } +} + +# Function to set OpenSSL config. +Function Add-OpenSSLConf { + try { + Set-OpenSSLConf -Target User + } catch { + New-Item $php_dir\extras\openssl.cnf -Type File -Force > $null 2>&1 + Set-OpenSSLConf -Path $php_dir\extras\openssl.cnf -Target User + } + Add-Env -EnvName OPENSSL_CONF -EnvValue $env:OPENSSL_CONF +} + +# Function to set PHP config. +Function Add-PhpConfig { + $current = Get-Content -Path $php_dir\php.ini-current -ErrorAction SilentlyContinue + if($ini -eq 'development' -or ($ini -eq 'production' -and $current -and $current -ne 'production')) { + Copy-Item -Path $php_dir\php.ini-$ini -Destination $php_dir\php.ini -Force + } elseif ($ini -eq 'none') { + Set-Content -Path $php_dir\php.ini -Value '' + } + Set-Content -Path $php_dir\php.ini-current -Value $ini + $ini_config_dir = "$src\configs\ini" + $ini_files = @("$ini_config_dir\php.ini") + $version -match $jit_versions -and ($ini_files += ("$ini_config_dir\jit.ini")) > $null 2>&1 + $version -match $xdebug3_versions -and ($ini_files += ("$ini_config_dir\xdebug.ini")) > $null 2>&1 + Add-Content -Path $ini_config_dir\php.ini -Value extension_dir=$ext_dir + Get-Content -Path $ini_files | Add-Content -Path $php_dir\php.ini +} + +# Function to get PHP from GitHub releases cache +Function Set-PhpCache { + try { + try { + $release = Invoke-RestMethod https://api.github.com/repos/shivammathur/php-builder-windows/releases/tags/php$version + $asset = $release.assets | ForEach-Object { + if($_.name -match "php-$version.[0-9]+$env:PHPTS-Win32-.*-$arch.zip") { + return $_.name + } + } | Select-Object -Last 1 + if($null -eq $asset) { + throw "Asset not found" + } + } catch { + $release = Get-File -Url $php_builder/releases/expanded_assets/php$version + $asset = $release.links.href | ForEach-Object { + if($_ -match "php-$version.[0-9]+$env:PHPTS-Win32-.*-$arch.zip") { + return $_.split('/')[-1] + } + } | Select-Object -Last 1 + } + Get-File -Url $php_builder/releases/download/php$version/$asset -OutFile $php_dir\$asset + Set-PhpDownloadCache -Path $php_dir CurrentUser + } catch { } +} + +# Function to add debug symbols to PHP. +Function Add-DebugSymbols { + $dev = if ($version -match $nightly_versions) { '-dev' } else { '' } + try { + $release = Invoke-RestMethod https://api.github.com/repos/shivammathur/php-builder-windows/releases/tags/php$version + $asset = $release.assets | ForEach-Object { + if($_.name -match "php-debug-pack-$version.[0-9]+$dev$env:PHPTS-Win32-.*-$arch.zip") { + return $_.name + } + } | Select-Object -Last 1 + } catch { + $release = Get-File -Url $php_builder/releases/expanded_assets/php$version + $asset = $release.links.href | ForEach-Object { + if($_ -match "php-debug-pack-$version.[0-9]+$dev$env:PHPTS-Win32-.*-$arch.zip") { + return $_.split('/')[-1] + } + } | Select-Object -Last 1 + } + Get-File -Url $php_builder/releases/download/php$version/$asset -OutFile $php_dir\$asset + Expand-Archive -Path $php_dir\$asset -DestinationPath $php_dir -Force + Get-ChildItem -Path $php_dir -Filter php_*.pdb | Move-Item -Destination $ext_dir +} + +# Function to install nightly version of PHP +Function Install-PhpNightly { + Get-File -Url $php_builder/releases/latest/download/Get-PhpNightly.ps1 -FallbackUrl https://dl.cloudsmith.io/public/shivammathur/php-builder-windows/raw/files/Get-PhpNightly.ps1 -OutFile $php_dir\Get-PhpNightly.ps1 > $null 2>&1 + & $php_dir\Get-PhpNightly.ps1 -Architecture $arch -ThreadSafe $ts -Path $php_dir -Version $version > $null 2>&1 + if(Test-Path $php_dir\COMMIT) { + return " ($( Get-Content $php_dir\COMMIT ))" + } + return; +} + +# Variables +$tick = ([char]8730) +$cross = ([char]10007) +$php_dir = 'C:\tools\php' +$ext_dir = "$php_dir\ext" +$bin_dir = $php_dir +$github = 'https://github.com' +$php_builder = "$github/shivammathur/php-builder-windows" +$current_profile = "$env:TEMP\setup-php.ps1" +$ProgressPreference = 'SilentlyContinue' +$jit_versions = '8.[0-9]' +$nightly_versions = '8.[6-9]' +$xdebug3_versions = "7.[2-4]|8.[0-9]" +$enable_extensions = ('openssl', 'curl', 'mbstring') + +$arch = 'x64' +if(-not([Environment]::Is64BitOperatingSystem) -or $version -lt '7.0') { + $arch = 'x86' +} + +$ts = ($env:PHPTS -match '^z?ts$') +if(-not($ts)) { + $env:PHPTS = '-nts' +} else { + $env:PHPTS = '' +} + +if ( $env:GITHUB_ACTIONS -eq 'true') { + $env:GROUP = '::group::' + $env:END_GROUP = '::endgroup::' +} else { + $env:GROUP = '' + $env:END_GROUP = '' +} + +if(-not($env:ImageOS) -and -not($env:ImageVersion)) { + if($env:RUNNER -eq 'github') { + Add-Log $cross "Runner" "Runner set as github in self-hosted environment" + Write-Error "Runner set as github in self-hosted environment" -ErrorAction Stop + } + $bin_dir = 'C:\tools\bin' + $php_dir = "$php_dir$version" + $ext_dir = "$php_dir\ext" + Get-CleanPSProfile >$null 2>&1 + New-Item $bin_dir -Type Directory -Force > $null 2>&1 + Add-Path -PathItem $bin_dir + if($version -lt 5.6) { + Add-Log $cross "PHP" "PHP $version is not supported on self-hosted runner" + Start-Sleep 1 + Write-Error "PHP $version is not supported on self-hosted runner" -ErrorAction Stop + } + if ($null -eq (Get-Module -ListAvailable -Name VcRedist)) { + Install-Module -Name VcRedist -Force + } + New-Item $php_dir -Type Directory -Force > $null 2>&1 + Add-Path -PathItem $php_dir + setx PHPROOT $php_dir >$null 2>&1 + Add-Env -EnvName RUNNER_TOOL_CACHE -EnvValue $env:TEMP +} else { + $current_profile = "$PSHOME\Profile.ps1" + if(-not(Test-Path -LiteralPath $current_profile)) { + New-Item -Path $current_profile -ItemType "file" -Force >$null 2>&1 + } + Add-Path -PathItem $bin_dir -Force +} + +$src = Join-Path -Path $PSScriptRoot -ChildPath \.. +. $src\scripts\tools\add_tools.ps1 +. $src\scripts\extensions\add_extensions.ps1 + +Add-Printf >$null 2>&1 +Step-Log "Setup PhpManager" +Install-PSPackage PhpManager PhpManager\PhpManager "$github/mlocati/powershell-phpmanager/releases/latest/download/PhpManager.zip" Get-Php >$null 2>&1 +Add-Log $tick "PhpManager" "Installed" + +Step-Log "Setup PHP" +$installed = $null +if (Test-Path -LiteralPath $php_dir -PathType Container) { + try { + if(Test-Path $php_dir\php.ini) { + Rename-Item -Path $php_dir\php.ini -NewName 'php.ini.bak' + } + $installed = Get-Php -Path $php_dir -ErrorAction SilentlyContinue 2>$null 3>$null + if(Test-Path $php_dir\php.ini.bak) { + Rename-Item -Path $php_dir\php.ini.bak -NewName 'php.ini' + } + } catch { } +} +$status = "Installed" +$extra_version = "" +if($version -eq 'pre') { + if($null -ne $installed) { + $version = $installed.MajorMinorVersion + $env:update = 'false' + } else { + Add-Log $cross "PHP" "No pre-installed PHP version found" + Write-Error "No pre-installed PHP version found" -ErrorAction Stop + } +} +if ($null -eq $installed -or -not("$($installed.Version).".StartsWith(($version -replace '^(\d+(\.\d+)*).*', '$1.'))) -or $ts -ne $installed.ThreadSafe) { + if ($version -lt '7.0' -and ($null -eq (Get-Module -ListAvailable -Name VcRedist))) { + Install-PSPackage VcRedist VcRedist-main\VcRedist\VcRedist "$github/aaronparker/VcRedist/archive/main.zip" Get-VcList >$null 2>&1 + } + try { + if ($version -match $nightly_versions) { + $extra_version = Install-PhpNightly + } else { + Set-PhpCache + Install-Php -Version $version -Architecture $arch -ThreadSafe $ts -InstallVC -Path $php_dir -TimeZone UTC -InitialPhpIni production -Force > $null 2>&1 + } + Add-PhpConfig + } catch { } +} else { + if($env:update -eq 'true') { + Update-Php $php_dir >$null 2>&1 + $status = "Updated to" + } else { + $status = "Found" + } + Add-PhpConfig +} + +if($env:DEBUG -eq 'true') { + Add-DebugSymbols +} + +$installed = Get-Php -Path $php_dir +if($installed.MajorMinorVersion -ne $version) { + Add-Log $cross "PHP" "Could not setup PHP $version" + Write-Error "Could not setup PHP $version" -ErrorAction Stop +} +if($version -lt "5.5") { + ('libeay32.dll', 'ssleay32.dll') | ForEach-Object -Parallel { Invoke-WebRequest -Uri "$using:php_builder/releases/download/openssl-1.0.2u/$_" -OutFile $using:php_dir\$_ >$null 2>&1 } +} elseif($version -lt "8.5") { + $enable_extensions += ('opcache') +} +if($version -ge "8.5" -and (Test-Path $ext_dir\php_opcache.dll)) { + Remove-Item $ext_dir\php_opcache.dll -Force +} +Enable-PhpExtension -Extension ($enable_extensions | Where-Object { Test-Path $ext_dir\php_$_.dll }) -Path $php_dir +Add-PhpCAInfo +Add-OpenSSLConf +Copy-Item -Path $src\configs\pm\*.json -Destination $env:RUNNER_TOOL_CACHE +Set-Output php-version $($installed.FullVersion) +Add-Log $tick "PHP" "$status PHP $($installed.FullVersion)$extra_version" diff --git a/src/tools.ts b/src/tools.ts new file mode 100644 index 0000000..39efe07 --- /dev/null +++ b/src/tools.ts @@ -0,0 +1,719 @@ +import path from 'path'; +import fs from 'fs'; +import * as cv from 'compare-versions'; +import * as fetch from './fetch'; +import * as packagist from './packagist'; +import * as utils from './utils'; + +/** + * Valid function names for custom tool handlers + */ +type ToolFunction = + | 'castor' + | 'composer' + | 'deployer' + | 'dev_tools' + | 'phive' + | 'blackfire_player' + | 'pecl' + | 'phing' + | 'phpunit' + | 'phpcpd' + | 'wp_cli'; + +/** + * Tool data interface containing all properties for tool installation + */ +export interface ToolData { + tool: string; + version: string; + os: string; + php_version: string; + github: string; + domain: string; + extension: string; + repository: string; + prefix: string; + verb: string; + fetch_latest: 'true' | 'false'; + scope: string; + version_parameter: string; + version_prefix: string; + release: string; + packagist: string; + type?: string; + function?: ToolFunction; + alias?: string; + url: string; + uri?: string; + error?: string; +} + +/** + * Input type for functions that may receive partial/unresolved tool data + * Used by getUrl, getLatestVersion etc. before version is fully resolved + */ +export type ToolInput = Omit & {version?: string}; + +/** + * Partial tool data from tools.json configuration + */ +interface ToolConfig { + tool?: string; + repository?: string; + type?: string; + function?: ToolFunction; + alias?: string; + domain?: string; + extension?: string; + fetch_latest?: 'true' | 'false'; + scope?: string; + version_parameter?: string; + version_prefix?: string; + packagist?: string; +} + +/** + * GitHub reference object from API response + */ +interface GitHubRef { + ref: string; + node_id: string; + url: string; + object: { + sha: string; + type: string; + url: string; + }; +} + +/** + * Deployer manifest entry + */ +interface DeployerManifestEntry { + version: string; + url: string; +} + +/** + * Function to get version in semver format. + * + * @param data + */ +export async function getSemverVersion(data: ToolData): Promise { + const fixSemver = (t: string): string => { + if (/^\d+\.\d+\.\d+(-|$)/.test(t)) return t; + const m = t.match(/^(\d+\.\d+\.\d+)([A-Za-z]+[0-9A-Za-z.]+)$/); + return m ? `${m[1]}-${m[2]}` : t; + }; + const search: string = data['version_prefix'] + data['version']; + const url = `https://api.github.com/repos/${data['repository']}/git/matching-refs/tags%2F${search}.`; + const github_token: string = + (await utils.readEnv('GITHUB_TOKEN')) || + (await utils.readEnv('COMPOSER_TOKEN')); + const response = await fetch.fetch(url, github_token); + if (response.error || response.data === '[]') { + data.error = response.error ?? `No version found with prefix ${search}.`; + return data.version; + } else { + const refs: GitHubRef[] = JSON.parse(response.data); + const tags = refs + .map((i: GitHubRef) => + (i.ref?.split('/').pop() ?? '').replace(/^v(?=\d)/, '') + ) + .filter((t: string) => t.length > 0); + const fixedToOriginal = new Map(); + const fixed = tags.map(t => { + const f = fixSemver(t); + fixedToOriginal.set(f, t); + return f; + }); + const sorted = fixed.toSorted((a, b) => { + try { + return cv.compareVersions(b, a); + } catch { + return b.localeCompare(a, 'en', {numeric: true, sensitivity: 'base'}); + } + }); + return fixedToOriginal.get(sorted[0]) ?? sorted[0]; + } +} + +/** + * Function to get latest version from releases.atom + * + * @param data + */ +export async function getLatestVersion(data: ToolInput): Promise { + if (!data.version && data.fetch_latest === 'false') { + return 'latest'; + } + if (data.fetch_latest === 'true' && !data.repository) { + return 'latest'; + } + const resp = await fetch.fetch( + `${data.github}/${data.repository}/releases.atom` + ); + if (resp.data) { + const releases: string[] = [ + ...resp.data.matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+\.\d+\.\d+)"/g) + ].map(match => match[2]); + + const sorted = releases.toSorted((a: string, b: string) => + a.localeCompare(b, undefined, {numeric: true}) + ); + return sorted.at(-1) || 'latest'; + } + return 'latest'; +} + +/** + * Function to get tool version + * + * @param version + * @param data + */ +export async function getVersion( + version: string, + data: ToolData +): Promise { + // semver_regex - https://semver.org/ + const semver_regex = + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; + const composer_regex = /^composer:(stable|preview|snapshot|[12])$/; + const constraint_regex = /[><=^~]+.*/; + const major_minor_regex = /^\d+(\.\d+)?$/; + data.version = version.replace(/v?(\d)/, '$1').replace(/\.x/, ''); + switch (true) { + case composer_regex.test(data.release): + case semver_regex.test(data.version): + case constraint_regex.test(data.version) && data.type === 'composer': + return data.version; + case major_minor_regex.test(data.version) && data.type === 'composer': + data.release = `${data.tool}:${data.version}.*`; + return `${data.version}.*`; + case !!data.repository && major_minor_regex.test(data.version): + return await getSemverVersion(data); + default: + return data.version.replace(/[><=^~]*/, ''); + } +} + +/** + * Function to parse the release tool:version + * + * @param release + * @param data + */ +export async function getRelease( + release: string, + data: ToolData +): Promise { + release = release.includes('/') ? release.split('/')[1] : release; + return release.includes(':') + ? [data.tool, release.split(':')[1]].join(':') + : data.tool; +} + +/** + * Function to add/move composer in the tools list + * + * @param tools_list + */ +export async function filterList(tools_list: string[]): Promise { + const regex_any = /^composer($|:.*)/; + const regex_valid = + /^composer:?($|preview$|snapshot$|v?\d+(\.\d+)?$|v?\d+\.\d+\.\d+[\w-]*$)/; + const matches: string[] = tools_list.filter(tool => regex_valid.test(tool)); + let composer = 'composer'; + tools_list = tools_list.filter(tool => !regex_any.test(tool)); + switch (true) { + case matches[0] == undefined: + break; + default: + composer = matches.at(-1)!.replace(/v(\d\S*)/, '$1'); + break; + } + tools_list.unshift(composer); + return tools_list; +} + +/** + * Function to get the url of tool with the given version + * + * @param data + */ +export async function getUrl(data: ToolInput): Promise { + const version = data.version ?? 'latest'; + if (version === 'latest' || version === '') { + return [ + data.domain, + data.repository, + data.prefix, + 'latest', + data.verb, + data.tool + data.extension + ] + .filter(Boolean) + .join('/'); + } else { + return [ + data.domain, + data.repository, + data.prefix, + data.verb, + data.version_prefix + data.version, + data.tool + data.extension + ] + .filter(Boolean) + .join('/'); + } +} + +/** + * Function to get the phar url in domain/tool-version.phar format + * + * @param data + */ +export async function getPharUrl(data: ToolData): Promise { + if (data.version === 'latest') { + return data.domain + '/' + data.tool + '.phar'; + } else { + return ( + data.domain + + '/' + + data.tool + + '-' + + data.version_prefix + + data.version + + '.phar' + ); + } +} + +/** + * Helper function to get script to setup a tool using a phar url + * + * @param data + */ +export async function addArchive(data: ToolData): Promise { + return ( + (await utils.getCommand(data.os, 'tool')) + + (await utils.joins(data.url, data.tool, data.version_parameter)) + ); +} + +/** + * Helper function to get script to setup a tool using composer + * + * @param data + */ +export async function addPackage(data: ToolData): Promise { + const command = await utils.getCommand(data.os, 'composer_tool'); + const parts: string[] = data.repository.split('/'); + const args: string = await utils.joins( + parts[1], + data.release, + parts[0] + '/', + data.scope + ); + return command + args; +} + +/** + * Function to add blackfire-player + * + * @param data + */ +export async function addBlackfirePlayer(data: ToolData): Promise { + switch (data.os) { + case 'win32': + return await utils.addLog( + '$cross', + data.tool, + data.tool + ' is not a windows tool', + 'win32' + ); + default: + if (data.version == 'latest') { + if (/5\.[5-6]|7\.0/.test(data.php_version)) { + data.version = '1.9.3'; + } else if (/7\.[1-4]|8\.0/.test(data.php_version)) { + data.version = '1.22.0'; + } + } + data.url = await getPharUrl(data); + return addArchive(data); + } +} + +/** + * Function to add Castor + * + * @param data + */ +export async function addCastor(data: ToolData): Promise { + data.tool = 'castor.' + data.os.replace('win32', 'windows') + '-amd64'; + data.url = await getUrl(data); + data.tool = 'castor'; + data.version_parameter = fs.existsSync('castor.php') + ? data.version_parameter + : ''; + return await addArchive(data); +} + +/** + * Function to add composer + * + * @param data + */ +export async function addComposer(data: ToolData): Promise { + const channel = data.version.replace('latest', 'stable'); + const github = data.github; + const getcomposer = data.domain; + const cds = 'https://dl.cloudsmith.io'; + const spc = 'https://artifacts.setup-php.com'; + const filename = `composer-${data.php_version}-${channel}.phar`; + const releases_url = `${github}/shivammathur/composer-cache/releases/latest/download/${filename}`; + const cds_url = `${cds}/public/shivammathur/composer-cache/raw/files/${filename}`; + const spc_url = `${spc}/composer/${filename}`; + const lts_url = `${getcomposer}/download/latest-2.2.x/composer.phar`; + const is_lts = /^5\.[3-6]$|^7\.[0-1]$/.test(data.php_version); + const channel_source_url = `${getcomposer}/composer-${channel}.phar`; + const version_source_url = `${getcomposer}/download/${channel}/composer.phar`; + let cache_url = `${releases_url},${spc_url},${cds_url}`; + let source_url = `${getcomposer}/composer.phar`; + switch (true) { + case /^snapshot$/.test(channel): + source_url = is_lts ? lts_url : source_url; + break; + case /^preview$|^2$/.test(channel): + source_url = is_lts ? lts_url : channel_source_url; + break; + case /^1$/.test(channel): + source_url = channel_source_url; + break; + case /^\d+\.\d+\.\d+[\w-]*$/.test(data.version): + cache_url = `${github}/${data.repository}/releases/download/${data.version}/composer.phar`; + source_url = version_source_url; + break; + default: + source_url = is_lts ? lts_url : channel_source_url; + } + const use_cache: boolean = (await utils.readEnv('NO_TOOLS_CACHE')) !== 'true'; + data.url = use_cache ? `${cache_url},${source_url}` : source_url; + data.version_parameter = data.version; + return await addArchive(data); +} + +/** + * Function to add Deployer + * + * @param data + */ +export async function addDeployer(data: ToolData): Promise { + if (data.version === 'latest') { + data.url = data.domain + '/deployer.phar'; + } else { + const manifest = await fetch.fetch('https://deployer.org/manifest.json'); + const version_data: Record = JSON.parse( + manifest.data + ); + const version_key: string | undefined = Object.keys(version_data).find( + (key: string) => { + return version_data[key].version === data.version; + } + ); + if (version_key) { + data.url = version_data[version_key].url; + } else { + return await utils.addLog( + '$cross', + 'deployer', + 'Version missing in deployer manifest', + data.os + ); + } + } + return await addArchive(data); +} + +/** + * Function to add php-config and phpize + * + * @param data + */ +export async function addDevTools(data: ToolData): Promise { + switch (data.os) { + case 'linux': + case 'darwin': + return 'add_devtools ' + data.tool; + case 'win32': + return await utils.addLog( + '$tick', + data.tool, + data.tool + ' is not a windows tool', + 'win32' + ); + default: + return await utils.log( + 'Platform ' + data.os + ' is not supported', + data.os, + 'error' + ); + } +} + +/** + * Function to add PECL + * + * @param data + */ +export async function addPECL(data: ToolData): Promise { + return await utils.getCommand(data.os, 'pecl'); +} + +/** + * Function to add Phing + * + * @param data + */ +export async function addPhing(data: ToolData): Promise { + data.url = data.domain + '/get/phing-' + data.version + data.extension; + if (data.version != 'latest') { + [data.prefix, data.verb] = ['releases', 'download']; + data.domain = data.github; + data.extension = '-' + data.version + data.extension; + data.url += ',' + (await getUrl(data)); + } + return await addArchive(data); +} + +/** + * Helper function to add Phive + * + * @param data + */ +export async function addPhive(data: ToolData): Promise { + switch (true) { + case /5\.[3-5]/.test(data.php_version): + return await utils.addLog( + '$cross', + 'phive', + 'Phive is not supported on PHP ' + data.php_version, + data.os + ); + case /5\.6|7\.0/.test(data.php_version): + data.version = '0.12.1'; + break; + case /7\.1/.test(data.php_version): + data.version = '0.13.5'; + break; + case /7\.2/.test(data.php_version): + data.version = '0.14.5'; + break; + case /7\.3|7\.4/.test(data.php_version): + data.version = '0.15.3'; + break; + case /^latest$/.test(data.version): + data.version = await getLatestVersion(data); + break; + } + data.extension = '-' + data.version + data.extension; + data.url = await getUrl(data); + return await addArchive(data); +} + +/** + * Function to add PHPUnit and related tools + * + * @param data + */ +export async function addPHPUnitTools(data: ToolData): Promise { + /* istanbul ignore next */ + if (data.version === 'latest') { + data.version = + (await packagist.search(data.packagist, data.php_version)) ?? 'latest'; + } + data.url = await getPharUrl(data); + if (data.url.match(/-\d+/)) { + data.url += ',' + data.url.replace(/-(\d+)\.\d+\.\d+/, '-$1'); + } + return await addArchive(data); +} + +/** + * Function to add WP-CLI + * + * @param data + */ +export async function addWPCLI(data: ToolData): Promise { + if (data.version === 'latest') { + data.uri = 'wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true'; + data.url = [data.domain, data.uri].join('/'); + } else { + data.extension = '-' + data.version + data.extension; + data.url = await getUrl(data); + } + return await addArchive(data); +} + +/** + * Function to get information about a tool + * + * @param release + * @param php_version + * @param os + */ +export async function getData( + release: string, + php_version: string, + os: string +): Promise { + const json_file_path = path.join(__dirname, '../src/configs/tools.json'); + const json_file: string = fs.readFileSync(json_file_path, 'utf8'); + const json_objects: Record = JSON.parse(json_file); + release = release.replace(/\s+/g, ''); + const parts: string[] = release.split(':'); + const tool = parts[0]; + const version = parts[1]; + let config: ToolConfig & {tool: string}; + if (Object.hasOwn(json_objects, tool)) { + config = {...json_objects[tool], tool}; + } else { + const key: string | undefined = Object.keys(json_objects).find( + (key: string) => { + return json_objects[key].alias == tool; + } + ); + if (key) { + config = {...json_objects[key], tool: key}; + } else if (tool.includes('/')) { + config = { + tool: tool.split('/')[1], + repository: tool, + type: 'composer' + }; + } else { + config = {tool}; + } + } + const github = 'https://github.com'; + const domain = config.domain ?? github; + const data: ToolData = { + tool: config.tool, + version: '', + url: '', + os, + php_version, + github, + domain, + extension: config.extension ?? '.phar', + repository: config.repository ?? '', + prefix: domain === github ? 'releases' : '', + verb: domain === github ? 'download' : '', + fetch_latest: config.fetch_latest ?? 'false', + scope: config.scope ?? 'global', + version_parameter: + config.version_parameter != null + ? JSON.stringify(config.version_parameter) + : '', + version_prefix: config.version_prefix ?? '', + release: '', + packagist: config.packagist ?? config.repository ?? '', + type: config.type, + function: config.function, + alias: config.alias + }; + data.release = await getRelease(release, data); + data.version = version + ? await getVersion(version, data) + : await getLatestVersion(data); + data.url = await getUrl(data); + return data; +} + +export const functionRecord: Record< + ToolFunction, + (data: ToolData) => Promise +> = { + castor: addCastor, + composer: addComposer, + deployer: addDeployer, + dev_tools: addDevTools, + phive: addPhive, + blackfire_player: addBlackfirePlayer, + pecl: addPECL, + phing: addPhing, + phpunit: addPHPUnitTools, + phpcpd: addPHPUnitTools, + wp_cli: addWPCLI +}; + +/** + * Setup tools + * + * @param tools_csv + * @param php_version + * @param os + */ +export async function addTools( + tools_csv: string, + php_version: string, + os: string +): Promise { + let script = '\n'; + if (tools_csv === 'none') { + return ''; + } else { + script += await utils.stepLog('Setup Tools', os); + } + const tools_list = await filterList(await utils.CSVArray(tools_csv)); + await utils.asyncForEach(tools_list, async function (release: string) { + const data: ToolData = await getData(release, php_version, os); + script += '\n'; + switch (true) { + case data.error !== undefined: + script += await utils.addLog('$cross', data.tool, data.error, data.os); + break; + case 'phar' === data.type: + script += await addArchive(data); + break; + case 'composer' === data.type: + script += await addPackage(data); + break; + case 'custom-package' === data.type: + script += await utils.customPackage( + data.tool.split('-')[0], + 'tools', + data.version, + data.os + ); + break; + case 'custom-function' === data.type: + if (!data.function) { + script += await utils.addLog( + '$cross', + data.tool, + data.tool + ' has no function defined. Please report this issue.', + data.os + ); + } else { + script += await functionRecord[data.function](data); + } + break; + case /^none$/.test(data.tool): + break; + default: + script += await utils.addLog( + '$cross', + data.tool, + 'Tool ' + data.tool + ' is not supported', + data.os + ); + break; + } + }); + + return script; +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..15bfb1f --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,506 @@ +import fs from 'fs'; +import * as path from 'path'; +import * as core from './core'; +import * as fetch from './fetch'; + +/** + * Function to read environment variable and return a string value. + * + * @param property + */ +export async function readEnv(property: string): Promise { + const property_lc: string = property.toLowerCase(); + const property_uc: string = property.toUpperCase(); + return ( + process.env[property] || + process.env[property_lc] || + process.env[property_uc] || + process.env[property_lc.replace('_', '-')] || + process.env[property_uc.replace('_', '-')] || + '' + ); +} + +/** + * Function to get inputs from both with and env annotations. + * + * @param name + * @param mandatory + */ +export async function getInput( + name: string, + mandatory: boolean +): Promise { + const input = core.getInput(name); + const env_input = await readEnv(name); + switch (true) { + case input != '': + return input; + case input == '' && env_input != '': + return env_input; + case input == '' && env_input == '' && mandatory: + throw new Error(`Input required and not supplied: ${name}`); + default: + return ''; + } +} + +/** + * Function to get manifest URL + */ +export async function getManifestURLS(): Promise { + return [ + 'https://raw.githubusercontent.com/step-security/setup-php/release/src/configs/php-versions.json', + 'https://setup-php.com/php-versions.json' + ]; +} + +/** + * Function to parse PHP version. + * + * @param version + */ +export async function parseVersion(version: string): Promise { + switch (true) { + case /^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(version): + for (const manifestURL of await getManifestURLS()) { + const fetchResult = await fetch.fetch(manifestURL); + if (fetchResult['data'] ?? false) { + return JSON.parse(fetchResult['data'])[version]; + } + } + throw new Error(`Could not fetch the PHP version manifest.`); + default: + switch (true) { + case version.length > 1: + return version.slice(0, 3); + default: + return version + '.0'; + } + } +} + +/** + * Function to parse ini file. + * + * @param ini_file + */ +export async function parseIniFile(ini_file: string): Promise { + switch (true) { + case /^(production|development|none)$/.test(ini_file): + return ini_file; + case /php\.ini-(production|development)$/.test(ini_file): + return ini_file.split('-')[1]; + default: + return 'production'; + } +} + +/** + * Async foreach loop using modern for...of pattern + * + * @param array + * @param callback + */ +export async function asyncForEach( + array: Array, + callback: ( + element: string, + index: number, + array: Array + ) => Promise +): Promise { + for (const [index, element] of array.entries()) { + await callback(element, index, array); + } +} + +/** + * Get color index + * + * @param type + */ +export async function color(type: string): Promise { + switch (type) { + case 'error': + return '31'; + default: + case 'success': + return '32'; + case 'warning': + return '33'; + } +} + +/** + * Log to console + * + * @param message + * @param os + * @param log_type + */ +export async function log( + message: string, + os: string, + log_type: string +): Promise { + switch (os) { + case 'win32': + return ( + 'printf "\\033[' + + (await color(log_type)) + + ';1m' + + message + + ' \\033[0m"' + ); + + case 'linux': + case 'darwin': + default: + return ( + 'echo "\\033[' + (await color(log_type)) + ';1m' + message + '\\033[0m"' + ); + } +} + +/** + * Function to log a step + * + * @param message + * @param os + */ +export async function stepLog(message: string, os: string): Promise { + switch (os) { + case 'win32': + return 'Step-Log "' + message + '"'; + case 'linux': + case 'darwin': + return 'step_log "' + message + '"'; + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to log a result + * @param mark + * @param subject + * @param message + * @param os + */ +export async function addLog( + mark: string, + subject: string, + message: string, + os: string +): Promise { + switch (os) { + case 'win32': + return 'Add-Log "' + mark + '" "' + subject + '" "' + message + '"'; + case 'linux': + case 'darwin': + return 'add_log "' + mark + '" "' + subject + '" "' + message + '"'; + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to break extension csv into an array + * + * @param extension_csv + */ +export async function extensionArray( + extension_csv: string +): Promise> { + switch (extension_csv) { + case '': + case ' ': + return []; + default: + return [ + extension_csv.match(/(^|,\s?)none(\s?,|$)/) ? 'none' : '', + ...extension_csv + .split(',') + + .map(function (extension: string) { + extension = extension.trim().replace(/^\\\s*/, ''); + if (/.+-.+\/.+@.+/.test(extension)) { + return extension; + } + return extension + .toLowerCase() + .replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/, '$1$3'); + }) + ].filter(Boolean); + } +} + +/** + * Function to break csv into an array + * + * @param values_csv + * @constructor + */ +export async function CSVArray(values_csv: string): Promise> { + switch (values_csv) { + case '': + case ' ': + return []; + default: + return values_csv + .split(/,(?=(?:(?:[^"']*["']){2})*[^"']*$)/) + .map(function (value) { + return value + .trim() + .replace(/^["']|["']$|(?<==)["']/g, '') + .replace(/=(((?!E_).)*[?{}|&~![()^]+((?!E_).)+)/, "='$1'") + .replace(/=(.*?)(=.*)/, "='$1$2'") + .replace(/:\s*["'](.*?)/g, ':$1'); + }) + .filter(Boolean); + } +} + +/** + * Function to get prefix required to load an extension. + * + * @param extension + */ +export async function getExtensionPrefix(extension: string): Promise { + switch (true) { + default: + return 'extension'; + case /xdebug([2-3])?$|opcache|ioncube|eaccelerator/.test(extension): + return 'zend_extension'; + } +} + +/** + * Function to get the suffix to suppress console output + * + * @param os + */ +export async function suppressOutput(os: string): Promise { + switch (os) { + case 'win32': + return ' >$null 2>&1'; + case 'linux': + case 'darwin': + return ' >/dev/null 2>&1'; + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to get script to log unsupported extensions. + * + * @param extension + * @param version + * @param os + */ +export async function getUnsupportedLog( + extension: string, + version: string, + os: string +): Promise { + return ( + '\n' + + (await addLog( + '$cross', + extension, + [extension, 'is not supported on PHP', version].join(' '), + os + )) + + '\n' + ); +} + +/** + * Function to get command to setup tools + * + * @param os + * @param suffix + */ +export async function getCommand(os: string, suffix: string): Promise { + switch (os) { + case 'linux': + case 'darwin': + return 'add_' + suffix + ' '; + case 'win32': + return ( + 'Add-' + + suffix + .split('_') + .map((part: string) => part.charAt(0).toUpperCase() + part.slice(1)) + .join('') + + ' ' + ); + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to join strings with space + * + * @param str + */ +export async function joins(...str: string[]): Promise { + return [...str].join(' '); +} + +/** + * Function to get script extensions + * + * @param os + */ +export async function scriptExtension(os: string): Promise { + switch (os) { + case 'win32': + return '.ps1'; + case 'linux': + case 'darwin': + return '.sh'; + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to get script tool + * + * @param os + */ +export async function scriptTool(os: string): Promise { + switch (os) { + case 'win32': + return 'pwsh '; + case 'linux': + case 'darwin': + return 'bash '; + default: + return await log('Platform ' + os + ' is not supported', os, 'error'); + } +} + +/** + * Function to get script to add tools with custom support. + * + * @param pkg + * @param type + * @param version + * @param os + */ +export async function customPackage( + pkg: string, + type: string, + version: string, + os: string +): Promise { + const pkg_name: string = pkg.replace(/\d+|(pdo|pecl)[_-]|[_-]db2/, ''); + const script_extension: string = await scriptExtension(os); + const script: string = path.join( + __dirname, + '../src/scripts/' + type + '/' + pkg_name + script_extension + ); + const command: string = await getCommand(os, pkg_name); + return '\n. ' + script + '\n' + command + version; +} + +/** + * Function to extension input for installation from source. + * + * @param extension + * @param prefix + */ +export async function parseExtensionSource( + extension: string, + prefix: string +): Promise { + // Groups: extension, domain url, org, repo, release + const regex = + /(\w+)-(\w+:\/\/.{1,253}(?:[.:][^:/\s]{2,63})+\/)?([\w.-]+)\/([\w.-]+)@(.+)/; + const matches = regex.exec(extension) as RegExpExecArray; + matches[2] = matches[2] ? matches[2].slice(0, -1) : 'https://github.com'; + return await joins( + '\nadd_extension_from_source', + ...matches.splice(1, matches.length), + prefix + ); +} + +/** + * Read php version from input or file + */ +export async function readPHPVersion(): Promise { + const version = await getInput('php-version', false); + if (version) { + return version; + } + const versionFile = + (await getInput('php-version-file', false)) || '.php-version'; + if (fs.existsSync(versionFile)) { + const contents: string = fs.readFileSync(versionFile, 'utf8'); + const match: RegExpMatchArray | null = contents.match( + /^(?:php\s)?(\d+\.\d+\.\d+)$/m + ); + return match ? match[1] : contents.trim(); + } else if (versionFile !== '.php-version') { + throw new Error(`Could not find '${versionFile}' file.`); + } + + const composerProjectDir = await readEnv('COMPOSER_PROJECT_DIR'); + const composerLock = path.join(composerProjectDir, 'composer.lock'); + if (fs.existsSync(composerLock)) { + const lockFileContents = JSON.parse(fs.readFileSync(composerLock, 'utf8')); + /* istanbul ignore next */ + if ( + lockFileContents['platform-overrides'] && + lockFileContents['platform-overrides']['php'] + ) { + return lockFileContents['platform-overrides']['php']; + } + } + + const composerJson = path.join(composerProjectDir, 'composer.json'); + if (fs.existsSync(composerJson)) { + const composerFileContents = JSON.parse( + fs.readFileSync(composerJson, 'utf8') + ); + /* istanbul ignore next */ + if ( + composerFileContents['config'] && + composerFileContents['config']['platform'] && + composerFileContents['config']['platform']['php'] + ) { + return composerFileContents['config']['platform']['php']; + } + } + + return 'latest'; +} + +/** + * Log to console + * + * @param variable + * @param command + * @param os + */ +export async function setVariable( + variable: string, + command: string, + os: string +): Promise { + switch (os) { + case 'win32': + return '\n$' + variable + ' = ' + command + '\n'; + + case 'linux': + case 'darwin': + default: + return '\n' + variable + '="$(' + command + ')"\n'; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9f037c0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "declaration": true, + "esModuleInterop": true, + "lib": [ + "ES2024" + ], + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true, + "outDir": "./lib", + "removeComments": true, + "rootDir": "./src", + "sourceMap": true, + "strict": true, + "target": "ES2024" + }, + "exclude": ["__tests__", "lib", "node_modules"] +} \ No newline at end of file