diff --git a/.github/workflows/build-apk-forgejo.yml b/.github/workflows/build-apk-forgejo.yml index c4fbda8..4261e15 100644 --- a/.github/workflows/build-apk-forgejo.yml +++ b/.github/workflows/build-apk-forgejo.yml @@ -7,6 +7,11 @@ on: description: "Optional: override package iteration (integer). Leave empty for auto" required: false default: "" + bump: + description: "Bump each package iteration to (latest published on the repo) + 1" + type: boolean + required: false + default: false php_versions: description: "Optional: PHP versions (comma-separated, e.g., 8.2,8.5). Leave empty for all" required: false @@ -222,6 +227,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ITERATION: ${{ inputs.iteration || '' }} + BUMP: ${{ inputs.bump || false }} PACKAGES: ${{ inputs.packages || '' }} FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true @@ -294,7 +300,11 @@ jobs: if [[ -n "${ITERATION}" ]]; then ITERATION_FLAG="--iteration=${ITERATION}" fi - php bin/spp all --target="native-native-musl -dynamic" --phpv=${{ matrix.php-version }} --prefix="-zts" --type=apk $ITERATION_FLAG $PACKAGES_FLAG + BUMP_FLAG="" + if [[ "${BUMP}" == "true" ]]; then + BUMP_FLAG="--bump" + fi + php bin/spp all --target="native-native-musl -dynamic" --phpv=${{ matrix.php-version }} --prefix="-zts" --type=apk $ITERATION_FLAG $BUMP_FLAG $PACKAGES_FLAG - name: Upload logs on failure if: ${{ failure() }} diff --git a/.github/workflows/build-deb-forgejo.yml b/.github/workflows/build-deb-forgejo.yml index badedbb..2896e58 100644 --- a/.github/workflows/build-deb-forgejo.yml +++ b/.github/workflows/build-deb-forgejo.yml @@ -7,6 +7,11 @@ on: description: "Optional: override package iteration (integer). Leave empty for auto" required: false default: "" + bump: + description: "Bump each package iteration to (latest published on the repo) + 1" + type: boolean + required: false + default: false php_versions: description: "Optional: PHP versions (comma-separated, e.g., 8.2,8.5). Leave empty for all" required: false @@ -39,9 +44,7 @@ jobs: outputs: libs-pairs: ${{ steps.set-matrix.outputs.libs-pairs }} gcc-php-versions: ${{ steps.set-matrix.outputs.gcc-php-versions }} - zig-php-versions: ${{ steps.set-matrix.outputs.zig-php-versions }} gcc-needed: ${{ steps.set-matrix.outputs.gcc-needed }} - zig-needed: ${{ steps.set-matrix.outputs.zig-needed }} steps: - name: Set up matrix id: set-matrix @@ -61,20 +64,16 @@ jobs: arch_versions=$default_arch fi - # Split PHP versions by required toolchain (gcc for <8.5, zig for >=8.5). - gcc_php=$(jq -nc --argjson p "$php_versions" '[$p[] | select(startswith("8.5") | not)]') - zig_php=$(jq -nc --argjson p "$php_versions" '[$p[] | select(startswith("8.5"))]') + # All PHP versions build with gcc; zig is only used for alpine/musl (separate workflow). + gcc_php="$php_versions" gcc_needed=$(jq -nr --argjson p "$gcc_php" 'if ($p | length) > 0 then "true" else "false" end') - zig_needed=$(jq -nr --argjson p "$zig_php" 'if ($p | length) > 0 then "true" else "false" end') libs_pairs=$(jq -nc --argjson arch "$arch_versions" '{include: [$arch[] as $r | {arch: $r}]}') echo "libs-pairs=$libs_pairs" >> $GITHUB_OUTPUT echo "gcc-php-versions=$gcc_php" >> $GITHUB_OUTPUT - echo "zig-php-versions=$zig_php" >> $GITHUB_OUTPUT echo "gcc-needed=$gcc_needed" >> $GITHUB_OUTPUT - echo "zig-needed=$zig_needed" >> $GITHUB_OUTPUT env: INPUTS_PHP_VERSIONS: ${{ inputs.php_versions }} INPUTS_ARCHITECTURES: ${{ inputs.architectures }} @@ -201,128 +200,6 @@ jobs: sudo: false timeout-minutes: 30 - build-libs-zig: - needs: setup-matrix - if: ${{ needs.setup-matrix.outputs.zig-needed == 'true' }} - name: Build libs zig (${{ matrix.arch }}) - runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }} - container: - image: ghcr.io/static-php/packages-builder-debian:latest - permissions: - contents: write - packages: read - defaults: - run: - shell: bash - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup-matrix.outputs.libs-pairs) }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASH_ENV: /tmp/gha-bashenv - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - steps: - - name: Checkout code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Set architecture variables - run: | - if [[ "${{ matrix.arch }}" == "arm64" ]]; then - echo "RPM_ARCH=aarch64" >> $GITHUB_ENV - else - echo "RPM_ARCH=x86_64" >> $GITHUB_ENV - fi - - - name: Compute buildroot cache key - id: cache-key - run: | - set -euo pipefail - WEEK=$(date -u +%G-%V) - echo "key=buildroot-deb-${{ matrix.arch }}-zig-${WEEK}" >> $GITHUB_OUTPUT - - - name: Restore buildroot cache - id: cache - uses: ./.github/actions/buildroot-cache - with: - mode: restore - key: ${{ steps.cache-key.outputs.key }} - - - name: Download artifact from spc-download.yml - if: steps.cache.outputs.cache-hit != 'true' - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - branch: master - search_artifacts: true - - - name: Prepare cache directories - if: steps.cache.outputs.cache-hit != 'true' - run: composer config -g cache-dir - - - name: Cache Composer downloads - if: steps.cache.outputs.cache-hit != 'true' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Install vendor - if: steps.cache.outputs.cache-hit != 'true' - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Extract with permissions - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Build libs - if: steps.cache.outputs.cache-hit != 'true' - run: bin/spp build --phpv=8.5 --type=deb --libs-only - - - name: Pack buildroot - if: steps.cache.outputs.cache-hit != 'true' - run: tar --zstd -cf buildroot.tar.zst buildroot - - - name: Save buildroot cache - if: steps.cache.outputs.cache-hit != 'true' - uses: ./.github/actions/buildroot-cache - with: - mode: save - key: ${{ steps.cache-key.outputs.key }} - - - name: Upload logs on failure - if: ${{ failure() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: build-logs-libs-${{ matrix.arch }}-zig - path: log - - - name: Install tmate - if: ${{ failure() && inputs.debug_tmate == true }} - run: | - case "${RPM_ARCH}" in - x86_64) arch="amd64" ;; - aarch64) arch="arm64v8" ;; - esac - dir="tmate-2.4.0-static-linux-$arch" - curl -L "https://github.com/tmate-io/tmate/releases/download/2.4.0/$dir.tar.xz" | tar -xJ -O "$dir/tmate" > /usr/bin/tmate - chmod +x /usr/bin/tmate - - - name: Setup tmate session - if: ${{ failure() && inputs.debug_tmate == true }} - uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 - with: - install-dependencies: false - sudo: false - timeout-minutes: 30 - compute-build-gcc-matrix: needs: [setup-matrix, build-libs-gcc] runs-on: ubuntu-24.04 @@ -362,45 +239,6 @@ jobs: fi echo "matrix={\"include\":$include}" >> $GITHUB_OUTPUT - compute-build-zig-matrix: - needs: [setup-matrix, build-libs-zig] - runs-on: ubuntu-24.04 - if: ${{ !cancelled() && needs.setup-matrix.outputs.zig-needed == 'true' }} - permissions: - actions: read - outputs: - matrix: ${{ steps.filter.outputs.matrix }} - any: ${{ steps.filter.outputs.any }} - steps: - - name: Filter build matrix to arches with successful zig libs - id: filter - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ZIG_PHP: ${{ needs.setup-matrix.outputs.zig-php-versions }} - run: | - set -euo pipefail - succeeded=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs" --paginate \ - --jq '.jobs[] | select(.conclusion == "success" and (.name | test("^Build libs zig \\("))) | .name' \ - | sed -E 's/^Build libs zig \(([^)]+)\)$/\1/' \ - | sort -u) - echo "Successful zig libs arches:" - printf '%s\n' "$succeeded" - - include=$(jq -nc --arg s "$succeeded" --argjson p "$ZIG_PHP" ' - ($s | split("\n") | map(select(length > 0) | {arch: .})) as $arches | - [ $arches[] as $a | $p[] as $php | $a + {"php-version": $php} ] - ') - count=$(jq 'length' <<< "$include") - echo "Filtered combos: $count" - printf '%s\n' "$include" | jq . - - if [[ "$count" -gt 0 ]]; then - echo "any=true" >> $GITHUB_OUTPUT - else - echo "any=false" >> $GITHUB_OUTPUT - fi - echo "matrix={\"include\":$include}" >> $GITHUB_OUTPUT - build-gcc: needs: [compute-build-gcc-matrix] if: ${{ !cancelled() && needs.compute-build-gcc-matrix.outputs.any == 'true' }} @@ -421,6 +259,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BASH_ENV: /tmp/gha-bashenv ITERATION: ${{ inputs.iteration || '' }} + BUMP: ${{ inputs.bump || false }} PACKAGES: ${{ inputs.packages || '' }} FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true @@ -500,151 +339,11 @@ jobs: if [[ -n "${ITERATION}" ]]; then ITERATION_FLAG="--iteration=${ITERATION}" fi - bin/spp all --phpv=${{ matrix.php-version }} --prefix="-zts" --type=deb --debuginfo $ITERATION_FLAG $PACKAGES_FLAG - - - name: Upload logs on failure - if: ${{ failure() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: build-logs-${{ matrix.arch }}-php${{ matrix.php-version }} - path: log - - - name: Upload to Forgejo Host 1 - working-directory: dist/deb - run: | - echo "listing from host 1" - ../../bin/forgejo-helper list debian "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.deb" - echo "uploading to host 1" - ../../bin/forgejo-helper upload debian "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.deb" - - - name: Upload to Forgejo Host 2 - working-directory: dist/deb - continue-on-error: true - run: | - echo "listing from host 2" - ../../bin/forgejo-helper --host=2 list debian "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.deb" - echo "uploading to host 2" - ../../bin/forgejo-helper --host=2 upload debian "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.deb" - - - name: Install tmate - if: ${{ failure() && inputs.debug_tmate == true }} - run: | - case "${RPM_ARCH}" in - x86_64) arch="amd64" ;; - aarch64) arch="arm64v8" ;; - esac - dir="tmate-2.4.0-static-linux-$arch" - curl -L "https://github.com/tmate-io/tmate/releases/download/2.4.0/$dir.tar.xz" | tar -xJ -O "$dir/tmate" > /usr/bin/tmate - chmod +x /usr/bin/tmate - - - name: Setup tmate session - if: ${{ failure() && inputs.debug_tmate == true }} - uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 - with: - install-dependencies: false - sudo: false - timeout-minutes: 30 - - build-zig: - needs: [compute-build-zig-matrix] - if: ${{ !cancelled() && needs.compute-build-zig-matrix.outputs.any == 'true' }} - name: Build for ${{ matrix.arch }} PHP ${{ matrix.php-version }} - runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }} - container: - image: ghcr.io/static-php/packages-builder-debian:latest - permissions: - contents: read - packages: read - defaults: - run: - shell: bash - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.compute-build-zig-matrix.outputs.matrix) }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASH_ENV: /tmp/gha-bashenv - ITERATION: ${{ inputs.iteration || '' }} - PACKAGES: ${{ inputs.packages || '' }} - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - - steps: - - name: Checkout code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Set architecture variables - run: | - if [[ "${{ matrix.arch }}" == "arm64" ]]; then - echo "RPM_ARCH=aarch64" >> $GITHUB_ENV - else - echo "RPM_ARCH=x86_64" >> $GITHUB_ENV + BUMP_FLAG="" + if [[ "${BUMP}" == "true" ]]; then + BUMP_FLAG="--bump" fi - - - name: Set PHP version short - run: | - PHP_VERSION_SHORT=$(echo "${{ matrix.php-version }}" | tr -d '.') - echo "PHP_VERSION_SHORT=$PHP_VERSION_SHORT" >> $GITHUB_ENV - - - name: Prepare cache directories - run: composer config -g cache-dir - - - name: Cache Composer downloads - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Install vendor - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Download artifact from spc-download.yml - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - branch: master - search_artifacts: true - - - name: Extract with permissions - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Compute buildroot cache key - id: cache-key - run: | - set -euo pipefail - WEEK=$(date -u +%G-%V) - echo "key=buildroot-deb-${{ matrix.arch }}-zig-${WEEK}" >> $GITHUB_OUTPUT - - - name: Restore buildroot cache - uses: ./.github/actions/buildroot-cache - with: - mode: restore - key: ${{ steps.cache-key.outputs.key }} - fail-on-cache-miss: true - - - name: Extract buildroot - run: | - tar --zstd -xf buildroot.tar.zst - rm buildroot.tar.zst - - - name: Build PHP packages - run: | - PACKAGES_FLAG="" - if [[ -n "${{ env.PACKAGES }}" ]]; then - PACKAGES_FLAG="--packages=${{ env.PACKAGES }}" - fi - ITERATION_FLAG="" - if [[ -n "${ITERATION}" ]]; then - ITERATION_FLAG="--iteration=${ITERATION}" - fi - bin/spp all --phpv=${{ matrix.php-version }} --prefix="-zts" --type=deb --debuginfo $ITERATION_FLAG $PACKAGES_FLAG + bin/spp all --phpv=${{ matrix.php-version }} --prefix="-zts" --type=deb --debuginfo $ITERATION_FLAG $BUMP_FLAG $PACKAGES_FLAG - name: Upload logs on failure if: ${{ failure() }} @@ -688,3 +387,4 @@ jobs: install-dependencies: false sudo: false timeout-minutes: 30 + diff --git a/.github/workflows/build-gcc-deb-packages.yml b/.github/workflows/build-gcc-deb-packages.yml deleted file mode 100644 index ea4cc3b..0000000 --- a/.github/workflows/build-gcc-deb-packages.yml +++ /dev/null @@ -1,309 +0,0 @@ -name: Build and upload gcc deb packages - -on: - workflow_dispatch: - inputs: - debug_tmate: - description: "Open tmate session on failure" - type: boolean - required: false - default: false - -permissions: - contents: read - -jobs: - build: - name: Build for ${{ matrix.arch }} PHP ${{ matrix.php-version }} - runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }} - container: - image: debian:11 - permissions: - contents: read - defaults: - run: - shell: bash - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASH_ENV: /tmp/gha-bashenv - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - strategy: - fail-fast: false - matrix: - php-version: [ 8.4 ] - arch: [ amd64, arm64 ] - - steps: - - name: Checkout code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Set architecture variables - run: | - if [[ "${{ matrix.arch }}" == "arm64" ]]; then - echo "RPM_ARCH=aarch64" >> $GITHUB_ENV - else - echo "RPM_ARCH=x86_64" >> $GITHUB_ENV - fi - - - name: Bootstrap container - run: | - apt-get update - apt-get install -y ruby build-essential jq curl gzip sudo git gnupg tar zstd - apt-get upgrade -y - gem install --no-document fpm - - - name: Install cmake - run: | - curl -o cmake.tar.gz -fsSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$(uname -m).tar.gz && \ - sudo tar -xzf cmake.tar.gz -C /usr/local --strip-components=1 && \ - rm cmake.tar.gz - - - name: Install composer - run: | - sudo curl -L https://files.henderkes.com/${RPM_ARCH}-linux/php -o /usr/local/bin/php - sudo chmod +x /usr/local/bin/php - sudo curl -sS https://raw.githubusercontent.com/composer/getcomposer.org/f3108f64b4e1c1ce6eb462b159956461592b3e3e/web/installer | php -- --quiet - sudo mv composer.phar /usr/local/bin/composer - - - name: Prepare cache directories - run: | - composer config -g cache-dir - - - name: Cache Composer downloads - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Install vendor - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Download artifact from spc-download.yml - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - search_artifacts: true - - - name: Extract with permissions - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Build PHP - run: php bin/spp all --phpv=${{ matrix.php-version }} --prefix="-zts" --type=deb - - - name: Inject deprecation notice into packages - run: | - shopt -s nullglob - for deb in dist/deb/*.deb; do - echo "Processing $deb..." - - # Create a working directory - work_dir=$(mktemp -d) - extract_dir="$work_dir/extracted" - - # Extract the .deb - dpkg-deb -R "$deb" "$extract_dir" - - # Create or append to postinst script - postinst="$extract_dir/DEBIAN/postinst" - - if [ -f "$postinst" ]; then - # If postinst exists, insert deprecation notice after shebang - temp_file=$(mktemp) - head -1 "$postinst" > "$temp_file" - cat >> "$temp_file" <<'EOF' - - # Display deprecation notice - cat <<'NOTICE' - - ================================================================================ - ⚠️ DEPRECATION NOTICE - ================================================================================ - - The single-version php-zts repository is deprecated and will no longer receive updates. - - Please migrate to the new repository with different PHP versions available. - - More information: https://pkgs.henderkes.com - - ================================================================================ - - NOTICE - - EOF - tail -n +2 "$postinst" >> "$temp_file" - mv "$temp_file" "$postinst" - else - # Create new postinst script - cat > "$postinst" <<'EOF' - #!/bin/sh - set -e - - # Display deprecation notice - cat <<'NOTICE' - - ================================================================================ - ⚠️ DEPRECATION NOTICE - ================================================================================ - - This repository is deprecated and will no longer receive updates. - - Please migrate to the new repository with different PHP versions available. - - More information: https://pkgs.henderkes.com - - ================================================================================ - - NOTICE - - #DEBHELPER# - - exit 0 - EOF - fi - - chmod 755 "$postinst" - - # Repackage the .deb - dpkg-deb -b "$extract_dir" "$deb" - - # Cleanup - rm -rf "$work_dir" - - echo "✓ Injected deprecation notice into $deb" - done - - - name: Stage deb artifacts - run: | - mkdir -p "artifacts/${{ matrix.arch }}" - shopt -s nullglob - mv dist/deb/*.deb "artifacts/${{ matrix.arch }}/" - - - name: Upload debs - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: "debs-${{ matrix.arch }}" - path: artifacts/** - if-no-files-found: error - retention-days: 2 - - - name: Upload logs - if: ${{ failure() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: build-logs-${{ matrix.arch }}-php${{ matrix.php-version }} - path: log - - - name: Setup tmate session - if: ${{ failure() && inputs.debug_tmate == true }} - uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 - timeout-minutes: 10 - - assemble-repo: - needs: build - runs-on: ubuntu-latest - permissions: - contents: read - env: - DEB_GPG_PRIVATE_KEY: ${{ secrets.DEB_GPG_PRIVATE_KEY }} - DEB_GPG_PASSWORD: ${{ secrets.DEB_GPG_PASSWORD }} - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Install repo tooling - run: | - sudo apt-get update - sudo apt-get install -y reprepro gnupg rsync - - - name: Download all debs - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 - with: - pattern: debs-* - merge-multiple: true - path: collected - - - name: Build signed APT repo (aggregate) - run: | - REPO_ROOT="$(pwd)/repo" - mkdir -p "${REPO_ROOT}/conf" - ORIGIN="Static PHP repository" - LABEL="static-php" - COMPONENT="main" - DESC="Static PHP repository" - - export GNUPGHOME="${HOME}/.gnupg" - mkdir -p "${GNUPGHOME}"; chmod 700 "${GNUPGHOME}" - - echo "allow-loopback-pinentry" > "${GNUPGHOME}/gpg-agent.conf" - gpgconf --kill gpg-agent - - FPR=$(printf '%s' "${DEB_GPG_PRIVATE_KEY}" \ - | gpg --batch --quiet --with-colons --import-options show-only --import 2>/dev/null \ - | awk -F: '/^fpr:/ {print $10; exit}') - printf '%s' "${DEB_GPG_PRIVATE_KEY}" | gpg --batch --yes --import - - { - echo "pinentry-mode loopback" - echo "default-key ${FPR}" - } > "${GNUPGHOME}/gpg.conf" - - t=$(mktemp); echo warmup > "$t" - gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 \ - --local-user "${FPR}" --sign --output /dev/null "$t" <<<"${DEB_GPG_PASSWORD}" - rm -f "$t" - - cat > "${REPO_ROOT}/conf/distributions" <> ~/.ssh/known_hosts <<'EOF' - ${{ secrets.DEB_SERVER_IP }} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPQq0y77dDEtxECVMhCxjcqiV369goMcbInsY/d+F1yXGwqOXQ6RqIEzgaVhgq0joMJT5BiGXNXQ+OI10/KtzGI= - ${{ secrets.DEB_SERVER_IP }} ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2laCc5jifgjL/2zLzgP1E/X3kouXdaZv00KtAV1DOO5umThoWzb16cswnVtjtLUEMIuo9rPLB79xX2Asa+nN3uMgJDANnr/xnhRoI++yOGLga40/O69U88j5x+5FXODscH/k4n85mfcjzm/fZLXcHlb17ibCmU20I3v46sydn95Pp4/ShDvqsHVB4gWEKJ+jStkooUz2H1UZ8ZquNtaPTlmkOeClNj6gxag74P5b9VB6M5YNac2Emi3Nm0dYkc+BL0Qv+NEtFR1lR63DLa3O/NGTALGJYGmTUkjwiv8KygegaKhd2zxESmWhV7eYIPax8zL+GE9sX1Xwwh1huS0vsuwr2dXPP1/q5slz1AQV/lx85fGdiHc0F8RUXwqXbvGxZJheTuC/Mgu0cFzp5gqO4kTP28X+9fokzScBKBCIfObDXrl7rZgTXAA8IQ5gHk1tGchaEOIcDsjdISW5HVOiwocYSwUNMHzuZ08qAulatIywtOGcWVRdvOs7TcvSgfZ0= - ${{ secrets.DEB_SERVER_IP }} ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaB5IjokRHAH0Y9pzVe/Jx3s6cn0OADJ9uTxQQubBMu - EOF - chmod 600 ~/.ssh/known_hosts - - - name: Upload APT repo to DEB_SERVER_IP - run: rsync -azv --delete repo/ github@${{ secrets.DEB_SERVER_IP }}:/mnt/data/deb/ - - - name: Fix permissions for Caddy file browser - run: ssh github@${{ secrets.DEB_SERVER_IP }} 'chmod -R o+rx /mnt/data/deb' - -# - name: Setup tmate session -# if: ${{ failure() && github.event_name == 'workflow_dispatch' }} -# uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 -# timeout-minutes: 10 diff --git a/.github/workflows/build-rpm-modular-packages.yml b/.github/workflows/build-rpm-modular-packages.yml index 99971e7..7a6859e 100644 --- a/.github/workflows/build-rpm-modular-packages.yml +++ b/.github/workflows/build-rpm-modular-packages.yml @@ -7,6 +7,11 @@ on: description: "Optional: override package iteration (integer). Leave empty for auto" required: false default: "" + bump: + description: "Bump each package iteration to (latest published on the repo) + 1" + type: boolean + required: false + default: false php_versions: description: "Optional: PHP versions (comma-separated, e.g., 8.2,8.5). Leave empty for all" required: false @@ -42,9 +47,7 @@ jobs: outputs: libs-pairs: ${{ steps.set-matrix.outputs.libs-pairs }} gcc-php-versions: ${{ steps.set-matrix.outputs.gcc-php-versions }} - zig-php-versions: ${{ steps.set-matrix.outputs.zig-php-versions }} gcc-needed: ${{ steps.set-matrix.outputs.gcc-needed }} - zig-needed: ${{ steps.set-matrix.outputs.zig-needed }} steps: - name: Set up matrix id: set-matrix @@ -71,12 +74,10 @@ jobs: arch_versions=$default_arch fi - # Split PHP versions by required toolchain (gcc for <8.5, zig for >=8.5). - gcc_php=$(jq -nc --argjson p "$php_versions" '[$p[] | select(startswith("8.5") | not)]') - zig_php=$(jq -nc --argjson p "$php_versions" '[$p[] | select(startswith("8.5"))]') + # All PHP versions build with gcc; zig is only used for alpine/musl (separate workflow). + gcc_php="$php_versions" gcc_needed=$(jq -nr --argjson p "$gcc_php" 'if ($p | length) > 0 then "true" else "false" end') - zig_needed=$(jq -nr --argjson p "$zig_php" 'if ($p | length) > 0 then "true" else "false" end') libs_pairs=$(jq -nc \ --argjson alma "$alma_versions" \ @@ -85,9 +86,7 @@ jobs: echo "libs-pairs=$libs_pairs" >> $GITHUB_OUTPUT echo "gcc-php-versions=$gcc_php" >> $GITHUB_OUTPUT - echo "zig-php-versions=$zig_php" >> $GITHUB_OUTPUT echo "gcc-needed=$gcc_needed" >> $GITHUB_OUTPUT - echo "zig-needed=$zig_needed" >> $GITHUB_OUTPUT env: INPUTS_PHP_VERSIONS: ${{ inputs.php_versions }} INPUTS_ALMA_VERSIONS: ${{ inputs.alma_versions }} @@ -218,131 +217,6 @@ jobs: sudo: false timeout-minutes: 30 - build-libs-zig: - needs: setup-matrix - if: ${{ needs.setup-matrix.outputs.zig-needed == 'true' }} - name: Build libs zig (alma${{ matrix.alma }} ${{ matrix.arch }}) - runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} - container: - image: ghcr.io/static-php/packages-builder-rhel-${{ matrix.alma }}:latest - permissions: - contents: write - packages: read - defaults: - run: - shell: bash - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup-matrix.outputs.libs-pairs) }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASH_ENV: /tmp/gha-bashenv - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - steps: - - name: Checkout code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Set architecture variables - run: | - if [[ "${MATRIX_ARCH}" == "arm64" ]]; then - echo "RPM_ARCH=aarch64" >> $GITHUB_ENV - else - echo "RPM_ARCH=x86_64" >> $GITHUB_ENV - fi - env: - MATRIX_ARCH: ${{ matrix.arch }} - - - name: Compute buildroot cache key - id: cache-key - run: | - set -euo pipefail - WEEK=$(date -u +%G-%V) - echo "key=buildroot-rpm-alma${{ matrix.alma }}-${{ matrix.arch }}-zig-${WEEK}" >> $GITHUB_OUTPUT - - - name: Restore buildroot cache - id: cache - uses: ./.github/actions/buildroot-cache - with: - mode: restore - key: ${{ steps.cache-key.outputs.key }} - - - name: Download artifact from spc-download.yml - if: steps.cache.outputs.cache-hit != 'true' - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - search_artifacts: true - - - name: Prepare cache directories - if: steps.cache.outputs.cache-hit != 'true' - run: composer config -g cache-dir - - - name: Cache Composer downloads - if: steps.cache.outputs.cache-hit != 'true' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Composer install - if: steps.cache.outputs.cache-hit != 'true' - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Extract with permissions - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Build libs - if: steps.cache.outputs.cache-hit != 'true' - run: php bin/spp build --type=rpm --debuginfo --phpv=8.5 --libs-only - - - name: Pack buildroot - if: steps.cache.outputs.cache-hit != 'true' - run: tar -cf - buildroot | zstd -o buildroot.tar.zst - - - name: Save buildroot cache - if: steps.cache.outputs.cache-hit != 'true' - uses: ./.github/actions/buildroot-cache - with: - mode: save - key: ${{ steps.cache-key.outputs.key }} - - - name: Upload logs on failure - if: ${{ failure() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: build-logs-libs-alma${{ matrix.alma }}-${{ matrix.arch }}-zig - path: log - - - name: Install tmate - if: ${{ failure() && inputs.debug_tmate == true }} - run: | - case "${MATRIX_ARCH}" in - x86_64) arch="amd64" ;; - arm64) arch="arm64v8" ;; - esac - dir="tmate-2.4.0-static-linux-$arch" - curl -L "https://github.com/tmate-io/tmate/releases/download/2.4.0/$dir.tar.xz" | tar -xJ -O "$dir/tmate" > /usr/bin/tmate - chmod +x /usr/bin/tmate - env: - MATRIX_ARCH: ${{ matrix.arch }} - - - name: Setup tmate session - if: ${{ failure() && inputs.debug_tmate == true }} - uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 - with: - install-dependencies: false - sudo: false - timeout-minutes: 30 - compute-build-gcc-matrix: needs: [setup-matrix, build-libs-gcc] runs-on: ubuntu-24.04 @@ -382,45 +256,6 @@ jobs: fi echo "matrix={\"include\":$include}" >> $GITHUB_OUTPUT - compute-build-zig-matrix: - needs: [setup-matrix, build-libs-zig] - runs-on: ubuntu-24.04 - if: ${{ !cancelled() && needs.setup-matrix.outputs.zig-needed == 'true' }} - permissions: - actions: read - outputs: - matrix: ${{ steps.filter.outputs.matrix }} - any: ${{ steps.filter.outputs.any }} - steps: - - name: Filter build matrix to (alma, arch) with successful zig libs - id: filter - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ZIG_PHP: ${{ needs.setup-matrix.outputs.zig-php-versions }} - run: | - set -euo pipefail - succeeded=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs" --paginate \ - --jq '.jobs[] | select(.conclusion == "success" and (.name | test("^Build libs zig \\(alma"))) | .name' \ - | sed -E 's/^Build libs zig \(alma([^ ]+) ([^)]+)\)$/\1 \2/' \ - | sort -u) - echo "Successful zig libs combos:" - printf '%s\n' "$succeeded" - - include=$(jq -nc --arg s "$succeeded" --argjson p "$ZIG_PHP" ' - ($s | split("\n") | map(select(length > 0) | split(" ") | {alma: .[0], arch: .[1]})) as $pairs | - [ $pairs[] as $pair | $p[] as $php | $pair + {"php-version": $php} ] - ') - count=$(jq 'length' <<< "$include") - echo "Filtered combos: $count" - printf '%s\n' "$include" | jq . - - if [[ "$count" -gt 0 ]]; then - echo "any=true" >> $GITHUB_OUTPUT - else - echo "any=false" >> $GITHUB_OUTPUT - fi - echo "matrix={\"include\":$include}" >> $GITHUB_OUTPUT - build-gcc: needs: [compute-build-gcc-matrix] if: ${{ !cancelled() && needs.compute-build-gcc-matrix.outputs.any == 'true' }} @@ -438,6 +273,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BASH_ENV: /tmp/gha-bashenv ITERATION: ${{ inputs.iteration || '' }} + BUMP: ${{ inputs.bump || false }} PACKAGES: ${{ inputs.packages || '' }} FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true strategy: @@ -549,197 +385,11 @@ jobs: if [[ -n "${ITERATION}" ]]; then ITERATION_FLAG="--iteration=${ITERATION}" fi - php bin/spp all --type=rpm --debuginfo --phpv=${MATRIX_PHP_VERSION} $ITERATION_FLAG $PACKAGES_FLAG - env: - MATRIX_PHP_VERSION: ${{ matrix.php-version }} - - - name: Prepare rpm signing - run: | - export GNUPGHOME="${HOME}/.gnupg" - mkdir -p "${GNUPGHOME}" - chmod 700 "${GNUPGHOME}" - - echo "allow-loopback-pinentry" > "${GNUPGHOME}/gpg-agent.conf" - gpgconf --kill gpg-agent - - FPR=$(printf '%s' "${{ secrets.DEB_GPG_PRIVATE_KEY }}" \ - | gpg --batch --quiet --with-colons --import-options show-only --import 2>/dev/null \ - | awk -F: '/^fpr:/ {print $10; exit}') - printf '%s' "${{ secrets.DEB_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import - - { - echo "pinentry-mode loopback" - echo "default-key ${FPR}" - } > "${GNUPGHOME}/gpg.conf" - - t=$(mktemp); echo warmup > "$t" - gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 \ - --local-user "${FPR}" --sign --output /dev/null "$t" <<<"${{ secrets.DEB_GPG_PASSWORD }}" - rm -f "$t" - - cat > ~/.rpmmacros <> $GITHUB_ENV - else - echo "RPM_ARCH=x86_64" >> $GITHUB_ENV - fi - env: - MATRIX_ARCH: ${{ matrix.arch }} - - - name: Prepare cache directories - run: composer config -g cache-dir - - - name: Cache Composer downloads - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Set up SSH key - uses: webfactory/ssh-agent@d4b9b8ff72958532804b70bbe600ad43b36d5f2e # v0.8.0 - with: - ssh-private-key: ${{ secrets.GITHUBRPMHENDERKESPRIVATEKEY }} - - - name: Install tmate - run: | - case "${MATRIX_ARCH}" in - x86_64) arch="amd64" ;; - arm64) arch="arm64v8" ;; - esac - dir="tmate-2.4.0-static-linux-$arch" - curl -L "https://github.com/tmate-io/tmate/releases/download/2.4.0/$dir.tar.xz" | tar -xJ -O "$dir/tmate" > /usr/bin/tmate - chmod +x /usr/bin/tmate - env: - MATRIX_ARCH: ${{ matrix.arch }} - - - name: Add remote host to known_hosts - run: | - mkdir -p ~/.ssh - cat >> /root/.ssh/known_hosts <<'EOF' - ${{ secrets.DEB_SERVER_IP }} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPQq0y77dDEtxECVMhCxjcqiV369goMcbInsY/d+F1yXGwqOXQ6RqIEzgaVhgq0joMJT5BiGXNXQ+OI10/KtzGI= - ${{ secrets.DEB_SERVER_IP }} ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2laCc5jifgjL/2zLzgP1E/X3kouXdaZv00KtAV1DOO5umThoWzb16cswnVtjtLUEMIuo9rPLB79xX2Asa+nN3uMgJDANnr/xnhRoI++yOGLga40/O69U88j5x+5FXODscH/k4n85mfcjzm/fZLXcHlb17ibCmU20I3v46sydn95Pp4/ShDvqsHVB4gWEKJ+jStkooUz2H1UZ8ZquNtaPTlmkOeClNj6gxag74P5b9VB6M5YNac2Emi3Nm0dYkc+BL0Qv+NEtFR1lR63DLa3O/NGTALGJYGmTUkjwiv8KygegaKhd2zxESmWhV7eYIPax8zL+GE9sX1Xwwh1huS0vsuwr2dXPP1/q5slz1AQV/lx85fGdiHc0F8RUXwqXbvGxZJheTuC/Mgu0cFzp5gqO4kTP28X+9fokzScBKBCIfObDXrl7rZgTXAA8IQ5gHk1tGchaEOIcDsjdISW5HVOiwocYSwUNMHzuZ08qAulatIywtOGcWVRdvOs7TcvSgfZ0= - ${{ secrets.DEB_SERVER_IP }} ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaB5IjokRHAH0Y9pzVe/Jx3s6cn0OADJ9uTxQQubBMu - EOF - chmod 600 /root/.ssh/known_hosts - - - name: Set target folder - run: | - TARGET_DIR="el${MATRIX_ALMA}" - echo "TARGET_DIR=${TARGET_DIR}" >> "$GITHUB_ENV" - env: - MATRIX_ALMA: ${{ matrix.alma }} - - - name: Composer install - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Download artifact from spc-download.yml - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - search_artifacts: true - - - name: Extract with permissions - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Compute buildroot cache key - id: cache-key - run: | - set -euo pipefail - WEEK=$(date -u +%G-%V) - echo "key=buildroot-rpm-alma${{ matrix.alma }}-${{ matrix.arch }}-zig-${WEEK}" >> $GITHUB_OUTPUT - - - name: Restore buildroot cache - uses: ./.github/actions/buildroot-cache - with: - mode: restore - key: ${{ steps.cache-key.outputs.key }} - fail-on-cache-miss: true - - - name: Extract buildroot - run: | - zstd -dc buildroot.tar.zst | tar -xf - - rm buildroot.tar.zst - - - name: Build PHP - run: | - PACKAGES_FLAG="" - if [[ -n "${PACKAGES}" ]]; then - PACKAGES_FLAG="--packages=${PACKAGES}" - fi - ITERATION_FLAG="" - if [[ -n "${ITERATION}" ]]; then - ITERATION_FLAG="--iteration=${ITERATION}" + BUMP_FLAG="" + if [[ "${BUMP}" == "true" ]]; then + BUMP_FLAG="--bump" fi - php bin/spp all --type=rpm --debuginfo --phpv=${MATRIX_PHP_VERSION} $ITERATION_FLAG $PACKAGES_FLAG + php bin/spp all --type=rpm --debuginfo --phpv=${MATRIX_PHP_VERSION} $ITERATION_FLAG $BUMP_FLAG $PACKAGES_FLAG env: MATRIX_PHP_VERSION: ${{ matrix.php-version }} @@ -803,7 +453,7 @@ jobs: setup-update-matrix: runs-on: ubuntu-24.04 - needs: [build-gcc, build-zig] + needs: [build-gcc] if: ${{ !cancelled() }} permissions: actions: read diff --git a/.github/workflows/build-zig-packages.yml b/.github/workflows/build-zig-packages.yml deleted file mode 100644 index d2025f8..0000000 --- a/.github/workflows/build-zig-packages.yml +++ /dev/null @@ -1,199 +0,0 @@ -name: Build and upload zig rpm packages - -on: - # workflow_run: - # workflows: [ "spc-download" ] - # types: - # - completed - workflow_dispatch: - inputs: - iteration: - description: "Optional: override package iteration (integer). Leave empty for auto" - required: false - default: "" - packages: - description: "Optional: override packages list. Leave empty for default" - required: false - default: "" - debug_tmate: - description: "Open tmate session on failure" - type: boolean - required: false - default: false - -permissions: - contents: read - -jobs: - build: - runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ITERATION: ${{ inputs.iteration || '' }} - PACKAGES: ${{ inputs.packages || '' }} - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - strategy: - fail-fast: false - matrix: - php-version: [ 8.2, 8.3, 8.4, 8.5 ] - arch: [ x86_64, arm64 ] - target: [ native-native-gnu.2.17 ] - steps: - - name: Checkout code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Set up SSH key - uses: webfactory/ssh-agent@d4b9b8ff72958532804b70bbe600ad43b36d5f2e # v0.8.0 - with: - ssh-private-key: ${{ secrets.GITHUBRPMHENDERKESPRIVATEKEY }} - - - name: Add remote host to known_hosts - run: | - mkdir -p ~/.ssh - cat >> ~/.ssh/known_hosts <<'EOF' - ${{ secrets.DEB_SERVER_IP }} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPQq0y77dDEtxECVMhCxjcqiV369goMcbInsY/d+F1yXGwqOXQ6RqIEzgaVhgq0joMJT5BiGXNXQ+OI10/KtzGI= - ${{ secrets.DEB_SERVER_IP }} ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2laCc5jifgjL/2zLzgP1E/X3kouXdaZv00KtAV1DOO5umThoWzb16cswnVtjtLUEMIuo9rPLB79xX2Asa+nN3uMgJDANnr/xnhRoI++yOGLga40/O69U88j5x+5FXODscH/k4n85mfcjzm/fZLXcHlb17ibCmU20I3v46sydn95Pp4/ShDvqsHVB4gWEKJ+jStkooUz2H1UZ8ZquNtaPTlmkOeClNj6gxag74P5b9VB6M5YNac2Emi3Nm0dYkc+BL0Qv+NEtFR1lR63DLa3O/NGTALGJYGmTUkjwiv8KygegaKhd2zxESmWhV7eYIPax8zL+GE9sX1Xwwh1huS0vsuwr2dXPP1/q5slz1AQV/lx85fGdiHc0F8RUXwqXbvGxZJheTuC/Mgu0cFzp5gqO4kTP28X+9fokzScBKBCIfObDXrl7rZgTXAA8IQ5gHk1tGchaEOIcDsjdISW5HVOiwocYSwUNMHzuZ08qAulatIywtOGcWVRdvOs7TcvSgfZ0= - ${{ secrets.DEB_SERVER_IP }} ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaB5IjokRHAH0Y9pzVe/Jx3s6cn0OADJ9uTxQQubBMu - EOF - - - name: Set architecture variables - run: | - if [[ "${{ matrix.arch }}" == "arm64" ]]; then - echo "RPM_ARCH=aarch64" >> $GITHUB_ENV - else - echo "RPM_ARCH=${{ matrix.arch }}" >> $GITHUB_ENV - fi - - - name: Set target folder - run: | - if [[ "${{ matrix.target }}" == *"2.17"* ]]; then - echo "TARGET_DIR=el7" >> $GITHUB_ENV - elif [[ "${{ matrix.target }}" == *"2.28"* ]]; then - echo "TARGET_DIR=el8" >> $GITHUB_ENV - elif [[ "${{ matrix.target }}" == *"2.34"* ]]; then - echo "TARGET_DIR=el9" >> $GITHUB_ENV - elif [[ "${{ matrix.target }}" == *"2.39"* ]]; then - echo "TARGET_DIR=el10" >> $GITHUB_ENV - else - echo "TARGET_DIR=el10" >> $GITHUB_ENV - fi - - - name: Install APT dependencies - run: | - sudo apt-get update - sudo apt-get install -y curl ruby rpm build-essential tar zstd - sudo apt-get upgrade -y - sudo gem install fpm - - - name: Install composer - run: | - sudo curl -L https://files.henderkes.com/${RPM_ARCH}-linux/php -o /usr/local/bin/php - sudo chmod +x /usr/local/bin/php - sudo curl -sS https://raw.githubusercontent.com/composer/getcomposer.org/f3108f64b4e1c1ce6eb462b159956461592b3e3e/web/installer | php -- --quiet - sudo mv composer.phar /usr/local/bin/composer - - - name: Prepare cache directories - run: | - composer config -g cache-dir - - - name: Restore Composer cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/composer - key: composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - composer- - - - name: Install vendor - run: composer install --no-interaction --prefer-dist --no-progress - - - name: Download artifact from spc-download.yml - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: spc-download.yml - name: downloads-tarball - search_artifacts: true - - - name: Extract with permissions - run: | - mkdir -p downloads - tar -xzf downloads.tar.gz -C downloads - rm downloads.tar.gz - - - name: Build PHP and packages - run: | - PACKAGES_FLAG="" - if [[ -n "${{ env.PACKAGES }}" ]]; then - PACKAGES_FLAG="--packages=${{ env.PACKAGES }}" - fi - ITERATION_FLAG="" - if [[ -n "${{ env.ITERATION }}" ]]; then - ITERATION_FLAG="--iteration=${{ env.ITERATION }}" - fi - php bin/spp all --type=rpm --debuginfo --target=${{ matrix.target }} --phpv=${{ matrix.php-version }} $ITERATION_FLAG $PACKAGES_FLAG - - - name: Prepare rpm signing - run: | - # Setup GPG - export GNUPGHOME="${HOME}/.gnupg" - mkdir -p "${GNUPGHOME}" - chmod 700 "${GNUPGHOME}" - - echo "allow-loopback-pinentry" > "${GNUPGHOME}/gpg-agent.conf" - gpgconf --kill gpg-agent - - # Import private key and extract fingerprint - FPR=$(printf '%s' "${{ secrets.DEB_GPG_PRIVATE_KEY }}" \ - | gpg --batch --quiet --with-colons --import-options show-only --import 2>/dev/null \ - | awk -F: '/^fpr:/ {print $10; exit}') - printf '%s' "${{ secrets.DEB_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import - - # Configure gpg.conf - { - echo "pinentry-mode loopback" - echo "default-key ${FPR}" - } > "${GNUPGHOME}/gpg.conf" - - # Unlock key with passphrase (warmup) - t=$(mktemp); echo warmup > "$t" - gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 \ - --local-user "${FPR}" --sign --output /dev/null "$t" <<<"${{ secrets.DEB_GPG_PASSWORD }}" - rm -f "$t" - - # Create ~/.rpmmacros (not /root/.rpmmacros!) - cat > ~/.rpmmacros </`. +- `bin/createrepo_static`, `bin/forgejo-helper` — repo-side tools. +- `src/` — PHP source (`src/Command`, `src/step`, `src/package`, `src/util`, `src/patches`, `src/ini`, `CraftConfig.php`, `extension.php`, `package.php`). +- `craft.yml` — top-level static-php-cli config: extensions list, build options, SPC_* env (CFLAGS, LDFLAGS, etc.). When toolchain/optimization questions come up, look here before guessing. +- `Dockerfile.{rhel,debian,alpine}` — builders. Built by `.github/workflows/build-images.yml`. +- `.github/workflows/`: + - `build-rpm-modular-packages.yml` — Alma 8/9/10 × x86_64/arm64 × PHP 8.2/8.3/8.4/8.5. Uploads via rsync+SSH then runs `createrepo_c` on the remote. + - `build-deb-forgejo.yml`, `build-apk-forgejo.yml` — Debian/Alpine builds, push to Forgejo. + - `build-images.yml` — builds the builder containers (libs-only step exists to save build time; uses thin LTO). + - `spc-download.yml` — produces the `downloads-tarball` artifact that the build workflows pull via `dawidd6/action-download-artifact`. + - `zizmor.yml` — workflow security audit. + +## Builder containers + +`Dockerfile.rhel` is matrix-built per Alma version into `ghcr.io/static-php/packages-builder-rhel-{8,9,10}`. It installs `tar`, `zstd`, `gcc-toolset-15`, `cmake` 3.31, `re2c`, `fpm`, and a prebuilt `php` from `files.henderkes.com`. + +When editing `Dockerfile.rhel`, remember the per-Alma branches: + +- **Alma 8/9** use `@ruby:3.3` module + `source /opt/rh/gcc-toolset-15/enable`. +- **Alma 10** uses plain `ruby` + `source /usr/lib/gcc-toolset/15-env.source`. +- **Alma 8** has no `re2c` package — built from source (4.3 tarball). 9/10 install from repo. + +## PHP toolchain selection + +Toolchain is chosen by **package type**, not PHP version: + +- **RPM (Alma) and DEB (Debian)** → `gcc` for **all** PHP versions (8.2–8.5). No `--target` is passed, so `craft.yml.twig` sets `using_gcc = not target` → `GccNativeToolchain`. +- **APK (Alpine)** → `zig` (musl cross). `build-apk-forgejo.yml` passes `--target="native-native-musl -dynamic"`, so `using_gcc` is false. + +The `build-libs-gcc` job builds one lib set per (alma, arch) with `phpv: "8.4"` as the canonical trigger (libs are PHP-version-independent). The downstream `build` step reuses that single buildroot (`buildroot-rpm-alma{V}-{arch}-gcc` / `buildroot-deb-{arch}-gcc`) for every PHP version. Buildroots ship as `cache-YYYY-WW` GitHub **release** assets via the `.github/actions/buildroot-cache` composite action (pruned by `buildroot-cache-cleanup.yml`). + +## AlmaLinux 8 tar quirk + +**Alma 8 ships GNU tar 1.30** — `tar --zstd` is unsupported (the flag was added in tar 1.31). Pipe through the standalone `zstd` binary instead (it's in `Dockerfile.rhel`): + +```bash +# Pack +tar -cf - buildroot | zstd -o buildroot.tar.zst +# Unpack +zstd -dc buildroot.tar.zst | tar -xf - +``` + +The deb/apk forgejo workflows still use `tar --zstd` — that is **fine**; they don't run on Alma. Don't "fix" them. + +## Matrix isolation pattern + +Per-Alma failures must not cascade. Pattern used in `build-rpm-modular-packages.yml`: + +1. **Fan-out job** uses `strategy.fail-fast: false` and an explicit, parseable `name:` like `Build libs gcc (alma{V} {arch})` or `Build (alma{V} {arch} php{V})`. The name format is the contract — downstream filters parse it. +2. **Filter job** runs with `if: ${{ !cancelled() }}` and `permissions: actions: read`. It calls `gh api repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs --paginate --jq …`, filters successful jobs by name regex, sed-extracts the tuple, then jq-builds an `{include: [...]}` matrix and an `any` boolean. Both go to `$GITHUB_OUTPUT`. +3. **Downstream job** does `needs: [filter-job]`, gates with `if: ${{ !cancelled() && needs.filter-job.outputs.any == 'true' }}`, and uses `matrix: ${{ fromJson(needs.filter-job.outputs.matrix) }}`. + +Why `!cancelled()` not `success()`: upstream matrix entries are allowed to fail; without `!cancelled()` the filter job wouldn't run at all. + +When adding a new downstream stage to any workflow, follow this pattern rather than relying on `needs.*.result` (which collapses across the whole matrix). + +## Validating workflow changes locally + +Before pushing, validate YAML and simulate the jq filters: + +```bash +# YAML syntax +python3 -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" .github/workflows/build-rpm-modular-packages.yml + +# Simulate the compute-build-gcc-matrix jq with a mocked "succeeded" (alma arch) string +FULL_MATRIX='{"php-version":["8.2","8.3","8.4","8.5"],"alma":["8","9","10"],"arch":["x86_64","arm64"]}' +succeeded=$'9 x86_64\n9 arm64\n10 x86_64\n10 arm64' +jq -nc --argjson m "$FULL_MATRIX" --arg s "$succeeded" ' + ($s | split("\n") | map(select(length > 0))) as $set | + [ $m["php-version"][] as $p | $m.alma[] as $a | $m.arch[] as $r | + select($set | index("\($a) \($r)")) | + {"php-version": $p, alma: $a, arch: $r} + ]' +``` + +The Plan/Explore agents can also read large workflow files, but for these targeted edits prefer Read + Edit directly. + +## Workflow style conventions + +- 4-space indentation throughout (including step bodies). +- Steps written as `- name:` (3 spaces between dash and key). Match this when adding new steps. +- All third-party `uses:` actions are pinned to commit SHAs with a `# vX` trailing comment. Keep that style; don't switch to floating tags. +- `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true` is set in container jobs because the GH-hosted Node in Alma containers is too old. +- `runs-on` for arm64: `ubuntu-24.04-arm` (RPM) or `ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }}` (DEB style). +- Matrix arch is `arm64`/`x86_64` in inputs; the RPM tooling wants `aarch64` — the conversion happens in the "Set architecture variables" step (`MATRIX_ARCH` env → `RPM_ARCH`). + +## Build inputs + +All build-* workflows accept comma-separated overrides via `workflow_dispatch`: + +- `php_versions` (e.g., `8.2,8.5`) — empty = all. +- `alma_versions` (RPM only). +- `architectures` (`x86_64,arm64` for RPM/APK; `amd64,arm64` for DEB). +- `packages` — passed through to `bin/spp` as `--packages=…`. +- `iteration` — passed through as `--iteration=…`. +- `debug_tmate` — opens tmate on failure (only after build step; tmate binary is downloaded inline because Alma doesn't ship it). + +When the user asks to "rerun for X only", they mean these inputs. + +## Operational notes + +- Packages are uploaded via `rsync` over SSH to `${{ secrets.DEB_SERVER_IP }}:/mnt/data/{rpm|deb|apk}/${RPM_ARCH}/${TARGET_DIR}/`. RPM `update-repo` job ssh-runs `createrepo_static && createrepo_c --update . && modifyrepo_c …` on the remote. +- RPM signing: GPG key from `secrets.DEB_GPG_PRIVATE_KEY` + passphrase `DEB_GPG_PASSWORD`, loaded into `~/.rpmmacros` and used by `rpmsign --addsign`. +- Cache: composer cache is the only persistent cache (`actions/cache` keyed on `composer.lock`). +- `buildroot-*` artifacts are uploaded with `retention-days: 1` — they're cheap intermediates. + +## Don'ts + +- Don't switch `tar --zstd` to pipes in the deb/apk workflows — they don't run on Alma. +- Don't skip pinning new actions to SHAs. +- Don't replace the dynamic-matrix filter pattern with `if: needs.X.result == 'success'` — that fails closed for the whole matrix when any entry fails. +- Don't `git push` or `gh pr create` unless explicitly asked. diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ea05d11..9050398 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -41,14 +41,18 @@ RUN U=$(id -un 1000 2>/dev/null || echo "") && \ echo "$U ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/builder # Pre-install SPC's go-xcaddy and zig packages so workflows don't redownload them. +ARG GITHUB_TOKEN= ENV PKG_ROOT_PATH=/opt/spc-pkgroot COPY composer.json composer.lock /tmp/spc-bootstrap/ RUN cd /tmp/spc-bootstrap && \ + export GITHUB_TOKEN="${GITHUB_TOKEN}" && \ mkdir -p src && \ composer install --no-interaction --prefer-dist --no-progress --no-scripts && \ php vendor/bin/spc install-pkg go-xcaddy && \ SPC_TARGET="$(uname -m)-linux-musl" php vendor/bin/spc install-pkg zig && \ + php vendor/bin/spc install-pkg llvm-tools && \ SPC_TARGET=native-native-musl php vendor/bin/spc doctor --auto-fix --debug && \ + cp /tmp/spc-bootstrap/downloads/.cache.json "$PKG_ROOT_PATH/.cache.json" && \ rm -rf /tmp/spc-bootstrap /root/.composer /root/.cache && \ chown -R ${UID}:${GID} "$PKG_ROOT_PATH" diff --git a/Dockerfile.debian b/Dockerfile.debian index 85a4a70..06b5773 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -38,14 +38,18 @@ RUN U=$(id -un 1000 2>/dev/null || echo "") && \ echo "$U ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/builder # Pre-install SPC's go-xcaddy and zig packages so workflows don't redownload them. +ARG GITHUB_TOKEN= ENV PKG_ROOT_PATH=/opt/spc-pkgroot COPY composer.json composer.lock /tmp/spc-bootstrap/ RUN cd /tmp/spc-bootstrap && \ + export GITHUB_TOKEN="${GITHUB_TOKEN}" && \ mkdir -p src && \ composer install --no-interaction --prefer-dist --no-progress --no-scripts && \ php vendor/bin/spc install-pkg go-xcaddy && \ SPC_TARGET="$(uname -m)-linux-musl" php vendor/bin/spc install-pkg zig && \ + php vendor/bin/spc install-pkg llvm-tools && \ SPC_TARGET=native-native-musl php vendor/bin/spc doctor --auto-fix --debug && \ + cp /tmp/spc-bootstrap/downloads/.cache.json "$PKG_ROOT_PATH/.cache.json" && \ rm -rf /tmp/spc-bootstrap /root/.composer /root/.cache && \ chown -R ${UID}:${GID} "$PKG_ROOT_PATH" diff --git a/Dockerfile.rhel b/Dockerfile.rhel index e1f070a..057afbc 100644 --- a/Dockerfile.rhel +++ b/Dockerfile.rhel @@ -33,7 +33,7 @@ RUN dnf -y install epel-release dnf-plugins-core && \ git jq gzip which sudo xz tar zstd curl \ python3 python3-requests \ bison flex autoconf automake gettext-devel libtool pkgconfig \ - gcc-toolset-15 llvm nasm && \ + gcc-toolset-15 llvm nasm gperf && \ mkdir -p /usr/lib/bfd-plugins && \ PLUGIN=$(find /usr/lib /usr/lib64 -name LLVMgold.so 2>/dev/null | head -1) && \ [ -n "$PLUGIN" ] && ln -sf "$PLUGIN" /usr/lib/bfd-plugins/LLVMgold.so @@ -64,10 +64,17 @@ RUN curl -o cmake.tar.gz -fsSL "https://github.com/Kitware/CMake/releases/downlo tar -xzf cmake.tar.gz -C /usr/local --strip-components=1 && \ rm cmake.tar.gz +ARG GITHUB_TOKEN= RUN RPM_ARCH=$(cat /tmp/rpm_arch) && \ curl -L "https://files.henderkes.com/${RPM_ARCH}-linux/php" -o /usr/local/bin/php && \ chmod +x /usr/local/bin/php && \ - curl -sS https://raw.githubusercontent.com/composer/getcomposer.org/f3108f64b4e1c1ce6eb462b159956461592b3e3e/web/installer | php -- --quiet && \ + COMPOSER_INSTALLER_SHA=f3108f64b4e1c1ce6eb462b159956461592b3e3e && \ + if [ -n "${GITHUB_TOKEN}" ]; then \ + curl -sS -H "Authorization: Bearer ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.raw" \ + "https://api.github.com/repos/composer/getcomposer.org/contents/web/installer?ref=${COMPOSER_INSTALLER_SHA}" | php -- --quiet; \ + else \ + curl -sS "https://raw.githubusercontent.com/composer/getcomposer.org/${COMPOSER_INSTALLER_SHA}/web/installer" | php -- --quiet; \ + fi && \ mv composer.phar /usr/bin/composer RUN U=$(id -un 1000 2>/dev/null || echo "") && \ @@ -77,14 +84,18 @@ RUN U=$(id -un 1000 2>/dev/null || echo "") && \ echo "$U ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/builder # Pre-install SPC's go-xcaddy and zig packages so workflows don't redownload them. +ARG GITHUB_TOKEN= ENV PKG_ROOT_PATH=/opt/spc-pkgroot COPY composer.json composer.lock /tmp/spc-bootstrap/ RUN cd /tmp/spc-bootstrap && \ + export GITHUB_TOKEN="${GITHUB_TOKEN}" && \ mkdir -p src && \ composer install --no-interaction --prefer-dist --no-progress --no-scripts && \ php vendor/bin/spc install-pkg go-xcaddy && \ SPC_TARGET="$(uname -m)-linux-musl" php vendor/bin/spc install-pkg zig && \ + php vendor/bin/spc install-pkg llvm-tools && \ SPC_TARGET=native-native-musl php vendor/bin/spc doctor --auto-fix --debug && \ + cp /tmp/spc-bootstrap/downloads/.cache.json "$PKG_ROOT_PATH/.cache.json" && \ rm -rf /tmp/spc-bootstrap /root/.composer /root/.cache && \ chown -R ${UID}:${GID} "$PKG_ROOT_PATH" diff --git a/bin/spp b/bin/spp index 5d0609b..08dcaa5 100755 --- a/bin/spp +++ b/bin/spp @@ -10,11 +10,28 @@ const DIST_DEB_PATH = DIST_PATH . '/deb'; const DIST_APK_PATH = DIST_PATH . '/apk'; define('TEMP_DIR', sys_get_temp_dir() . '/spc-packages'); +// Seed SPC's download cache from the container's prebuilt PKG_ROOT_PATH (set in +// Dockerfile.{rhel,debian,alpine}). The bootstrap step installs zig + go-xcaddy +// into PKG_ROOT_PATH and saves the resulting cache; without this merge SPC would +// re-download them on first run inside /build. +$_seed = ($_pkg_root = getenv('PKG_ROOT_PATH')) ? $_pkg_root . '/.cache.json' : null; +$_target = BASE_PATH . '/downloads/.cache.json'; +if ($_seed && is_readable($_seed)) { + $_seed_data = json_decode((string) file_get_contents($_seed), true) ?: []; + $_target_data = is_readable($_target) ? (json_decode((string) file_get_contents($_target), true) ?: []) : []; + $_merged = $_target_data + $_seed_data; + if ($_merged !== $_target_data) { + if (!is_dir(dirname($_target))) { + mkdir(dirname($_target), 0755, true); + } + file_put_contents($_target, json_encode($_merged, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + } +} +unset($_seed, $_target, $_seed_data, $_target_data, $_merged, $_pkg_root); // Ensure autoloading is set up require_once BASE_PATH . '/vendor/autoload.php'; -use SPC\builder\linux\SystemUtil; use staticphp\step\CreatePackages; use Symfony\Component\Console\Application; use staticphp\Command\BuildCommand; diff --git a/composer.json b/composer.json index 265bc46..a012b08 100644 --- a/composer.json +++ b/composer.json @@ -20,14 +20,16 @@ "prefer-stable": true, "require": { "php": ">=8.5", + "ext-simplexml": "*", "ext-yaml": "*", "ext-zlib": "*", - "crazywhalecc/static-php-cli": "dev-feat/pgo", + "crazywhalecc/static-php-cli": "dev-feat/pgo-v3", "laravel/helpers": "^1.7", "twig/twig": "^3.0" }, "require-dev": { - "roave/security-advisories": "dev-latest" + "friendsofphp/php-cs-fixer": "^3.95", + "phpstan/phpstan": "^2.1" }, "autoload": { "classmap": [ diff --git a/composer.lock b/composer.lock index f840f94..8b58db1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "faee9a9425c1129961eb9728e0d619fc", + "content-hash": "aef4385aaa6d7e98eea0eee7641eea22", "packages": [ { "name": "carbonphp/carbon-doctrine-types", @@ -77,36 +77,40 @@ }, { "name": "crazywhalecc/static-php-cli", - "version": "dev-feat/pgo", + "version": "dev-feat/pgo-v3", "source": { "type": "git", "url": "https://github.com/crazywhalecc/static-php-cli.git", - "reference": "2adedc0943317ddf1d10118f9675bd40766a35db" + "reference": "6b6a099a47fa3a5bcc41af3184de5f8a0b538eb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/crazywhalecc/static-php-cli/zipball/2adedc0943317ddf1d10118f9675bd40766a35db", - "reference": "2adedc0943317ddf1d10118f9675bd40766a35db", + "url": "https://api.github.com/repos/crazywhalecc/static-php-cli/zipball/6b6a099a47fa3a5bcc41af3184de5f8a0b538eb1", + "reference": "6b6a099a47fa3a5bcc41af3184de5f8a0b538eb1", "shasum": "" }, "require": { "ext-mbstring": "*", "ext-zlib": "*", - "laravel/prompts": "^0.1.12", - "php": ">= 8.3", + "laravel/prompts": "~0.1", + "php": ">=8.4", + "php-di/php-di": "^7.1", "symfony/console": "^5.4 || ^6 || ^7", "symfony/process": "^7.2", "symfony/yaml": "^7.2", - "zhamao/logger": "^1.1.3" + "zhamao/logger": "^1.1.4" }, "require-dev": { "captainhook/captainhook-phar": "^5.23", "captainhook/hook-installer": "^1.0", "friendsofphp/php-cs-fixer": "^3.60", "humbug/box": "^4.5.0 || ^4.6.0", - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^10.3 || ^9.5" }, + "suggest": { + "ext-yaml": "Speeds up YAML config file parsing" + }, "bin": [ "bin/spc" ], @@ -117,7 +121,8 @@ "src/globals/functions.php" ], "psr-4": { - "SPC\\": "src/SPC" + "Package\\": "src/Package", + "StaticPHP\\": "src/StaticPHP" } }, "notification-url": "https://packagist.org/downloads/", @@ -133,7 +138,7 @@ "description": "Build single static PHP binary, with PHP project together, with popular extensions included.", "support": { "issues": "https://github.com/crazywhalecc/static-php-cli/issues", - "source": "https://github.com/crazywhalecc/static-php-cli/tree/feat/pgo" + "source": "https://github.com/crazywhalecc/static-php-cli/tree/feat/pgo-v3" }, "funding": [ { @@ -141,7 +146,7 @@ "type": "other" } ], - "time": "2026-07-09T07:07:41+00:00" + "time": "2026-07-09T12:27:41+00:00" }, { "name": "doctrine/inflector", @@ -235,31 +240,35 @@ }, { "name": "illuminate/collections", - "version": "v11.51.0", + "version": "v13.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "856b1da953e46281ba61d7c82d337072d3ee1825" + "reference": "b58840a1bbbba5cb5895760bd806808fdfdd7e51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/856b1da953e46281ba61d7c82d337072d3ee1825", - "reference": "856b1da953e46281ba61d7c82d337072d3ee1825", + "url": "https://api.github.com/repos/illuminate/collections/zipball/b58840a1bbbba5cb5895760bd806808fdfdd7e51", + "reference": "b58840a1bbbba5cb5895760bd806808fdfdd7e51", "shasum": "" }, "require": { - "illuminate/conditionable": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "php": "^8.2" + "illuminate/conditionable": "^13.0", + "illuminate/contracts": "^13.0", + "illuminate/macroable": "^13.0", + "php": "^8.3", + "symfony/polyfill-php84": "^1.36", + "symfony/polyfill-php85": "^1.36", + "symfony/polyfill-php86": "^1.36" }, "suggest": { - "symfony/var-dumper": "Required to use the dump method (^7.0)." + "illuminate/http": "Required to convert collections to API resources (^13.0).", + "symfony/var-dumper": "Required to use the dump method (^7.4 || ^8.0)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "13.0.x-dev" } }, "autoload": { @@ -287,29 +296,29 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-03-24T11:54:20+00:00" + "time": "2026-07-06T15:30:07+00:00" }, { "name": "illuminate/conditionable", - "version": "v11.51.0", + "version": "v13.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", - "reference": "319b717e0587bd7c8a3b44464f0e27867b4bcda9" + "reference": "7f1ef52d9a346f829421b296adfb7644a951b216" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/319b717e0587bd7c8a3b44464f0e27867b4bcda9", - "reference": "319b717e0587bd7c8a3b44464f0e27867b4bcda9", + "url": "https://api.github.com/repos/illuminate/conditionable/zipball/7f1ef52d9a346f829421b296adfb7644a951b216", + "reference": "7f1ef52d9a346f829421b296adfb7644a951b216", "shasum": "" }, "require": { - "php": "^8.0.2" + "php": "^8.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "13.0.x-dev" } }, "autoload": { @@ -333,31 +342,31 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-03-24T11:54:20+00:00" + "time": "2026-02-25T16:07:55+00:00" }, { "name": "illuminate/contracts", - "version": "v11.51.0", + "version": "v13.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "4787042340aae19a7ea0fa82f4073c4826204a48" + "reference": "a108b67e086a933e92abebe69bb8e15c1218d3c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/4787042340aae19a7ea0fa82f4073c4826204a48", - "reference": "4787042340aae19a7ea0fa82f4073c4826204a48", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/a108b67e086a933e92abebe69bb8e15c1218d3c8", + "reference": "a108b67e086a933e92abebe69bb8e15c1218d3c8", "shasum": "" }, "require": { - "php": "^8.2", - "psr/container": "^1.1.1|^2.0.1", - "psr/simple-cache": "^1.0|^2.0|^3.0" + "php": "^8.3", + "psr/container": "^1.1.1 || ^2.0.1", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "13.0.x-dev" } }, "autoload": { @@ -381,20 +390,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-11-27T16:16:07+00:00" + "time": "2026-06-25T18:32:48+00:00" }, { "name": "illuminate/macroable", - "version": "v11.51.0", + "version": "v13.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", - "reference": "e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed" + "reference": "59b5b5f3cf290a91db8cf6cd3d35ff56978bc057" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/macroable/zipball/e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed", - "reference": "e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/59b5b5f3cf290a91db8cf6cd3d35ff56978bc057", + "reference": "59b5b5f3cf290a91db8cf6cd3d35ff56978bc057", "shasum": "" }, "require": { @@ -403,7 +412,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "13.0.x-dev" } }, "autoload": { @@ -427,20 +436,71 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-06-28T20:10:30+00:00" + "time": "2026-04-29T09:35:06+00:00" + }, + { + "name": "illuminate/reflection", + "version": "v13.19.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/reflection.git", + "reference": "178cdb5eb08c5369ae6b71518e557bed68e74577" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/reflection/zipball/178cdb5eb08c5369ae6b71518e557bed68e74577", + "reference": "178cdb5eb08c5369ae6b71518e557bed68e74577", + "shasum": "" + }, + "require": { + "illuminate/collections": "^13.0", + "illuminate/contracts": "^13.0", + "php": "^8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "13.0.x-dev" + } + }, + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Reflection package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2026-06-18T15:47:27+00:00" }, { "name": "illuminate/support", - "version": "v11.51.0", + "version": "v13.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "11cc8bd46991e277f6af19eb9dee5d4c1f65c7d2" + "reference": "6cff5e09069fc1961536d0f61d1c9ab935cc2a23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/11cc8bd46991e277f6af19eb9dee5d4c1f65c7d2", - "reference": "11cc8bd46991e277f6af19eb9dee5d4c1f65c7d2", + "url": "https://api.github.com/repos/illuminate/support/zipball/6cff5e09069fc1961536d0f61d1c9ab935cc2a23", + "reference": "6cff5e09069fc1961536d0f61d1c9ab935cc2a23", "shasum": "" }, "require": { @@ -448,12 +508,14 @@ "ext-ctype": "*", "ext-filter": "*", "ext-mbstring": "*", - "illuminate/collections": "^11.0", - "illuminate/conditionable": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "nesbot/carbon": "^2.72.6|^3.8.4", - "php": "^8.2", + "illuminate/collections": "^13.0", + "illuminate/conditionable": "^13.0", + "illuminate/contracts": "^13.0", + "illuminate/macroable": "^13.0", + "illuminate/reflection": "^13.0", + "nesbot/carbon": "^3.8.4", + "php": "^8.3", + "symfony/polyfill-php85": "^1.36", "voku/portable-ascii": "^2.0.2" }, "conflict": { @@ -463,20 +525,20 @@ "spatie/once": "*" }, "suggest": { - "illuminate/filesystem": "Required to use the Composer class (^11.0).", - "laravel/serializable-closure": "Required to use the once function (^1.3|^2.0).", + "illuminate/filesystem": "Required to use the Composer class (^13.0).", + "laravel/serializable-closure": "Required to use the once function (^2.0.10).", "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.7).", "league/uri": "Required to use the Uri class (^7.5.1).", "ramsey/uuid": "Required to use Str::uuid() (^4.7).", - "symfony/process": "Required to use the Composer class (^7.0).", - "symfony/uid": "Required to use Str::ulid() (^7.0).", - "symfony/var-dumper": "Required to use the dd function (^7.0).", + "symfony/process": "Required to use the Composer class (^7.4 || ^8.0).", + "symfony/uid": "Required to use Str::ulid() (^7.4 || ^8.0).", + "symfony/var-dumper": "Required to use the dd function (^7.4 || ^8.0).", "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.6.1)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "13.0.x-dev" } }, "autoload": { @@ -504,7 +566,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-20T15:25:35+00:00" + "time": "2026-07-06T23:09:58+00:00" }, { "name": "laravel/helpers", @@ -565,33 +627,34 @@ }, { "name": "laravel/prompts", - "version": "v0.1.25", + "version": "v0.3.21", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95" + "reference": "7753c65c281c2550c7c183f14e18062073b7d821" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/7b4029a84c37cb2725fc7f011586e2997040bc95", - "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95", + "url": "https://api.github.com/repos/laravel/prompts/zipball/7753c65c281c2550c7c183f14e18062073b7d821", + "reference": "7753c65c281c2550c7c183f14e18062073b7d821", "shasum": "" }, "require": { + "composer-runtime-api": "^2.2", "ext-mbstring": "*", - "illuminate/collections": "^10.0|^11.0", "php": "^8.1", - "symfony/console": "^6.2|^7.0" + "symfony/console": "^6.2|^7.0|^8.0" }, "conflict": { "illuminate/console": ">=10.17.0 <10.25.0", "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", "mockery/mockery": "^1.5", - "pestphp/pest": "^2.3", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-mockery": "^1.1" + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" }, "suggest": { "ext-pcntl": "Required for the spinner to be animated." @@ -599,7 +662,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "0.1.x-dev" + "dev-main": "0.3.x-dev" } }, "autoload": { @@ -617,9 +680,70 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.25" + "source": "https://github.com/laravel/prompts/tree/v0.3.21" + }, + "time": "2026-06-26T00:11:25+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.13", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b566ee0dd251f3c4078bed003a7ce015f5ea6dce", + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-08-12T22:06:33+00:00" + "time": "2026-04-16T14:03:50+00:00" }, { "name": "nesbot/carbon", @@ -726,6 +850,134 @@ ], "time": "2026-06-18T13:49:15+00:00" }, + { + "name": "php-di/invoker", + "version": "2.3.7", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2025-08-30T10:22:22+00:00" + }, + { + "name": "php-di/php-di", + "version": "7.1.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f88054cc052e40dbe7b383c8817c19442d480352", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0 || ^2.0", + "php": ">=8.0", + "php-di/invoker": "^2.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.6 || ^10 || ^11", + "vimeo/psalm": "^5|^6" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.1.1" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2025-08-16T11:10:48+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -1510,29 +1762,38 @@ "time": "2026-05-27T06:59:30+00:00" }, { - "name": "symfony/process", - "version": "v7.4.13", + "name": "symfony/polyfill-php84", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "f5804be144caceb570f6747519999636b664f24c" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f5804be144caceb570f6747519999636b664f24c", - "reference": "f5804be144caceb570f6747519999636b664f24c", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Process\\": "" + "Symfony\\Polyfill\\Php84\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1541,18 +1802,24 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Executes commands in sub-processes", + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/process/tree/v7.4.13" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1" }, "funding": [ { @@ -1572,46 +1839,41 @@ "type": "tidelift" } ], - "time": "2026-05-23T16:05:06+00:00" + "time": "2026-05-26T12:51:13+00:00" }, { - "name": "symfony/service-contracts", - "version": "v3.7.1", + "name": "symfony/polyfill-php85", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.7-dev" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Contracts\\Service\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, - "exclude-from-classmap": [ - "/Test/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1628,18 +1890,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1" }, "funding": [ { @@ -1659,31 +1919,263 @@ "type": "tidelift" } ], - "time": "2026-06-16T09:55:08+00:00" + "time": "2026-05-26T02:25:22+00:00" }, { - "name": "symfony/string", - "version": "v8.1.0", + "name": "symfony/polyfill-php86", + "version": "v1.38.0", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" + "url": "https://github.com/symfony/polyfill-php86.git", + "reference": "fcec68d64f46dc84e1f6ffcf2c6dda40ff3143ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", - "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "url": "https://api.github.com/repos/symfony/polyfill-php86/zipball/fcec68d64f46dc84e1f6ffcf2c6dda40ff3143ad", + "reference": "fcec68d64f46dc84e1f6ffcf2c6dda40ff3143ad", "shasum": "" }, "require": { - "php": ">=8.4.1", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-intl-grapheme": "^1.33", - "symfony/polyfill-intl-normalizer": "^1.0", - "symfony/polyfill-mbstring": "^1.0" + "php": ">=7.2" }, - "conflict": { - "symfony/translation-contracts": "<2.5" + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php86\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php86/tree/v1.38.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-25T11:52:35+00:00" + }, + { + "name": "symfony/process", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "f5804be144caceb570f6747519999636b664f24c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/f5804be144caceb570f6747519999636b664f24c", + "reference": "f5804be144caceb570f6747519999636b664f24c", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-23T16:05:06+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-16T09:55:08+00:00" + }, + { + "name": "symfony/string", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/emoji": "^7.4|^8.0", @@ -2228,1129 +2720,1900 @@ ], "packages-dev": [ { - "name": "roave/security-advisories", - "version": "dev-latest", + "name": "clue/ndjson-react", + "version": "v1.3.0", "source": { "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "1c42f8ab3728bd379639d1988a955d673d4cb365" + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/1c42f8ab3728bd379639d1988a955d673d4cb365", - "reference": "1c42f8ab3728bd379639d1988a955d673d4cb365", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", "shasum": "" }, - "conflict": { - "3f/pygmentize": "<1.2", - "adaptcms/adaptcms": "<=1.3", - "admidio/admidio": "<=5.0.9", - "adodb/adodb-php": "<=5.22.9", - "aheinze/cockpit": "<2.2", - "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", - "aimeos/ai-admin-jsonadm": "<2020.10.13|>=2021.04.1,<2021.10.6|>=2022.04.1,<2022.10.3|>=2023.04.1,<2023.10.4|==2024.04.1", - "aimeos/ai-client-html": ">=2020.04.1,<2020.10.27|>=2021.04.1,<2021.10.22|>=2022.04.1,<2022.10.13|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.04.7", - "aimeos/ai-cms-grapesjs": ">=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.9|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.10.8|>=2025.04.1,<2025.10.2", - "aimeos/ai-controller-frontend": "<2020.10.15|>=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.8|>=2023.04.1,<2023.10.9|==2024.04.1", - "aimeos/aimeos-core": ">=2022.04.1,<2022.10.17|>=2023.04.1,<2023.10.17|>=2024.04.1,<2024.04.7", - "aimeos/aimeos-laravel": "==2021.10", - "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", - "aimeos/pagible": "<0.10.4", - "airesvsg/acf-to-rest-api": "<=3.1", - "akaunting/akaunting": "<2.1.13", - "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", - "alextselegidis/easyappointments": "<=1.5.2", - "alexusmai/laravel-file-manager": "<=3.3.1", - "algolia/algoliasearch-magento-2": "<=3.16.1|>=3.17.0.0-beta1,<=3.17.1", - "almirhodzic/nova-toggle-5": "<1.3", - "alt-design/alt-redirect": "<1.6.4", - "altcha-org/altcha": "<1.3.1", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amazing/media2click": ">=1,<1.3.3", - "ameos/ameos_tarteaucitron": "<1.2.23", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<=1.7.2|>=2,<=2.1", - "amphp/http-client": ">=4,<4.4", - "amphp/http-server": ">=2.0.0.0-RC1-dev,<2.1.10|>=3.0.0.0-beta1,<3.4.4", - "anchorcms/anchor-cms": "<=0.12.7", - "andreapollastri/cipi": "<=3.1.15", - "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", - "aoe/restler": "<1.7.1", - "apache-solr-for-typo3/solr": "<2.8.3", - "apereo/phpcas": "<1.6", - "api-platform/core": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", - "api-platform/graphql": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", - "appwrite/server-ce": "<=1.2.1", - "arc/web": "<3", - "area17/twill": "<1.2.5|>=2,<2.5.3", - "artesaos/seotools": "<0.17.2", - "asymmetricrypt/asymmetricrypt": "<9.9.99", - "athlon1600/php-proxy": "<=5.1", - "athlon1600/php-proxy-app": "<=3", - "athlon1600/youtube-downloader": "<=4", - "aureuserp/aureuserp": "<1.3.0.0-beta1", - "austintoddj/canvas": "<=3.4.2", - "auth0/auth0-php": ">=3.3,<=8.18", - "auth0/login": "<=7.20", - "auth0/symfony": "<=5.7", - "auth0/wordpress": "<=5.5", - "automad/automad": "<=2.0.0.0-beta27", - "automattic/jetpack": "<9.8", - "awesome-support/awesome-support": "<=6.0.7", - "aws/aws-sdk-php": "<=3.371.3", - "ayacoo/redirect-tab": "<2.1.2|>=3,<3.1.7|>=4,<4.0.5", - "azuracast/azuracast": "<=0.23.5", - "b13/seo_basics": "<0.8.2", - "backdrop/backdrop": "<=1.32", - "backpack/crud": "<4.0.63|>=4.1,<4.1.69|>=5,<5.0.13", - "backpack/filemanager": "<2.0.2|>=3,<3.0.9", - "bacula-web/bacula-web": "<9.7.1", - "badaso/core": "<=2.9.11", - "bagisto/bagisto": "<=2.3.15", - "barrelstrength/sprout-base-email": "<1.2.7", - "barrelstrength/sprout-forms": "<3.9", - "barryvdh/laravel-translation-manager": "<0.6.8", - "barzahlen/barzahlen-php": "<2.0.1", - "baserproject/basercms": "<=5.2.2", - "bassjobsen/bootstrap-3-typeahead": ">4.0.2", - "bbpress/bbpress": "<2.6.5", - "bcit-ci/codeigniter": "<3.1.3", - "bcosca/fatfree": "<3.7.2", - "bedita/bedita": "<4", - "bednee/cooluri": "<1.0.30", - "bigfork/silverstripe-form-capture": ">=3,<3.1.1", - "billabear/billabear": "<=2025.01.03", - "billz/raspap-webgui": "<3.3.6", - "binarytorch/larecipe": "<2.8.1", - "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", - "blueimp/jquery-file-upload": "==6.4.4", - "bmarshall511/wordpress_zero_spam": "<5.2.13", - "bolt/bolt": "<3.7.2", - "bolt/core": "<=4.2", - "born05/craft-twofactorauthentication": "<3.3.4", - "bottelet/flarepoint": "<2.2.1", - "bref/bref": "<2.1.17", - "brightlocal/phpwhois": "<=4.2.5", - "brotkrueml/codehighlight": "<2.7", - "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", - "brotkrueml/typo3-matomo-integration": "<1.3.2", - "buddypress/buddypress": "<7.2.1", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "bvbmedia/multishop": "<2.0.39", - "bytefury/crater": "<6.0.2", - "cachethq/cachet": "<2.5.1", - "cadmium-org/cadmium-cms": "<=0.4.9", - "cakephp/authentication": "<3.3.6|>=4,<4.1.1", - "cakephp/cakephp": "<4.5.11|>=4.6,<4.6.4|>=5,<5.1.7|>=5.2,<5.2.13|>=5.3,<5.3.6", - "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", - "cardgate/magento2": "<2.0.33", - "cardgate/woocommerce": "<=3.1.15", - "cart2quote/module-quotation": ">=4.1.6,<4.4.6|>=5,<5.4.4", - "cart2quote/module-quotation-encoded": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<2.1.7", - "catfan/medoo": "<1.7.5", - "causal/oidc": "<4", - "cecil/cecil": "<7.47.1", - "centreon/centreon": "<22.10.15", - "cesargb/laravel-magiclink": ">=2,<2.25.1", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "chriskacerguis/codeigniter-restserver": "<=2.7.1", - "chrome-php/chrome": "<1.14", - "ci4-cms-erp/ci4ms": "<=0.31.8", - "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", - "ckeditor/ckeditor": "<4.25", - "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", - "co-stack/fal_sftp": "<0.2.6", - "cockpit-hq/cockpit": "<=2.14", - "code16/sharp": "<9.22.3", - "codeception/codeception": "<3.1.3|>=4,<4.1.22", - "codeigniter/framework": "<3.1.10", - "codeigniter4/framework": "<4.7.2", - "codeigniter4/shield": "<1.0.0.0-beta8", - "codiad/codiad": "<=2.8.4", - "codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9", - "codingms/modules": "<4.3.11|>=5,<5.7.4|>=6,<6.4.2|>=7,<7.5.5", - "commerceteam/commerce": ">=0.9.6,<0.9.9", - "components/jquery": ">=1.0.3,<3.5", - "composer/composer": "<2.2.28|>=2.3,<2.9.8", - "concrete5/concrete5": "<9.5.1", - "concrete5/core": "<8.5.8|>=9,<9.1", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", - "contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.13.56|>=5,<5.3.38|>=5.4.0.0-RC1-dev,<5.6.1", - "contao/core": "<3.5.39", - "contao/core-bundle": "<4.13.57|>=5,<5.3.42|>=5.4,<5.6.5", - "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", - "contao/managed-edition": "<=1.5", - "coreshop/core-shop": "<4.1.9|==5", - "corveda/phpsandbox": "<1.3.5", - "cosenary/instagram": "<=2.3", - "cotonti/cotonti": "<=1", - "couleurcitron/tarteaucitron-wp": "<0.3", - "cpsit/typo3-mailqueue": "<0.4.5|>=0.5,<0.5.2", - "craftcms/aws-s3": ">=2.0.2,<=2.2.4", - "craftcms/azure-blob": ">=2.0.0.0-beta1,<=2.1", - "craftcms/cms": "<4.18|>=5,<5.10", - "craftcms/commerce": ">=4,<=4.11.1|>=5,<=5.6.4", - "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", - "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", - "craftcms/google-cloud": ">=2.0.0.0-beta1,<=2.2", - "craftcms/webhooks": ">=3,<3.2", - "croogo/croogo": "<=4.0.7", - "cuyz/valinor": "<0.12", - "czim/file-handling": "<1.5|>=2,<2.3", - "czproject/git-php": "<4.0.3", - "damienharper/auditor-bundle": "<5.2.6", - "dapphp/securimage": "<3.6.6", - "darylldoyle/safe-svg": "<1.9.10", - "datadog/dd-trace": ">=0.30,<0.30.2", - "datahihi1/tiny-env": "<1.0.3|>=1.0.9,<1.0.11", - "datatables/datatables": "<1.10.10", - "david-garcia/phpwhois": "<=4.3.1", - "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", - "dedoc/scramble": ">=0.13.2,<0.13.22", - "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", - "desperado/xml-bundle": "<=0.1.7", - "dev-lancer/minecraft-motd-parser": "<=1.0.5", - "devcode-it/openstamanager": "<=2.10.1", - "devgroup/dotplant": "<2020.09.14-dev", - "digimix/wp-svg-upload": "<=1", - "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", - "directorytree/imapengine": "<1.22.3", - "dl/yag": "<3.0.1", - "dmk/webkitpdf": "<1.1.4", - "dnadesign/silverstripe-elemental": "<5.3.12", - "doctrine/annotations": "<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": "<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<0.7.2", - "doctrine/mongodb-odm": "<1.0.2", - "doctrine/mongodb-odm-bundle": "<3.0.1", - "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<=23.0.2", - "dompdf/dompdf": "<2.0.4", - "doublethreedigital/guest-entries": "<3.1.2", - "dreamfactory/df-core": "<1.0.4", - "drupal-pattern-lab/unified-twig-extensions": "<=0.1", - "drupal/access_code": "<2.0.5", - "drupal/acquia_dam": "<1.1.5", - "drupal/admin_audit_trail": "<1.0.5", - "drupal/ai": "<1.0.5", - "drupal/alogin": "<2.0.6", - "drupal/cache_utility": "<1.2.1", - "drupal/civictheme": "<1.12", - "drupal/commerce_alphabank_redirect": "<1.0.3", - "drupal/commerce_eurobank_redirect": "<2.1.1", - "drupal/config_split": "<1.10|>=2,<2.0.2", - "drupal/core": ">=6,<6.38|>=7,<7.103|>=8,<10.5.10|>=10.6,<10.6.9|>=11,<11.2.12|>=11.3,<11.3.10", - "drupal/core-recommended": ">=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", - "drupal/currency": "<3.5", - "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", - "drupal/email_tfa": "<2.0.6", - "drupal/formatter_suite": "<2.1", - "drupal/gdpr": "<3.0.1|>=3.1,<3.1.2", - "drupal/google_tag": "<1.8|>=2,<2.0.8", - "drupal/ignition": "<1.0.4", - "drupal/json_field": "<1.5", - "drupal/lightgallery": "<1.6", - "drupal/link_field_display_mode_formatter": "<1.6", - "drupal/matomo": "<1.24", - "drupal/oauth2_client": "<4.1.3", - "drupal/oauth2_server": "<2.1", - "drupal/obfuscate": "<2.0.1", - "drupal/plausible_tracking": "<1.0.2", - "drupal/quick_node_block": "<2", - "drupal/rapidoc_elements_field_formatter": "<1.0.1", - "drupal/reverse_proxy_header": "<1.1.2", - "drupal/simple_multistep": "<2", - "drupal/simple_oauth": ">=6,<6.0.7", - "drupal/spamspan": "<3.2.1", - "drupal/tfa": "<1.10", - "drupal/umami_analytics": "<1.0.1", - "duncanmcclean/guest-entries": "<3.1.2", - "dweeves/magmi": "<=0.7.24", - "easycorp/easyadmin-bundle": ">=4,<4.29.10|>=5,<5.0.13", - "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.3.1", - "ecodev/newsletter": "<=4", - "ectouch/ectouch": "<=2.7.2", - "egroupware/egroupware": "<23.1.20260601|>=26.0.20251208,<26.5.20260507", - "elefant/cms": "<2.0.7", - "elgg/elgg": "<3.3.24|>=4,<4.0.5", - "elijaa/phpmemcacheadmin": "<=1.3", - "elmsln/haxcms": "<11.0.14", - "encore/laravel-admin": "<=1.8.19", - "endroid/qr-code-bundle": "<3.4.2", - "enhavo/enhavo-app": "<=0.13.1", - "enshrined/svg-sanitize": "<0.22", - "erusev/parsedown": "<1.7.2", - "ether/logs": "<3.0.4", - "evolutioncms/evolution": "<=3.2.3", - "evoweb/sf-register": "<13.2.4|>=14,<14.0.2", - "exceedone/exment": "<4.4.3|>=5,<5.0.3", - "exceedone/laravel-admin": "<2.2.3|==3", - "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", - "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", - "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.39|>=3.3,<3.3.39", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1|>=5.3.0.0-beta1,<5.3.5", - "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", - "ezsystems/ezplatform-http-cache": "<2.3.16", - "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.35", - "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.26|>=3.3,<3.3.40", - "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.31", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", - "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", - "ezyang/htmlpurifier": "<=4.2", - "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2025.92|>=2026,<=2026.1", - "fastly/magento2": "<1.2.26", - "feehi/cms": "<=2.1.1", - "feehi/feehicms": "<=2.1.1", - "fenom/fenom": "<=2.12.1", - "filament/actions": ">=3.2,<3.2.123|>=4,<=4.11.3|>=5,<=5.6.3", - "filament/filament": ">=3,<=3.3.51|>=4,<4.11.5|>=5,<5.6.5", - "filament/forms": ">=3,<=3.3.52", - "filament/infolists": ">=3,<3.2.115|>=4,<=4.11.4|>=5,<=5.6.4", - "filament/tables": ">=3,<=3.3.50|>=4,<=4.11.4|>=5,<=5.6.4", - "filegator/filegator": "<7.8", - "filp/whoops": "<2.1.13", - "fineuploader/php-traditional-server": "<=1.2.2", - "firebase/php-jwt": "<7", - "fisharebest/webtrees": "<=2.1.18", - "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", - "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<=1.8.15|>=2.0.0.0-beta1,<=2.0.0.0-beta8", - "flarum/flarum": "<0.1.0.0-beta8", - "flarum/framework": "<1.8.10", - "flarum/mentions": "<1.6.3", - "flarum/nicknames": "<1.8.3", - "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", - "flarum/tags": "<=0.1.0.0-beta13", - "flightphp/core": "<3.18.1", - "floriangaerber/magnesium": "<0.3.1", - "fluidtypo3/vhs": "<5.1.1", - "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", - "fof/pretty-mail": "<=1.1.2", - "fof/upload": "<1.2.3", - "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", - "fooman/tcpdf": "<6.2.22", - "forkcms/forkcms": "<5.11.1", - "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<=11.5.1", - "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1,<1.3.5", - "friendsofsymfony1/swiftmailer": ">=4,<5.4.13|>=6,<6.2.5", - "friendsofsymfony1/symfony1": ">=1.1,<1.5.19", - "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", - "friendsoftypo3/tt-address": "<8.1.2|>=9,<9.1.1|>=10,<10.0.1", - "froala/wysiwyg-editor": "<=4.3", - "frosh/adminer-platform": "<2.2.1", - "froxlor/froxlor": "<2.3.7", - "frozennode/administrator": "<=5.0.12", - "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=7.1.0.0-RC6", - "gaoming13/wechat-php-sdk": "<=1.10.2", - "genix/cms": "<=1.1.11", - "georgringer/news": "<10.0.4|>=11,<11.4.4|>=12,<12.3.2|>=13,<13.0.2|>=14,<14.0.3", - "geshi/geshi": "<=1.0.9.1", - "getformwork/formwork": "<=2.3.3", - "getgrav/grav": "<=2.0.0.0-RC8", - "getgrav/grav-plugin-api": "<1.0.0.0-beta15", - "getgrav/grav-plugin-form": "<9.1", - "getkirby/cms": "<=4.9.3|>=5,<=5.4.3", - "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", - "getkirby/panel": "<2.5.14", - "getkirby/starterkit": "<=3.7.0.2", - "gilacms/gila": "<=1.15.4", - "gleez/cms": "<=1.3|==2", - "globalpayments/php-sdk": "<2", - "goalgorilla/open_social": "<12.3.11|>=12.4,<12.4.10|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", - "gogentooss/samlbase": "<1.2.7", - "goodoneuz/pay-uz": "<=2.2.24", - "google/protobuf": "<4.33.6", - "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", - "gp247/core": "<1.1.24", - "gree/jose": "<2.2.1", - "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<=6.6.2", - "gugoan/economizzer": "<=0.9.0.0-beta1", - "guzzlehttp/guzzle": "<7.12.1", - "guzzlehttp/guzzle-services": "<1.5.4", - "guzzlehttp/oauth-subscriber": "<0.8.1", - "guzzlehttp/psr7": "<2.12.1", - "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", - "handcraftedinthealps/goodby-csv": "<1.4.3", - "harvesthq/chosen": "<1.8.7", - "helloxz/imgurl": "<=2.31", - "hhxsv5/laravel-s": "<3.7.36", - "hillelcoren/invoice-ninja": "<5.3.35", - "himiklab/yii2-jqgrid-widget": "<1.0.8", - "hjue/justwriting": "<=1", - "hov/jobfair": "<1.0.13|>=2,<2.0.2", - "httpsoft/http-message": "<1.0.12", - "hybridauth/hybridauth": "<=3.12.2", - "hyn/multi-tenant": ">=5.6,<5.7.2", - "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6,<4.6.25|>=5,<5.0.3", - "ibexa/admin-ui-assets": ">=4.6.0.0-alpha1,<4.6.21", - "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", - "ibexa/fieldtype-richtext": ">=4.6,<4.6.25|>=5,<5.0.3", - "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", - "ibexa/http-cache": ">=4.6,<4.6.14", - "ibexa/post-install": "<1.0.16|>=4.6,<4.6.14", - "ibexa/solr": ">=4.5,<4.5.4", - "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", - "icecoder/icecoder": "<=8.1", - "idno/known": "<1.6.4", - "ilicmiljan/secure-props": ">=1.2,<1.2.2", - "illuminate/auth": "<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", - "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/mail": ">=9,<12.60|>=13,<13.10", - "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "imdbphp/imdbphp": "<=5.1.1", - "impresscms/impresscms": "<=1.4.5", - "impresspages/impresspages": "<1.0.13", - "in2code/femanager": "<6.4.2|>=7,<7.5.3|>=8,<8.3.1", - "in2code/ipandlanguageredirect": "<5.1.2", - "in2code/lux": "<17.6.1|>=18,<24.0.2", - "in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.5.3|==13", - "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<4.2.2", - "inter-mediator/inter-mediator": "==5.5", - "intercom/intercom-php": "==5.0.2", - "invoiceninja/invoiceninja": "<5.13.4", - "ipl/web": "<=0.10.2|>=0.11,<=0.13", - "islandora/crayfish": "<4.1", - "islandora/islandora": ">=2,<2.4.1", - "ivankristianto/phpwhois": "<=4.3", - "j0k3r/graby": "<=2.5", - "jackalope/jackalope-doctrine-dbal": "<1.7.4", - "jambagecom/div2007": "<0.10.2", - "james-heinrich/getid3": "<1.9.21", - "james-heinrich/phpthumb": "<=1.7.23", - "jasig/phpcas": "<1.3.3", - "jbartels/wec-map": "<3.0.3", - "jcbrand/converse.js": "<3.3.3", - "jleehr/canto-saas-api": "<=2", - "joedolson/my-calendar": "<3.7.7", - "joelbutcher/socialstream": "<5.6|>=6,<6.2", - "johnbillion/query-monitor": "<3.20.4", - "johnbillion/wp-crontrol": "<1.16.2|>=1.17,<1.19.2", - "joomla/application": "<1.0.13", - "joomla/archive": "<1.1.12|>=2,<2.0.1", - "joomla/database": ">=1,<2.2|>=3,<3.4", - "joomla/filesystem": "<1.6.2|>=2,<2.0.1", - "joomla/filter": "<2.0.6|>=3,<3.0.5|==4", - "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", - "joomla/input": ">=2,<2.0.2", - "joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6", - "joomla/joomla-platform": "<1.5.4", - "joomla/session": "<1.3.1", - "joyqi/hyper-down": "<=2.4.27", - "jsdecena/laracom": "<2.0.9", - "jsmitty12/phpwhois": "<5.1", - "juzaweb/cms": "<=3.4.2", - "jweiland/events2": "<8.3.8|>=9,<9.0.6", - "jweiland/kk-downloader": "<1.2.2", - "kantorge/yaffa": "<=2", - "kazist/phpwhois": "<=4.2.6", - "kelvinmo/simplejwt": "<=1.1", - "kelvinmo/simplexrd": "<3.1.1", - "kevinpapst/kimai2": "<1.16.7", - "khodakhah/nodcms": "<=3.4.1", - "kimai/kimai": "<=2.57", - "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", - "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<=1.7", - "kohana/core": "<3.3.3", - "koillection/koillection": "<1.6.12", - "krayin/laravel-crm": "<=2.2", - "kreait/firebase-php": ">=3.2,<3.8.1", - "kumbiaphp/kumbiapp": "<=1.1.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laktak/hjson": "<2.3", - "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", - "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", - "laminas/laminas-http": "<2.14.2", - "lara-zeus/artemis": ">=1,<=1.0.6", - "lara-zeus/dynamic-dashboard": ">=3,<=3.0.1", - "laravel/fortify": "<1.11.1", - "laravel/framework": "<12.61.1|>=13,<13.12", - "laravel/laravel": ">=5.4,<5.4.22", - "laravel/passport": ">=13,<13.7.1", - "laravel/pulse": "<1.3.1", - "laravel/reverb": "<1.7", - "laravel/socialite": ">=1,<2.0.10", - "latte/latte": "<2.10.8", - "lavalite/cms": "<=10.1", - "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", - "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", - "league/commonmark": "<=2.8.1", - "league/flysystem": "<1.1.4|>=2,<2.1.1", - "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", - "leantime/leantime": "<3.3", - "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "libreform/libreform": ">=2,<=2.0.8", - "librenms/librenms": "<26.3", - "liftkit/database": "<2.13.2", - "lightsaml/lightsaml": "<1.3.5", - "limesurvey/limesurvey": "<6.15.4", - "livehelperchat/livehelperchat": "<=3.91", - "livewire-filemanager/filemanager": "<=1.0.4", - "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4", - "livewire/volt": "<1.7", - "lms/routes": "<2.1.1", - "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", - "lomkit/laravel-rest-api": "<2.13", - "luracast/restler": "<3.1", - "luyadev/yii-helpers": "<1.2.1", - "macropay-solutions/laravel-crud-wizard-free": "<3.4.17", - "maestroerror/php-heic-to-jpg": "<1.0.5", - "magento/community-edition": "<2.4.6.0-patch13|>=2.4.7.0-beta1,<2.4.7.0-patch8|>=2.4.8.0-beta1,<2.4.8.0-patch3|>=2.4.9.0-alpha1,<2.4.9.0-alpha3|==2.4.9", - "magento/core": "<=1.9.4.5", - "magento/magento1ce": "<1.9.4.3-dev", - "magento/magento1ee": ">=1,<1.14.4.3-dev", - "magento/product-community-edition": "<2.4.4.0-patch9|>=2.4.5,<2.4.5.0-patch8|>=2.4.6,<2.4.6.0-patch6|>=2.4.7,<2.4.7.0-patch1", - "magento/project-community-edition": "<=2.0.2", - "magneto/core": "<1.9.4.4-dev", - "mahocommerce/maho": "<25.9", - "maikuolan/phpmussel": ">=1,<1.6", - "mainwp/mainwp": "<=4.4.3.3", - "manogi/nova-tiptap": "<=3.2.6", - "mantisbt/mantisbt": "<2.28.2", - "marcwillmann/turn": "<0.3.3", - "markhuot/craftql": "<=1.3.7", - "marshmallow/nova-tiptap": "<5.7", - "matomo/matomo": "<1.11", - "matyhtf/framework": "<3.0.6", - "mautic/core": "<5.2.11|>=6,<6.0.9|>=7,<7.1.2", - "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", - "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", - "maximebf/debugbar": "<1.19", - "mckenziearts/livewire-markdown-editor": "<1.3", - "mdanter/ecc": "<2", - "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", - "mediawiki/cargo": "<3.8.3", - "mediawiki/core": "<1.39.5|==1.40", - "mediawiki/data-transfer": ">=1.39,<1.39.11|>=1.41,<1.41.3|>=1.42,<1.42.2", - "mediawiki/maps": "<12.1.3", - "mediawiki/matomo": "<2.4.3", - "mediawiki/semantic-media-wiki": "<4.0.2", - "mehrwert/phpmyadmin": "<3.2", - "melisplatform/melis-asset-manager": "<5.0.1", - "melisplatform/melis-cms": "<5.3.4", - "melisplatform/melis-cms-slider": "<5.3.1", - "melisplatform/melis-core": "<5.3.11", - "melisplatform/melis-front": "<5.0.1", - "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", - "mgallegos/laravel-jqgrid": "<=1.3", - "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", - "microsoft/microsoft-graph-beta": "<2.0.1", - "microsoft/microsoft-graph-core": "<2.0.2", - "microweber/microweber": "<2.0.20", - "mikehaertl/php-shellcommand": "<1.6.1", - "mineadmin/mineadmin": "<=3.0.9", - "miniorange/miniorange-saml": "<1.4.3", - "miraheze/ts-portal": "<=33", - "mittwald/typo3_forum": "<1.2.1", - "mix/mix": ">=2,<=2.2.17", - "mmc/ceselector": "<3.0.3|>=4,<4.0.2|>=5,<5.0.1|>=6,<6.0.1", - "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<=3.1", - "mojo42/jirafeau": "<4.4", - "mongodb/mongodb": ">=1,<1.9.2", - "mongodb/mongodb-extension": "<1.21.2", - "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.5.9|>=5.0.0.0-beta,<5.0.5|>=5.1.0.0-beta,<5.1.2", - "moonshine/moonshine": "<=3.12.5", - "mos/cimage": "<0.7.19", - "movim/moxl": ">=0.8,<=0.10", - "movingbytes/social-network": "<=1.2.1", - "mpdf/mpdf": "<=7.1.7", - "mtdowling/jmespath.php": "<2.9.1", - "munkireport/comment": "<4", - "munkireport/managedinstalls": "<2.6", - "munkireport/munki_facts": "<1.5", - "munkireport/reportdata": "<3.5", - "munkireport/softwareupdate": "<1.6", - "mustache/mustache": ">=2,<2.14.1", - "mwdelaney/wp-enable-svg": "<=0.2", - "nabeel/phpvms": "<7.0.6", - "namshi/jose": "<2.2", - "nasirkhan/laravel-starter": "<11.11", - "nategood/httpful": "<1", - "neoan3-apps/template": "<1.1.1", - "neorazorx/facturascripts": "<2022.04", - "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", - "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", - "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", - "neos/swiftmailer": "<5.4.5", - "nesbot/carbon": "<2.72.6|>=3,<3.8.4", - "netcarver/textile": "<=4.1.2", - "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", - "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", - "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "neuron-core/neuron-ai": "<=2.8.11", - "nilsteampassnet/teampass": "<3.1.3.1-dev", - "nitsan/ns-backup": "<13.0.1", - "nonfiction/nterchange": "<4.1.1", - "notrinos/notrinos-erp": "<=0.7", - "noumo/easyii": "<=0.9", - "novaksolutions/infusionsoft-php-sdk": "<1", - "novosga/novosga": "<=2.2.12", - "nukeviet/nukeviet": "<4.5.02", - "nyholm/psr7": "<1.6.1", - "nystudio107/craft-seomatic": "<3.4.12", - "nzedb/nzedb": "<0.8", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": "<1.1.2", - "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", - "october/october": "<3.7.14|>=4,<4.1.10", - "october/rain": "<=3.7.13|>=4,<=4.1.9", - "october/system": "<3.7.16|>=4,<4.1.16", - "oliverklee/phpunit": "<3.5.15", - "omeka/omeka-s": "<4.0.3", - "onelogin/php-saml": "<2.21.1|>=3,<3.8.1|>=4,<4.3.1", - "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", - "open-web-analytics/open-web-analytics": "<1.8.1", - "opencart/opencart": ">=0", - "openid/php-openid": "<2.3", - "openmage/magento-lts": "<=20.17", - "opensolutions/vimbadmin": "<=3.0.15", - "opensource-workshop/connect-cms": "<1.41.1|>=2,<2.41.1", - "orchid/platform": ">=8,<14.43", - "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", - "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", - "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", - "oro/crm-call-bundle": ">=4.2,<=4.2.5|>=5,<5.0.4|>=5.1,<5.1.1", - "oro/customer-portal": ">=4.1,<=4.1.13|>=4.2,<=4.2.10|>=5,<=5.0.11|>=5.1,<=5.1.3", - "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<=4.2.10|>=5,<=5.0.12|>=5.1,<=5.1.3", - "oveleon/contao-cookiebar": "<1.16.3|>=2,<2.1.3", - "oxid-esales/oxideshop-ce": "<=7.0.5", - "oxid-esales/paymorrow-module": ">=1,<1.0.2|>=2,<2.0.1", - "packbackbooks/lti-1-3-php-library": "<5", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": "<3", - "pagekit/pagekit": "<=1.0.18", - "paragonie/ecc": "<2.0.1", - "paragonie/random_compat": "<2", - "paragonie/sodium_compat": "<1.24|>=2,<2.5", - "passbolt/passbolt_api": "<4.6.2", - "paymenter/paymenter": "<=1.5.4", - "paypal/adaptivepayments-sdk-php": "<=3.9.2", - "paypal/invoice-sdk-php": "<=3.9", - "paypal/merchant-sdk-php": "<3.12", - "paypal/permissions-sdk-php": "<=3.9.1", - "pear/archive_tar": "<1.4.14", - "pear/auth": "<1.2.4", - "pear/crypt_gpg": "<1.6.7", - "pear/http_request2": "<2.7", - "pear/pear": "<=1.10.1", - "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", - "personnummer/personnummer": "<3.0.2", - "ph7software/ph7builder": "<=17.9.1", - "phanan/koel": "<=9.3.4", - "pheditor/pheditor": ">=2.0.1,<=2.0.3", - "phenx/php-svg-lib": "<0.5.2", - "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", - "php-mod/curl": "<2.3.2", - "php-standard-library/h2": ">=6.1,<6.1.2|>=6.2,<6.2.1", - "php-standard-library/php-standard-library": ">=6.1,<6.1.2|>=6.2,<6.2.1", - "phpbb/phpbb": "<3.3.16|==4.0.0.0-alpha1", - "phpems/phpems": ">=6,<=6.1.3", - "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", - "phpmailer/phpmailer": "<6.5", - "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<5.2.2", - "phpmyfaq/phpmyfaq": "<4.1.4", - "phpoffice/common": "<0.2.9", - "phpoffice/math": "<=0.2", - "phpoffice/phpexcel": "<=1.8.2", - "phpoffice/phpspreadsheet": "<=1.30.4|>=2,<=2.1.15|>=2.2,<=2.4.4|>=3,<=3.10.4|>=4,<=5.6", - "phppgadmin/phppgadmin": "<=7.13", - "phpseclib/phpseclib": "<=2.0.54|>=3,<=3.0.53", - "phpservermon/phpservermon": "<3.6", - "phpsysinfo/phpsysinfo": "<3.4.3", - "phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8|>=12.5.21,<12.5.22|>=13.1.5,<13.1.6", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "phpxmlrpc/phpxmlrpc": "<4.9.2", - "phraseanet/phraseanet": "==4.0.3", - "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<=2.3.5", - "pimcore/customer-management-framework-bundle": "<4.2.1", - "pimcore/data-hub": "<1.2.4", - "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", - "pimcore/demo": "<10.3", - "pimcore/ecommerce-framework-bundle": "<1.0.10", - "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<=12.3.8", - "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", - "piwik/piwik": "<1.11", - "pixelfed/pixelfed": "<0.12.5", - "plotly/plotly.js": "<2.25.2", - "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<5.42.1", - "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", - "pontedilana/php-weasyprint": "<=2.5.1", - "poweradmin/poweradmin": "<4.2.4|>=4.3,<4.3.3", - "pressbooks/pressbooks": "<5.18", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/blockreassurance": "<=5.1.3", - "prestashop/blockwishlist": ">=2,<2.1.1", - "prestashop/contactform": ">=1.0.1,<4.3", - "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.2.6|>=9,<9.1.1", - "prestashop/productcomments": "<5.0.2", - "prestashop/ps_checkout": "<5.3", - "prestashop/ps_contactinfo": "<=3.3.2", - "prestashop/ps_emailsubscription": "<2.6.1", - "prestashop/ps_facetedsearch": "<3.4.1", - "prestashop/ps_linklist": "<3.1", - "privatebin/privatebin": "<1.4|>=1.5,<1.7.4|>=1.7.7,<2.0.3", - "processwire/processwire": "<=3.0.255", - "propel/propel": ">=2.0.0.0-alpha1,<2.0.0.0-alpha8", - "propel/propel1": ">=1,<1.7.2", - "psy/psysh": "<=0.11.22|>=0.12,<=0.12.18", - "pterodactyl/panel": "<1.12.3", - "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", - "ptrofimov/beanstalk_console": "<1.7.14", - "pubnub/pubnub": "<6.1", - "punktde/pt_extbase": "<1.5.1", - "pusher/pusher-php-server": "<2.2.1", - "putyourlightson/craft-sprig": ">=2,<2.15.2|>=3,<3.7.2", - "pwweb/laravel-core": "<=0.3.6.0-beta", - "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", - "pyrocms/pyrocms": "<=3.9.1", - "qcubed/qcubed": "<=3.1.1", - "quickapps/cms": "<=2.0.0.0-beta2", - "rainlab/blog-plugin": "<1.4.1", - "rainlab/debugbar-plugin": "<3.1", - "rainlab/user-plugin": "<=1.4.5", - "ralffreit/mfa-email": "<1.0.7|==2", - "rankmath/seo-by-rank-math": "<=1.0.95", - "rap2hpoutre/laravel-log-viewer": "<0.13", - "react/http": ">=0.7,<1.9", - "really-simple-plugins/complianz-gdpr": "<6.4.2", - "redaxo/source": "<5.21", - "remdex/livehelperchat": "<4.29", - "renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1", - "reportico-web/reportico": "<=8.1", - "rhukster/dom-sanitizer": "<1.0.10", - "rmccue/requests": ">=1.6,<1.8", - "roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9", - "roadiz/openid": "<2.3.43|>=2.5,<2.5.45|>=2.6,<2.6.31|>=2.7,<2.7.18", - "robrichards/xmlseclibs": "<3.1.5", - "roots/soil": "<4.1", - "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11|>=1.7.0.0-beta,<1.7.0.0-RC5-dev", - "rudloff/alltube": "<3.0.3", - "rudloff/rtmpdump-bin": "<=2.3.1", - "s-cart/core": "<=9.0.5", - "s-cart/s-cart": "<6.9", - "s9y/serendipity": "<2.6", - "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", - "saloonphp/saloon": "<4", - "samwilson/unlinked-wikibase": "<1.42", - "scheb/two-factor-bundle": "<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "setasign/fpdi": "<2.6.7", - "sfroemken/url_redirect": "<=1.2.1", - "sheng/yiicms": "<1.2.1", - "shopper/cart": "<2.8", - "shopper/framework": "<2.8", - "shopware/core": "<6.6.10.18-dev|>=6.7,<6.7.10.1-dev", - "shopware/platform": "<6.6.10.18-dev|>=6.7,<6.7.10.1-dev", - "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=6.3.5.2|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", - "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", - "shopxo/shopxo": "<=6.4", - "showdoc/showdoc": "<3.8.1", - "shuchkin/simplexlsx": ">=1.0.12,<1.1.13", - "silverstripe-australia/advancedreports": ">=1,<=2", - "silverstripe/admin": "<1.13.19|>=2,<2.1.8", - "silverstripe/assets": "<2.4.5|>=3,<3.1.3", - "silverstripe/cms": "<6.2.1", - "silverstripe/comments": ">=1.3,<3.1.1", - "silverstripe/forum": "<0.6.2|>=0.7,<0.7.4", - "silverstripe/framework": "<6.2.2", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", - "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", - "silverstripe/recipe-cms": ">=4.5,<4.5.3", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/reports": "<5.2.3", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4|>=2.1,<2.1.2", - "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", - "silverstripe/subsites": ">=2,<2.6.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<6.4.9|>=7,<7.0.7|>=7.1,<7.1.1", - "silverstripe/versioned": "<3.2.1", - "silverstripe/versioned-admin": ">=1,<1.11.1", - "simogeo/filemanager": "<=2.5", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<=4.20.2|>=5,<5.0.6|>=6,<6.2.1", - "simplesamlphp/saml2-legacy": "<=4.20.2", - "simplesamlphp/simplesamlphp": "<=2.4.6|>=2.5,<=2.5.1", - "simplesamlphp/simplesamlphp-module-casserver": "<=7.0.2", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplesamlphp/simplesamlphp-module-openid": "<1", - "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", - "simplesamlphp/xml-common": "<1.20", - "simplesamlphp/xml-security": "<1.13.9|>=2,<2.3.1", - "simplito/elliptic-php": "<1.0.6", - "sitegeist/fluid-components": "<3.5", - "sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5", - "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", - "sjbr/static-info-tables": "<2.3.1", - "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", - "slim/slim": "<2.6|>=4.4,<=4.15.1", - "slub/slub-events": "<3.0.3", - "smarty/smarty": "<4.5.3|>=5,<5.1.1", - "snipe/snipe-it": "<=8.6.1", - "socalnick/scn-social-auth": "<1.15.2", - "socialiteproviders/steam": "<1.1", - "solidinvoice/solidinvoice": "<=2.3.15", - "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", - "soosyze/soosyze": "<=2", - "spatie/browsershot": "<5.0.5", - "spatie/image-optimizer": "<1.7.3", - "spatie/laravel-medialibrary": "<11.23", - "spatie/schema-org": ">=3.23.1,<3.23.2|>=4,<4.0.2", - "spencer14420/sp-php-email-handler": "<1", - "spipu/html2pdf": "<5.2.8", - "spiral/roadrunner": "<2025.1", - "spomky-labs/otphp": "<11.4.3", - "spoon/library": "<1.4.1", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<24.05.1", - "starcitizentools/citizen-skin": ">=1.9.4,<3.9", - "starcitizentools/short-description": ">=4,<4.0.1", - "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", - "starcitizenwiki/embedvideo": "<=4", - "statamic/cms": "<5.74|>=6,<6.20.3", - "stormpath/sdk": "<9.9.99", - "studio-42/elfinder": "<=2.1.67", - "studiomitte/friendlycaptcha": "<0.1.4", - "subhh/libconnect": "<7.0.8|>=8,<8.1", - "sukohi/surpass": "<1", - "sulu/form-bundle": ">=2,<2.5.3", - "sulu/sulu": "<=2.6.22|>=3,<=3.0.5", - "sumocoders/framework-user-bundle": "<1.4", - "superbig/craft-audit": "<3.0.2", - "svewap/a21glossary": "<=0.4.10", - "swag/paypal": "<5.4.4", - "swiftmailer/swiftmailer": "<6.2.5", - "swiftyedit/swiftyedit": "<1.2", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": "<1.10.1", - "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", - "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.9.12|>=1.10,<1.10.16|>=1.11,<1.11.17|>=1.12,<=1.12.22|>=1.13,<=1.13.14|>=1.14,<=1.14.17|>=2,<=2.0.15|>=2.1,<=2.1.11|>=2.2,<=2.2.2", - "symbiote/silverstripe-advancedworkflow": "<6.4.5|>=7,<7.1.3|>=7.2,<7.2.1", - "symbiote/silverstripe-multivaluefield": ">=3,<3.1", - "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", - "symbiote/silverstripe-seed": "<6.0.3", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfont/process": ">=0", - "symfony/cache": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/dom-crawler": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<5.3.15|>=5.4.3,<5.4.4|>=6.0.3,<6.0.4", - "symfony/html-sanitizer": ">=6.1,<6.4.41|>=7,<7.4.13|>=8,<8.0.13", - "symfony/http-client": ">=4.3,<5.4.53|>=6,<6.4.15|>=7,<7.1.8", - "symfony/http-foundation": "<5.4.50|>=6,<6.4.41|>=7,<7.4.13|>=8,<8.0.13", - "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6|>=7.4,<7.4.12|>=8,<8.0.12", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/json-path": ">=7.3,<7.4.12|>=8,<8.0.12", - "symfony/lox24-notifier": ">=7.1,<7.4.12|>=8,<8.0.12", - "symfony/mailer": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/mailjet-mailer": ">=6.4,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/mailomat-mailer": ">=7.2,<7.4.13|>=8,<8.0.13", - "symfony/mailtrap-mailer": ">=7.2,<7.4.12|>=8,<8.0.12", - "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", - "symfony/mime": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/monolog-bridge": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10|>=1.17.1,<1.38.1", - "symfony/polyfill-intl-idn": ">=1.17.1,<1.38.1", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/process": "<5.4.51|>=6,<6.4.33|>=7,<7.1.7|>=7.3,<7.3.11|>=7.4,<7.4.5|>=8,<8.0.5", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": "<5.4.53|>=6,<6.4.41|>=7,<7.4.13|>=8,<8.0.13", - "symfony/runtime": ">=5.3,<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", - "symfony/security-bundle": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.4.10|>=7,<7.0.10|>=7.1,<7.1.3", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", - "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", - "symfony/security-http": "<5.4.53|>=6,<6.4.41|>=7,<7.4.13|>=8,<8.0.13", - "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": "<5.4.53|>=6,<6.4.41|>=7,<7.4.13|>=8,<8.0.13", - "symfony/translation": ">=2,<2.0.17", - "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8|>=6.4.24,<6.4.40", - "symfony/twilio-notifier": ">=6.4,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symfony/ux-autocomplete": "<2.36|>=3,<3.1", - "symfony/ux-icons": ">=2.17,<2.36.1|>=3,<3.2", - "symfony/ux-live-component": "<2.36|>=3,<3.1", - "symfony/ux-toolkit": ">=2.32,<2.36.1|>=3,<3.2", - "symfony/ux-twig-component": "<2.25.1", - "symfony/validator": "<5.4.43|>=6,<6.4.11|>=7,<7.1.4", - "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4|>=7.2.9,<7.4.12|>=8,<8.0.12", - "symfony/webhook": ">=6.3,<6.3.8", - "symfony/yaml": "<5.4.52|>=6,<6.4.40|>=7,<7.4.12|>=8,<8.0.12", - "symphonycms/symphony-2": "<2.6.4", - "t3/dce": "<0.11.5|>=2.2,<2.6.2", - "t3g/svg-sanitizer": "<1.0.3", - "t3s/content-consent": "<1.0.3|>=2,<2.0.2", - "tastyigniter/tastyigniter": "<4", - "tcg/voyager": "<=1.8", - "tecnickcom/tc-lib-pdf-font": "<2.6.4", - "tecnickcom/tcpdf": "<6.8", - "terminal42/contao-tablelookupwizard": "<3.3.5", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.3", - "theonedemon/phpwhois": "<=4.2.5", - "thinkcmf/thinkcmf": "<6.0.8", - "thorsten/phpmyfaq": "<4.1.4", - "tikiwiki/tiki-manager": "<=17.1", - "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", - "tinymce/tinymce": "<7.9.3|>=8,<8.5.1", - "tinymighty/wiki-seo": "<1.2.2", - "titon/framework": "<9.9.99", - "tltneon/lgsl": "<7", - "tobiasbg/tablepress": "<=2.0.0.0-RC1", - "tomasnorre/crawler": "<11.0.13|>=12,<12.0.11", - "topthink/framework": "<6.0.17|>=6.1,<=8.0.4", - "topthink/think": "<=6.1.1", - "topthink/thinkphp": "<=3.2.3|>=6.1.3,<=8.0.4", - "torrentpier/torrentpier": "<=2.8.8", - "tpwd/ke_search": "<5.6.2|>=6,<6.6.1|>=7,<7.0.1", - "tribalsystems/zenario": "<=9.7.61188", - "truckersmp/phpwhois": "<=4.3.1", - "ttskch/pagination-service-provider": "<1", - "twbs/bootstrap": "<3.4.1|>=4,<4.3.1", - "twig/cssinliner-extra": "<3.26", - "twig/intl-extra": "<3.26", - "twig/markdown-extra": "<3.26", - "twig/twig": "<3.27", - "typicms/core": "<16.1.7", - "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-core": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-dashboard": ">=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", - "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-felogin": ">=4.2,<4.2.3", - "typo3/cms-filelist": ">=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", - "typo3/cms-form": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", - "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", - "typo3/cms-lowlevel": ">=11,<=11.5.41", - "typo3/cms-recordlist": ">=11,<11.5.48", - "typo3/cms-recycler": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", - "typo3/cms-redirects": ">=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", - "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", - "typo3/cms-scheduler": ">=11,<=11.5.41", - "typo3/cms-setup": ">=9,<=9.5.50|>=10,<=10.4.49|>=11,<=11.5.43|>=12,<=12.4.30|>=13,<=13.4.11", - "typo3/cms-webhooks": ">=12,<=12.4.30|>=13,<=13.4.11", - "typo3/cms-workspaces": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": "<2.3.2", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", - "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", - "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", - "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", - "ua-parser/uap-php": "<3.8", - "uasoft-indonesia/badaso": "<=2.9.7", - "unisharp/laravel-filemanager": "<2.9.1", - "universal-omega/dynamic-page-list3": "<3.6.4", - "unopim/unopim": "<=0.3", - "userfrosting/userfrosting": ">=0.3.1,<4.6.3", - "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "uvdesk/community-skeleton": "<=1.1.1", - "uvdesk/core-framework": "<=1.1.1", - "vanilla/safecurl": "<0.9.2", - "verbb/comments": "<1.5.5", - "verbb/formie": "<3.1.27", - "verbb/image-resizer": "<2.0.9", - "verbb/knock-knock": "<1.2.8", - "verot/class.upload.php": "<=2.1.6", - "vertexvaar/falsftp": "<0.2.6", - "villagedefrance/opencart-overclocked": "<=1.11.1", - "vova07/yii2-fileapi-widget": "<0.1.9", - "vrana/adminer": "<5.4.2", - "vufind/vufind": ">=2,<9.1.1", - "waldhacker/hcaptcha": "<2.1.2", - "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<2.6.11", - "wanglelecc/laracms": "<=1.0.3", - "wapplersystems/a21glossary": "<=0.4.10", - "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9|>=5.2,<5.2.4|>=5.3,<5.3.1", - "web-auth/webauthn-lib": ">=4.5,<5.3.5", - "web-auth/webauthn-symfony-bundle": "<5.3.4", - "web-feet/coastercms": "==5.5", - "web-token/jwt-bundle": "<3.4.10|>=4,<4.0.7|>=4.1,<4.1.7", - "web-token/jwt-experimental": "<4.1.7", - "web-token/jwt-framework": "<4.1.7", - "web-token/jwt-library": "<3.4.10|>=4,<4.0.7|>=4.1,<4.1.7", - "web-tp3/wec_map": "<3.0.3", - "webbuilders-group/silverstripe-kapost-bridge": "<0.4", - "webcoast/deferred-image-processing": "<1.0.2", - "webklex/laravel-imap": "<5.3", - "webklex/php-imap": "<5.3", - "webonyx/graphql-php": "<=15.32.2", - "webpa/webpa": "<3.1.2", - "webreinvent/vaahcms": "<=2.3.1", - "wikibase/wikibase": "<=1.39.3", - "wikimedia/parsoid": "<0.12.2", - "willdurand/js-translation-bundle": "<2.1.1", - "winter/wn-backend-module": "<1.2.12", - "winter/wn-cms-module": "<=1.2.9", - "winter/wn-dusk-plugin": "<2.1", - "winter/wn-system-module": "<1.2.4", - "wintercms/winter": "<=1.2.3", - "wireui/wireui": "<1.19.3|>=2,<2.1.3", - "woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3", - "wp-cli/wp-cli": ">=0.12,<2.5", - "wp-graphql/wp-graphql": "<=1.14.5", - "wp-premium/gravityforms": "<2.4.21", - "wpanel/wpanel4-cms": "<=4.3.1", - "wpcloud/wp-stateless": "<3.2", - "wpglobus/wpglobus": "<=1.9.6", - "wpmetabox/meta-box": "<5.11.2", - "wwbn/avideo": "<=29", - "xataface/xataface": "<3", - "xpressengine/xpressengine": "<3.0.15", - "yab/quarx": "<2.4.5", - "yansongda/pay": "<=3.7.19", - "yeswiki/yeswiki": "<4.6.4", - "yetiforce/yetiforce-crm": "<6.5", - "yidashi/yii2cmf": "<=2", - "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": "<1.1.31", - "yiisoft/yii2": "<2.0.55", - "yiisoft/yii2-authclient": "<2.2.15", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<=2.0.45", - "yiisoft/yii2-elasticsearch": "<2.0.5", - "yiisoft/yii2-gii": "<=2.2.4", - "yiisoft/yii2-jui": "<2.0.4", - "yiisoft/yii2-redis": "<2.0.20", - "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", - "yoast-seo-for-typo3/yoast_seo": "<7.2.3", - "yoast/duplicate-post": "<=4.5", - "yourls/yourls": "<=1.10.2", - "yuan1994/tpadmin": "<=1.3.12", - "yungifez/skuul": "<=2.6.5", - "z-push/z-push-dev": "<2.7.6", - "zencart/zencart": "<=1.5.7.0-beta", - "zendesk/zendesk_api_client_php": "<2.2.11", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": "<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", - "zendframework/zend-diactoros": "<1.8.4", - "zendframework/zend-feed": "<2.10.3", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": "<2.8.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": "<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<=3", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": "<2.0.2", - "zendframework/zendrest": "<2.0.2", - "zendframework/zendservice-amazon": "<2.0.3", - "zendframework/zendservice-api": "<1", - "zendframework/zendservice-audioscrobbler": "<2.0.2", - "zendframework/zendservice-nirvanix": "<2.0.2", - "zendframework/zendservice-slideshare": "<2.0.2", - "zendframework/zendservice-technorati": "<2.0.2", - "zendframework/zendservice-windowsazure": "<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zenstruck/collection": "<0.2.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2", - "zoujingli/thinkadmin": "<=6.1.53", - "zumba/json-serializer": "<3.2.3" - }, - "default-branch": true, - "type": "metapackage", + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - }, - { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" + "name": "Christian Lück", + "email": "christian@clue.engineering" } ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", "keywords": [ - "dev" + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" ], "support": { - "issues": "https://github.com/Roave/SecurityAdvisories/issues", - "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" }, "funding": [ { - "url": "https://github.com/Ocramius", - "type": "github" + "url": "https://clue.engineering/support", + "type": "custom" }, { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", - "type": "tidelift" + "url": "https://github.com/clue", + "type": "github" } ], - "time": "2026-07-08T22:04:46+00:00" + "time": "2022-12-23T10:58:28+00:00" + }, + { + "name": "composer/pcre", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<2.2.2" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.4.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2026-06-07T11:47:49+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-08-20T19:15:30+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "ergebnis/agent-detector", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/agent-detector.git", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271", + "shasum": "" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.51.0", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.60.2", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.18.1", + "fakerphp/faker": "^1.24.1", + "infection/infection": "^0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.54", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.10", + "phpunit/phpunit": "^9.6.34", + "rector/rector": "^2.4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\AgentDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a detector for detecting the presence of an agent.", + "homepage": "https://github.com/ergebnis/agent-detector", + "support": { + "issues": "https://github.com/ergebnis/agent-detector/issues", + "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/agent-detector" + }, + "time": "2026-05-07T08:19:07+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2025-08-14T07:29:31+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.95.12", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "b1b9055997a98dce3c2338e884626e718a25a923" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b1b9055997a98dce3c2338e884626e718a25a923", + "reference": "b1b9055997a98dce3c2338e884626e718a25a923", + "shasum": "" + }, + "require": { + "clue/ndjson-react": "^1.3", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.5", + "ergebnis/agent-detector": "^1.2", + "ext-filter": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.3", + "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0 || ^9.0", + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.37", + "symfony/polyfill-php80": "^1.37", + "symfony/polyfill-php81": "^1.37", + "symfony/polyfill-php84": "^1.37", + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" + }, + "require-dev": { + "facile-it/paraunit": "^1.3.1 || ^2.11.0", + "infection/infection": "^0.32.7", + "justinrainbow/json-schema": "^6.10.0", + "keradus/cli-executor": "^2.3", + "mikey179/vfsstream": "^1.6.12", + "php-coveralls/php-coveralls": "^2.9.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8", + "phpunit/phpunit": "^9.6.35 || ^10.5.64 || ^11.5.56", + "symfony/polyfill-php85": "^1.38", + "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.0", + "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "exclude-from-classmap": [ + "src/**/Internal/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.12" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2026-07-07T13:29:36+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.2.5", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "reference": "909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-07-05T06:31:06+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.7", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/socket": "^1.16", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.7" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-12-23T15:25:20+00:00" + }, + { + "name": "react/dns", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.14.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-18T19:34:28+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-17T20:46:25+00:00" + }, + { + "name": "react/promise", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.12.28 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-08-19T18:57:03+00:00" + }, + { + "name": "react/socket", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.17.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-19T20:47:34+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "a3fb6a298a265ff487a91bbea46e03cd01dbb226" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a3fb6a298a265ff487a91bbea46e03cd01dbb226", + "reference": "a3fb6a298a265ff487a91bbea46e03cd01dbb226", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.2", + "symfony/process": "^7.4.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/9.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/diff", + "type": "tidelift" + } + ], + "time": "2026-06-05T03:04:51+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v8.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abd6c11dc468725d1627302ad10f6cd486e9e3d0", + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/security-http": "<7.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-09T12:28:30+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:23:12+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/99aec13b82b4967ec5088222c4a3ecca955949c2", + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/finder", + "version": "v8.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/e2989e762c70f9490fa3a00a0ac0fae5aa97a531", + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531", + "shasum": "" + }, + "require": { + "php": ">=8.4.1" + }, + "require-dev": { + "symfony/filesystem": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v8.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-27T09:05:56+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "88f9c561f678a02d54b897014049fa839e33ff82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/88f9c561f678a02d54b897014049fa839e33ff82", + "reference": "88f9c561f678a02d54b897014049fa839e33ff82", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-10T16:19:22+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T12:45:58+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "21c07b026905d596e8379caeb115d87aa479499d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/21c07b026905d596e8379caeb115d87aa479499d", + "reference": "21c07b026905d596e8379caeb115d87aa479499d", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": { - "crazywhalecc/static-php-cli": 20, - "roave/security-advisories": 20 + "crazywhalecc/static-php-cli": 20 }, "prefer-stable": true, "prefer-lowest": false, diff --git a/config/templates/craft.yml.twig b/config/templates/craft.yml.twig index eecb8b2..3835301 100644 --- a/config/templates/craft.yml.twig +++ b/config/templates/craft.yml.twig @@ -3,9 +3,7 @@ {%- if arch == 'x86_64' and os == '10' %} {% set arch_flags = arch_flags ~ ' -march=x86-64-v3' -%} {%- endif -%} {%- if arch == 'x86_64' and os == '9' %} {% set arch_flags = arch_flags ~ ' -march=x86-64-v2' -%} {%- endif -%} {%- if arch == 'x86_64' and os != '10' and os != '9' -%} {%- set arch_flags = arch_flags ~ ' ' -%} {%- endif -%} -{%- set using_gcc = not target and php_version < '8.5' -%} -{%- if not using_gcc and not target and os == 8 %}{% set target = 'native-native-gnu.2.28' -%}{%- endif -%} -{%- if not using_gcc and not target and os == 9 %}{% set target = 'native-native-gnu.2.34' -%}{%- endif -%} +{%- set using_gcc = not target -%} {%- if not using_gcc and not target %}{% set target = 'native-native-gnu' -%}{% endif -%} {%- set target = target|replace({'native-native': arch ~ '-linux'}) -%} {%- set specs_cflags = '-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1' -%} @@ -14,6 +12,7 @@ '-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -momit-leaf-frame-pointer -ffunction-sections -fdata-sections' ~ arch_flags -%} {%- set cflags = (using_gcc ? '' : '-flto=thin ') ~ cflags -%} +{%- if arch == 'aarch64' and using_gcc %}{% set cflags = cflags ~ ' -mtls-size=12' -%}{% endif -%} {%- set is_rhel = os in ['7', '8', '9', '10'] and type == 'rpm' -%} {%- if using_gcc and is_rhel -%} {%- if os == '7' or os == '8' -%} @@ -28,7 +27,7 @@ {# extensions #} {%- set base_sapi_str = 'cli,cgi,fpm,embed,frankenphp' -%} {%- set base_extensions_str = 'calendar,ctype,curl,dom,exif,fileinfo,filter,iconv,libxml,mbregex,mbstring,opcache,openssl,password-argon2,pcntl,phar,posix,readline,session,simplexml,sockets,sodium,tokenizer,xml,xmlreader,xmlwriter,zlib' -%} -{%- set base_shared_str = 'amqp,apcu,ast,bcmath,brotli,bz2,clickhouse,dba,decimal,deepclone,dio,ds,ev,event,excimer,fastchart,fastjson,ffi,ftp,gd,gettext,gmp,grpc,igbinary,imagick,inotify,intl,ldap,lz4,maxminddb,memcache,memcached,mongodb,msgpack,mysqli,mysqlnd,mysqlnd_ed25519,mysqlnd_parsec,odbc,opentelemetry,parallel,pcov,pdo,pdo_mysql,pdo_odbc,pdo_pgsql,pdo_sqlite,pdo_sqlsrv,pgsql,protobuf,rar,redis,rdkafka,shmop,simdjson,snappy,soap,spx,sqlite3,sqlsrv,ssh2,swoole,swoole-hook-mysql,swoole-hook-pgsql,swoole-hook-sqlite,swoole-hook-odbc,sysvmsg,sysvsem,sysvshm,tidy,trader,uuid,uv,xdebug,xhprof,xlswriter,xsl,xz,yac,yaml,zip,zstd' -%} +{%- set base_shared_str = 'amqp,apcu,ast,bcmath,brotli,bz2,clickhouse,dba,decimal,deepclone,dio,ds,ev,event,excimer,fastchart,fastjson,ffi,ftp,gd,gearman,gettext,gmp,gmssl,grpc,igbinary,imagick,inotify,intl,ldap,lz4,maxminddb,memcache,memcached,mongodb,msgpack,mysqli,mysqlnd,mysqlnd_ed25519,mysqlnd_parsec,odbc,opentelemetry,parallel,pcov,pdo,pdo_mysql,pdo_odbc,pdo_pgsql,pdo_sqlite,pdo_sqlsrv,pgsql,protobuf,rar,redis,rdkafka,shmop,simdjson,snappy,soap,spx,sqlite3,sqlsrv,ssh2,swoole,swoole-hook-mysql,swoole-hook-pgsql,swoole-hook-sqlite,swoole-hook-odbc,sysvmsg,sysvsem,sysvshm,tidy,trader,uuid,uv,xdebug,xhprof,xlswriter,xsl,xz,yac,yaml,zip,zstd' -%} {%- set base_extensions = base_extensions_str|split(',')|map(v => v|trim) -%} {%- set base_shared = base_shared_str|split(',')|map(v => v|trim) -%} @@ -55,9 +54,6 @@ {%- if (os == '8' or type == 'deb') and not using_gcc -%} {%- set shared_ext = shared_ext|filter(v => v != 'excimer') -%} {%- endif -%} -{%- if php_version < '8.3' -%} -{%- set shared_ext = shared_ext|filter(v => v != 'fastjson' and v != 'fastchart') -%} -{%- endif -%} php-version: {{ php_version }} extensions: {{ extensions|join(',') }} @@ -67,7 +63,6 @@ sapi: {{ sapi_list|join(',') }} debug: false build-options: enable-zts: true - with-clean: false with-suggested-libs: true with-suggested-exts: true no-strip: false @@ -79,6 +74,9 @@ build-options: with-hardcoded-ini: [ ] # UPX pack the binary (default: false) with-upx-pack: false + # Maintainer-only: skip PHP buildconf/configure/make when libphp.a/.so already exist. + # Frankenphp + shared extensions still rebuild. Flip to true to iterate on frankenphp. + maintainer-skip-build: false download-options: prefer-pre-built: false @@ -92,27 +90,19 @@ craft-options: extra-env: {% if using_gcc -%} - SPC_TOOLCHAIN: 'SPC\toolchain\GccNativeToolchain' + SPC_TOOLCHAIN: 'StaticPHP\Toolchain\GccNativeToolchain' SPC_LIBC: '{{ type == 'apk' ? 'musl' : 'glibc' }}' SPC_MUSL_DYNAMIC: 'true' {% else -%} SPC_TARGET: '{{ target }}' - # An __attribute__((ifunc)) in LTO bitcode crashes zig 0.16's lld (LLVM 21) during - # thin-link symbol resolution — long-standing upstream bug (llvm-project #45833, - # #45694); zig then aborts with no output. Hide only the ifunc attribute from PHP's - # configure: ZEND_INTRIN_*_FUNC_PROTO falls back to FUNC_PTR dispatch, which still - # compiles the AVX2/SSE fast paths and still selects them at startup via - # __builtin_cpu_supports (resolved by spc's libclang_rt.cpu_model.a). SPC_EXTRA_PHP_VARS: 'php_cv_preserve_none=yes ax_cv_have_func_attribute_ifunc=no' - # zig cc without -O keeps Debug UB traps; bare-built minilua aborts on Lua's 2^32 double->int cast - SPC_COMPILER_EXTRA: '-fno-sanitize=undefined' {% endif -%} EXTENSION_DIR: "{{ moduledir }}" SPC_CMD_VAR_PHP_EMBED_TYPE: 'shared' SPC_MICRO_PATCHES: - SPC_DEFAULT_C_FLAGS: "{{ cflags }}" - SPC_DEFAULT_CXX_FLAGS: "{{ cflags }} -fasynchronous-unwind-tables" - SPC_DEFAULT_LD_FLAGS: "-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -Wl,-z,noexecstack -Wl,--gc-sections {{ using_gcc and is_rhel ? specs_ldflags : '' }}{{ not using_gcc ? ' -flto=thin' : '' }}" + SPC_DEFAULT_CFLAGS: "{{ cflags }}" + SPC_DEFAULT_CXXFLAGS: "{{ cflags }} -fasynchronous-unwind-tables" + SPC_DEFAULT_LDFLAGS: "-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -Wl,-z,noexecstack -Wl,--gc-sections {{ using_gcc and is_rhel ? specs_ldflags : '' }}{{ not using_gcc ? ' -flto=thin' : '' }}" SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS: "{{ cflags }} -g -fno-math-errno -fPIE{{ using_gcc ? '' : ' -flto'}}" SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS: "-Wl,--build-id=sha1 -pie -release {{ release_suffix }}{{ using_gcc ? '' : ' -flto'}}" SPC_CMD_PREFIX_PHP_CONFIGURE: "./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-cgi --disable-phpdbg --disable-debug --with-pic --enable-rtld-now --enable-re2c-cgoto --disable-rpath" diff --git a/docker-compose.yaml b/docker-compose.yaml index ffd0b66..77f32fa 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,6 +5,7 @@ x-build-defaults: &build-defaults - .:/build environment: HOME: /build/.docker-home + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" command: ["bash", "-c", "mkdir -p $$HOME && exec sleep infinity"] services: @@ -16,6 +17,7 @@ services: args: UID: "${UID:-1000}" GID: "${GID:-1000}" + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" container_name: packages-debian alpine: @@ -26,6 +28,7 @@ services: args: UID: "${UID:-1000}" GID: "${GID:-1000}" + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" container_name: packages-alpine rhel-8: @@ -37,6 +40,7 @@ services: ALMA_VERSION: "8" UID: "${UID:-1000}" GID: "${GID:-1000}" + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" container_name: packages-rhel-8 rhel-9: @@ -48,6 +52,7 @@ services: ALMA_VERSION: "9" UID: "${UID:-1000}" GID: "${GID:-1000}" + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" container_name: packages-rhel-9 rhel-10: @@ -59,4 +64,5 @@ services: ALMA_VERSION: "10" UID: "${UID:-1000}" GID: "${GID:-1000}" + GITHUB_TOKEN: "${GITHUB_TOKEN:-}" container_name: packages-rhel-10 diff --git a/spc.registry.yml b/spc.registry.yml new file mode 100644 index 0000000..4fd268f --- /dev/null +++ b/spc.registry.yml @@ -0,0 +1,4 @@ +name: packages +package: + psr-4: + staticphp\hook: src/hook diff --git a/src/Command/AllCommand.php b/src/Command/AllCommand.php index 80a81db..f02ca2e 100644 --- a/src/Command/AllCommand.php +++ b/src/Command/AllCommand.php @@ -20,7 +20,8 @@ protected function configure(): void parent::configure(); $this ->addOption('packages', null, InputOption::VALUE_REQUIRED, 'Specify which packages to build (comma-separated)') - ->addOption('iteration', null, InputOption::VALUE_REQUIRED, 'Specify iteration number to use for packages (overrides auto-detected)'); + ->addOption('iteration', null, InputOption::VALUE_REQUIRED, 'Specify iteration number to use for packages (overrides auto-detected)') + ->addOption('bump', null, InputOption::VALUE_NONE, 'Bump each package iteration to (latest published on the remote repo) + 1'); } protected function execute(InputInterface $input, OutputInterface $output): int @@ -28,9 +29,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $debug = $input->getOption('debug'); $packagesOpt = $input->getOption('packages'); $iteration = $input->getOption('iteration'); + $bump = (bool)$input->getOption('bump'); $debuginfo = $input->getOption('debuginfo'); $phpVersion = SPP_PHP_VERSION; // Get from constant + if ($bump && $iteration !== null && $iteration !== '') { + throw new \InvalidArgumentException('--bump and --iteration are mutually exclusive; pass only one.'); + } + // Process packages option $packages = null; if (is_string($packagesOpt) && $packagesOpt !== '') { @@ -57,7 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // All parameters now come from constants set by BaseCommand::initialize() - $packageResult = CreatePackages::run($packages, $iteration, $debuginfo); + $packageResult = CreatePackages::run($packages, $iteration, $debuginfo, $bump); if (!$packageResult) { $output->writeln("Package creation failed."); diff --git a/src/Command/BaseCommand.php b/src/Command/BaseCommand.php index 7f698e2..f018246 100644 --- a/src/Command/BaseCommand.php +++ b/src/Command/BaseCommand.php @@ -17,7 +17,7 @@ protected function configure(): void ->addOption('phpv', null, InputOption::VALUE_REQUIRED, 'Specify PHP version to build', '8.4') ->addOption('target', null, InputOption::VALUE_REQUIRED, 'Specify the target triple for Zig (e.g., x86_64-linux-gnu, aarch64-linux-gnu)') ->addOption('prefix', null, InputOption::VALUE_REQUIRED, 'Specify the package prefix (e.g., -zts, -zts8.5, -zts85)', '-zts') - ->addOption('type', null, InputOption::VALUE_REQUIRED, 'Specify package type: rpm (uses /usr/lib64), deb (uses /usr/lib), or apk (uses /usr/lib). Required.', null) + ->addOption('type', null, InputOption::VALUE_REQUIRED, 'Specify package type: rpm (uses /usr/lib64), deb (uses /usr/lib), or apk (uses /usr/lib). Auto-detected from --target (musl → apk) or /etc/os-release if omitted.', null) ->addOption('debuginfo', null, InputOption::VALUE_NONE, 'Create debuginfo packages for APK (RPM and DEB always create debuginfo)'); } @@ -29,9 +29,9 @@ protected function initialize(InputInterface $input, OutputInterface $output) $prefix = $input->getOption('prefix') ?? '-zts'; $type = $input->getOption('type'); - // Validate that --type is provided + // Auto-detect type if not provided if ($type === null) { - throw new InvalidArgumentException('The --type option is required. Specify: rpm, deb, or apk'); + $type = $this->detectType($target); } // Validate type value @@ -61,6 +61,36 @@ protected function initialize(InputInterface $input, OutputInterface $output) $this->createDirectories(); } + private function detectType(?string $target): string + { + if ($target !== null && str_contains($target, 'musl')) { + return 'apk'; + } + + $osRelease = @parse_ini_file('/etc/os-release'); + if ($osRelease === false) { + throw new InvalidArgumentException('Could not auto-detect package type: /etc/os-release missing. Specify --type=rpm|deb|apk.'); + } + + $id = strtolower($osRelease['ID'] ?? ''); + $idLike = strtolower($osRelease['ID_LIKE'] ?? ''); + $ids = array_filter(array_merge([$id], preg_split('/\s+/', $idLike))); + + foreach ($ids as $candidate) { + if ($candidate === 'alpine') { + return 'apk'; + } + if (in_array($candidate, ['rhel', 'fedora', 'centos', 'almalinux', 'rocky'], true)) { + return 'rpm'; + } + if (in_array($candidate, ['debian', 'ubuntu'], true)) { + return 'deb'; + } + } + + throw new InvalidArgumentException('Could not auto-detect package type from /etc/os-release (ID=' . $id . '). Specify --type=rpm|deb|apk.'); + } + protected function createDirectories(): void { $paths = [BUILD_ROOT_PATH, BUILD_BIN_PATH, BUILD_LIB_PATH, BUILD_MODULES_PATH, DIST_PATH, DIST_RPM_PATH, DIST_DEB_PATH, DIST_APK_PATH]; diff --git a/src/Command/PackageCommand.php b/src/Command/PackageCommand.php index 431ac03..a7f9987 100644 --- a/src/Command/PackageCommand.php +++ b/src/Command/PackageCommand.php @@ -19,15 +19,21 @@ protected function configure(): void parent::configure(); $this ->addOption('packages', null, InputOption::VALUE_REQUIRED, 'Specify which packages to build (comma-separated)') - ->addOption('iteration', null, InputOption::VALUE_REQUIRED, 'Specify iteration number to use for packages (overrides auto-detected)'); + ->addOption('iteration', null, InputOption::VALUE_REQUIRED, 'Specify iteration number to use for packages (overrides auto-detected)') + ->addOption('bump', null, InputOption::VALUE_NONE, 'Bump each package iteration to (latest published on the remote repo) + 1'); } protected function execute(InputInterface $input, OutputInterface $output): int { $packageNames = $input->getOption('packages'); $iteration = $input->getOption('iteration'); + $bump = (bool)$input->getOption('bump'); $debuginfo = $input->getOption('debuginfo'); + if ($bump && $iteration !== null && $iteration !== '') { + throw new \InvalidArgumentException('--bump and --iteration are mutually exclusive; pass only one.'); + } + if ($packageNames) { $packageNames = explode(',', $packageNames); $output->writeln("Creating packages for: " . implode(', ', $packageNames) . "..."); @@ -36,7 +42,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // All parameters now come from constants set by BaseCommand::initialize() - $result = CreatePackages::run($packageNames, $iteration, $debuginfo); + $result = CreatePackages::run($packageNames, $iteration, $debuginfo, $bump); if ($result) { $output->writeln("Package creation completed successfully."); diff --git a/src/extension.php b/src/extension.php index 9009473..aeb0033 100644 --- a/src/extension.php +++ b/src/extension.php @@ -3,8 +3,8 @@ namespace staticphp; use Exception; -use SPC\store\Config; use staticphp\step\CreatePackages; +use staticphp\util\ExtMeta; use staticphp\util\TwigRenderer; class extension implements package @@ -24,12 +24,10 @@ private function determineExtensionPrefix(): string return ''; } - $config = Config::getExt($this->name); - if ($this->name === 'xdebug' || $this->name === 'ffi') { return '15-'; } - if ($config['zend-extension'] ?? false) { + if (ExtMeta::isZendExtension($this->name)) { return '10-'; } @@ -44,9 +42,7 @@ private function determineExtensionPrefix(): string public function getExtensionDependencies(string $extensionName, array $visited = []): array { - $config = Config::getExt($extensionName); - $keys = ['ext-depends', 'ext-suggests', 'ext-depends-unix', 'ext-suggests-unix', 'ext-depends-linux', 'ext-suggests-linux']; - if (!$config) { + if (ExtMeta::get($extensionName) === null) { return []; } @@ -54,15 +50,7 @@ public function getExtensionDependencies(string $extensionName, array $visited = $visited[] = $extensionName; $craftConfig = CraftConfig::getInstance(); - $dependencies = []; - foreach ($keys as $key) { - if (isset($config[$key])) { - foreach ($config[$key] as $item) { - $dependencies[] = $item; - } - } - } - foreach ($dependencies as $dependency) { + foreach (ExtMeta::extDependencies($extensionName) as $dependency) { if (!in_array($dependency, $craftConfig->getSharedExtensions()) || in_array($dependency, $craftConfig->getStaticExtensions())) { continue; } @@ -71,20 +59,10 @@ public function getExtensionDependencies(string $extensionName, array $visited = continue; } - $depConfig = Config::getExt($dependency); - $hasDependencies = false; - foreach ($keys as $key) { - if (!empty($depConfig[$key])) { - $hasDependencies = true; - break; - } - } - - if ($hasDependencies) { + if (ExtMeta::extDependencies($dependency) !== []) { $transitiveDeps = $this->getExtensionDependencies($dependency, $visited); foreach ($transitiveDeps as $transitiveDep) { - $craftConfig = CraftConfig::getInstance(); if (!in_array($transitiveDep, $craftConfig->getSharedExtensions()) || in_array($transitiveDep, $craftConfig->getStaticExtensions())) { continue; } @@ -102,8 +80,7 @@ public function getExtensionDependencies(string $extensionName, array $visited = public function getFpmConfig(): array { - $config = Config::getExt($this->name); - if (!$config) { + if (ExtMeta::get($this->name) === null) { throw new Exception("Extension configuration for '{$this->name}' not found."); } $prefix = CreatePackages::getPrefix(); @@ -111,39 +88,25 @@ public function getFpmConfig(): array $seen = []; $ordered = []; - $keys = ['ext-depends', 'ext-suggests', 'ext-depends-unix', 'ext-suggests-unix', 'ext-depends-linux', 'ext-suggests-linux']; - - /** - * Add a package and recursively include its ext-depends. - * - * @param string $name - * @param callable $loadConfig function(string $name): ?array - */ - $collect = function (string $name) use (&$collect, &$ordered, &$seen, $prefix, $keys): void { + $collect = function (string $name) use (&$collect, &$ordered, &$seen, $prefix): void { if (isset($seen[$name])) { return; } $seen[$name] = true; - $cfg = Config::getExt($name); - if ($cfg['type'] !== 'addon') { - $ordered[] = $prefix . '-' . $name; - } - if (!is_array($cfg)) { + if (ExtMeta::get($name) === null) { return; } - - foreach ($keys as $key) { - foreach ($cfg[$key] ?? [] as $dep) { - $collect($dep); - } + if (!ExtMeta::isAddon($name)) { + $ordered[] = $prefix . '-' . $name; } - }; - - foreach ($keys as $key) { - foreach (($config[$key] ?? []) as $dep) { + foreach (ExtMeta::extDependencies($name) as $dep) { $collect($dep); } + }; + + foreach (ExtMeta::extDependencies($this->name) as $dep) { + $collect($dep); } $depends = array_merge($depends, $ordered); diff --git a/src/hook/CleanupSources.php b/src/hook/CleanupSources.php new file mode 100644 index 0000000..b1afacc --- /dev/null +++ b/src/hook/CleanupSources.php @@ -0,0 +1,76 @@ +cleanupExtension($package); + return; + } + if ($package instanceof LibraryPackage) { + $this->cleanupLibrary($package); + } + } + + private function cleanupLibrary(LibraryPackage $package): void + { + $source = $package->getSourceDir(); + if (is_dir($source)) { + echo "Cleaning up source directory for library: {$package->getName()}\n"; + FileSystem::removeDir($source); + } + } + + private function cleanupExtension(PhpExtensionPackage $package): void + { + try { + $source = $package->getSourceDir(); + } catch (\Throwable) { + return; + } + if (!is_dir($source)) { + return; + } + echo "Cleaning up source directory for shared extension: {$package->getExtensionName()} (preserving license files)\n"; + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::CHILD_FIRST, + ); + foreach ($iterator as $fileInfo) { + $filename = $fileInfo->getFilename(); + $path = $fileInfo->getPathname(); + // Preserve COPYING/LICENSE/LICENCE/README/NOTICE/AUTHORS/CREDITS/PATENTS/CONTRIBUTORS files + if (preg_match('/^(COPYING|LICENSE|LICENCE|README|NOTICE|AUTHORS?|CREDITS?|PATENTS?|CONTRIBUTORS?)/i', $filename)) { + continue; + } + if ($fileInfo->isDir()) { + @rmdir($path); + } else { + @unlink($path); + } + } + } +} diff --git a/src/ini/extension/gearman.ini b/src/ini/extension/gearman.ini new file mode 100644 index 0000000..793fc83 --- /dev/null +++ b/src/ini/extension/gearman.ini @@ -0,0 +1,2 @@ +[gearman] +{{ is_shared ? '' : ';' }}extension=gearman{{ shared_library_suffix }} diff --git a/src/package/frankenphp.php b/src/package/frankenphp.php index a5f29f8..6b3ecce 100644 --- a/src/package/frankenphp.php +++ b/src/package/frankenphp.php @@ -62,7 +62,7 @@ private function getVersionedConflicts(): array /** * Create FrankenPHP packages (both RPM and DEB) */ - public function createPackages(string $packageType, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false): void + public function createPackages(string $packageType, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false, bool $bump = false): void { echo "Creating FrankenPHP package\n"; @@ -71,20 +71,36 @@ public function createPackages(string $packageType, array $binaryDependencies, ? $this->prepareFrankenPhpRepository(); if ($packageType === 'rpm') { - $this->createRpmPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo); + $this->createRpmPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo, $bump); } if ($packageType === 'deb') { - $this->createDebPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo); + $this->createDebPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo, $bump); } if ($packageType === 'apk') { - $this->createApkPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo); + $this->createApkPackage($architecture, $binaryDependencies, $iterationOverride, $debuginfo, $bump); } } + /** + * Resolve iteration for a FrankenPHP package: --iteration override wins, then --bump + * (remote query, shared with CreatePackages), then FrankenPHP's own local globber + * (which uses a distinct filename layout). + */ + private function resolveIteration(string $name, string $version, string $architecture, string $packageType, ?string $iterationOverride, bool $bump): string + { + if ($iterationOverride !== null) { + return $iterationOverride; + } + if ($bump) { + return (string)\staticphp\step\CreatePackages::getRemoteNextIteration($name, $version, $architecture, $packageType); + } + return (string)$this->getNextIteration($name, $version, $architecture, $packageType); + } + /** * Create RPM package for FrankenPHP */ - public function createRpmPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false): void + public function createRpmPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false, bool $bump = false): void { echo "Creating RPM package for FrankenPHP...\n"; @@ -112,8 +128,7 @@ public function createRpmPackage(string $architecture, array $binaryDependencies $name = $this->getName(); // Calculate iteration for RPM (with possible override) - $computed = (string)$this->getNextIteration($name, $rpmVersion, $architecture, 'rpm'); - $iteration = $iterationOverride ?? $computed; + $iteration = $this->resolveIteration($name, $rpmVersion, $architecture, 'rpm', $iterationOverride, $bump); $versionedConflicts = $this->getVersionedConflicts(); @@ -227,7 +242,7 @@ public function createRpmPackage(string $architecture, array $binaryDependencies /** * Create DEB package for FrankenPHP */ - public function createDebPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false): void + public function createDebPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false, bool $bump = false): void { echo "Creating DEB package for FrankenPHP...\n"; @@ -264,8 +279,7 @@ public function createDebPackage(string $architecture, array $binaryDependencies $debVersion = $version . '+php' . $phpVersionSuffix; // Calculate iteration for DEB (with possible override) - $computed = (string)$this->getNextIteration($name, $debVersion, $debArch, 'deb'); - $iteration = $iterationOverride ?? $computed; + $iteration = $this->resolveIteration($name, $debVersion, $debArch, 'deb', $iterationOverride, $bump); $debIteration = $iteration; $versionedConflicts = $this->getVersionedConflicts(); @@ -407,7 +421,7 @@ public function createDebPackage(string $architecture, array $binaryDependencies /** * Create APK package for FrankenPHP */ - public function createApkPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false): void + public function createApkPackage(string $architecture, array $binaryDependencies, ?string $iterationOverride = null, bool $debuginfo = false, bool $bump = false): void { echo "Creating APK package for FrankenPHP using nfpm...\n"; @@ -437,8 +451,7 @@ public function createApkPackage(string $architecture, array $binaryDependencies $apkVersion = $version . 'p' . $phpVersionSuffix; // Calculate iteration for APK (with possible override) - $computed = (string)$this->getNextIteration($name, $apkVersion, $architecture, 'apk'); - $iteration = $iterationOverride ?? $computed; + $iteration = $this->resolveIteration($name, $apkVersion, $architecture, 'apk', $iterationOverride, $bump); $versionedConflicts = $this->getVersionedConflicts(); diff --git a/src/package/pie.php b/src/package/pie.php index b729315..08ec63a 100644 --- a/src/package/pie.php +++ b/src/package/pie.php @@ -3,8 +3,6 @@ namespace staticphp\package; use RuntimeException; -use SPC\store\CurlHook; -use SPC\store\Downloader; use staticphp\package; use staticphp\step\CreatePackages; use staticphp\util\TwigRenderer; @@ -138,29 +136,50 @@ private function prepareArtifacts(): array private function downloadLatestPiePhar(string $targetPath): void { - [$url, $filename] = Downloader::getLatestGithubRelease('pie', [ - 'repo' => 'php/pie', - 'match' => 'pie\.phar', - 'prefer-stable' => true, - ]); + // Resolve the asset URL for `pie.phar` from the latest stable GitHub release. + $headers = self::githubAuthHeaders(); + $body = default_shell()->executeCurl( + 'https://api.github.com/repos/php/pie/releases/latest', + headers: $headers, + ); + $data = json_decode((string) $body, true); + if (!is_array($data) || empty($data['assets']) || !is_array($data['assets'])) { + throw new RuntimeException('PIE: failed to fetch latest release metadata from GitHub.'); + } + $assetUrl = null; + foreach ($data['assets'] as $asset) { + if (isset($asset['name'], $asset['url']) && preg_match('/^pie\.phar$/', $asset['name'])) { + $assetUrl = $asset['url']; + break; + } + } + if ($assetUrl === null) { + throw new RuntimeException('PIE: no pie.phar asset found in latest release.'); + } - Downloader::downloadFile( - name: 'pie', - url: $url, - filename: $filename, - move_path: null, - download_as: SPC_DOWNLOAD_PACKAGE, - headers: ['Accept: application/octet-stream'], - hooks: [[CurlHook::class, 'setupGithubToken']] + // GitHub's asset endpoints redirect to a signed S3 URL when the + // `application/octet-stream` Accept header is used. + default_shell()->executeCurlDownload( + $assetUrl, + $targetPath, + headers: array_merge($headers, ['Accept: application/octet-stream']), ); - $downloaded = DOWNLOAD_PATH . '/' . $filename; - if (!file_exists($downloaded)) { - throw new RuntimeException('PIE download did not produce expected file: ' . $downloaded); + if (!file_exists($targetPath)) { + throw new RuntimeException('PIE download did not produce expected file: ' . $targetPath); } + } - if ($downloaded !== $targetPath && !@copy($downloaded, $targetPath)) { - throw new RuntimeException('Failed to stage pie.phar to build directory.'); + /** @return list */ + private static function githubAuthHeaders(): array + { + $token = getenv('GITHUB_TOKEN') ?: getenv('GH_TOKEN'); + if (!is_string($token) || $token === '') { + return []; } + return [ + 'Authorization: Bearer ' . $token, + 'X-GitHub-Api-Version: 2022-11-28', + ]; } } diff --git a/src/patches/cleanup-sources.php b/src/patches/cleanup-sources.php deleted file mode 100644 index cd02a06..0000000 --- a/src/patches/cleanup-sources.php +++ /dev/null @@ -1,52 +0,0 @@ -getFilename(); - $path = $fileInfo->getPathname(); - - // Skip license and documentation files (COPYING*, LICENSE*, LICENCE*, README*, NOTICE*, AUTHORS*, CREDITS*, PATENTS*, CONTRIBUTORS*) - if (preg_match('/^(COPYING|LICENSE|LICENCE|README|NOTICE|AUTHORS?|CREDITS?|PATENTS?|CONTRIBUTORS?)/i', $filename)) { - continue; - } - - if ($fileInfo->isDir()) { - // Only remove empty directories - @rmdir($path); - } else { - // Delete non-license files - unlink($path); - } - } - } -} diff --git a/src/step/CreatePackages.php b/src/step/CreatePackages.php index a1a00d6..cd30c68 100644 --- a/src/step/CreatePackages.php +++ b/src/step/CreatePackages.php @@ -3,9 +3,9 @@ namespace staticphp\step; use RuntimeException; -use SPC\store\Config; use staticphp\extension; use staticphp\package; +use staticphp\util\ExtMeta; use Symfony\Component\Process\Process; use staticphp\CraftConfig; @@ -18,14 +18,20 @@ class CreatePackages private static $binaryDependencies = []; private static string $packageType = 'rpm'; private static ?string $iterationOverride = null; + private static bool $bump = false; + /** @var array memoised HTTP GET responses (per run) */ + private static array $httpCache = []; private static string $prefix = '-zts'; private static bool $debuginfo = false; - public static function run($packageNames = null, ?string $iteration = null, ?bool $debuginfo = null): true + public static function run($packageNames = null, ?string $iteration = null, ?bool $debuginfo = null, ?bool $bump = null): true { self::loadConfig(); + self::bootstrapSpcGlobals(); - define('DOWNLOAD_PATH', BUILD_ROOT_PATH . '/download'); + if (!defined('DOWNLOAD_PATH')) { + define('DOWNLOAD_PATH', BUILD_ROOT_PATH . '/download'); + } if (!is_dir(DOWNLOAD_PATH)) { @mkdir(DOWNLOAD_PATH, 0755, true); } @@ -36,6 +42,9 @@ public static function run($packageNames = null, ?string $iteration = null, ?boo self::$prefix = defined('SPP_PREFIX') ? SPP_PREFIX : '-zts'; self::$packageType = defined('SPP_TYPE') ? SPP_TYPE : 'rpm'; self::$iterationOverride = $iteration !== null && $iteration !== '' ? $iteration : null; + if ($bump !== null) { + self::$bump = $bump; + } // Verify that we're not trying to package a glibc binary as APK //if (self::$packageType === 'apk' && file_exists($phpBinary) && self::isGlibcBinary($phpBinary)) { @@ -164,7 +173,7 @@ private static function createSapiPackage(string $sapi): void // FrankenPHP has a special package creation flow if ($sapi === 'frankenphp') { $package = new $packageClass(); - $package->createPackages(self::$packageType, self::$binaryDependencies, self::$iterationOverride, self::$debuginfo); + $package->createPackages(self::$packageType, self::$binaryDependencies, self::$iterationOverride, self::$debuginfo, self::$bump); return; } @@ -188,7 +197,7 @@ private static function createExtensionPackages(): void echo "Creating packages for extensions...\n"; foreach (self::$sharedExtensions as $extension) { - if (Config::getExt($extension)['type'] === 'addon') { + if (ExtMeta::isAddon($extension)) { continue; } self::createExtensionPackage($extension); @@ -241,7 +250,7 @@ private static function getExtensionVersion(string $extension, string $phpVersio ]; foreach ($dependencies as $dependency) { $depExt = new extension($dependency); - if ($depExt->isSharedExtension() && Config::getExt($dependency)['type'] !== 'addon') { + if ($depExt->isSharedExtension() && !ExtMeta::isAddon($dependency)) { $args[] = '-d'; $args[] = "extension={$dependency}"; } @@ -253,6 +262,22 @@ private static function getExtensionVersion(string $extension, string $phpVersio $rawExtensionVersion = trim($versionProcess->getOutput()); $rawExtensionVersion = trim(preg_replace('/^Warning:.*$/m', '', $rawExtensionVersion)); + // Some shared extensions need libphp-zts-NN.so via LD_LIBRARY_PATH to dlopen, and may + // still segfault from symbol collisions with the static CLI; tolerate both. + if ($rawExtensionVersion === '' && is_dir(BUILD_LIB_PATH)) { + try { + $versionProcess = new Process([$phpBinary, ...$args, '-r', "echo phpversion('{$extension}');"], env: ['LD_LIBRARY_PATH' => BUILD_LIB_PATH]); + $versionProcess->run(); + $rawExtensionVersion = trim($versionProcess->getOutput()); + $rawExtensionVersion = trim(preg_replace('/^Warning:.*$/m', '', $rawExtensionVersion)); + } catch (\Throwable) { + $rawExtensionVersion = ''; + } + } + if ($rawExtensionVersion === '') { + $rawExtensionVersion = self::detectExtensionVersionFromSource($extension); + } + // Parse the extension version preserving a possible pre-release suffix // Examples of inputs we want to support: // - 1.2.3 @@ -287,6 +312,54 @@ private static function getExtensionVersion(string $extension, string $phpVersio return $extensionVersion; } + /** Pull SPC's internal-env constants and package configs in after BaseCommand has set BUILD_ROOT_PATH. */ + private static function bootstrapSpcGlobals(): void + { + static $done = false; + if ($done) { + return; + } + $done = true; + $spcRoot = BASE_PATH . '/vendor/crazywhalecc/static-php-cli'; + require_once $spcRoot . '/src/globals/internal-env.php'; + foreach (['lib', 'target', 'ext'] as $kind) { + \StaticPHP\Config\PackageConfig::loadFromDir($spcRoot . "/config/pkg/{$kind}", 'core'); + } + } + + private static function detectExtensionVersionFromSource(string $extension): string + { + $sourceDir = SOURCE_PATH . '/php-src/ext/' . $extension; + if (!is_dir($sourceDir)) { + return ''; + } + // PECL extensions ship a package.xml at the source root. + $packageXml = $sourceDir . '/package.xml'; + if (is_file($packageXml)) { + $xml = @simplexml_load_file($packageXml); + if ($xml !== false && isset($xml->version->release)) { + return trim((string) $xml->version->release); + } + } + // Otherwise scan the C headers for PHP__VERSION (the macro PHP_MINFO_FUNCTION + // emits as the phpversion() result). Look in php_.h first, then any header + // matching *.h. + $candidates = array_merge( + [$sourceDir . '/php_' . $extension . '.h'], + (array) glob($sourceDir . '/*.h'), + ); + foreach ($candidates as $hdr) { + if (!is_file($hdr)) { + continue; + } + $contents = (string) file_get_contents($hdr); + if (preg_match('/define\s+PHP_' . strtoupper($extension) . '_VERSION\s+"([^"]+)"/i', $contents, $m)) { + return trim($m[1]); + } + } + return ''; + } + private static function createPackageWithFpm(package $package, string $phpVersion, string $architecture, bool $isDebuginfo = false): void { if (self::$packageType === 'rpm') { @@ -325,9 +398,8 @@ private static function createRpmPackage(package $package, string $phpVersion, s $rpmVersion = $phpVersion . '_' . $phpVersionSuffix; } - // Calculate iteration for RPM (with possible override) - $computed = (string)self::getNextIteration($name, $rpmVersion, $architecture, 'rpm'); - $baseIteration = self::$iterationOverride ?? $computed; + // Calculate iteration for RPM (--iteration override > --bump remote query > local) + $baseIteration = self::resolveIteration($name, $rpmVersion, $architecture, 'rpm'); // Add distribution version to iteration for RPM metadata $distVersion = self::getDistVersion(); @@ -523,9 +595,8 @@ private static function createDebPackage( $debVersion = $phpVersion . '+php' . $phpVersionSuffix; } - // Calculate iteration for DEB (with possible override) - $computed = (string)self::getNextIteration($name, $debVersion, $debArch, 'deb'); - $iteration = self::$iterationOverride ?? $computed; + // Calculate iteration for DEB (--iteration override > --bump remote query > local) + $iteration = self::resolveIteration($name, $debVersion, $debArch, 'deb'); //$osRelease = parse_ini_file('/etc/os-release'); //$distroCodename = $osRelease['VERSION_CODENAME'] ?? null; @@ -726,9 +797,8 @@ private static function createApkPackage(package $package, string $phpVersion, s $apkVersion = $phpVersion . 'p' . $phpVersionSuffix; } - // Calculate iteration for APK (with possible override) - $computed = (string)self::getNextIteration($name, $apkVersion, $architecture, 'apk'); - $iteration = self::$iterationOverride ?? $computed; + // Calculate iteration for APK (--iteration override > --bump remote query > local) + $iteration = self::resolveIteration($name, $apkVersion, $architecture, 'apk'); // APK uses r{iteration} format for revision number $apkIteration = $iteration; @@ -1247,6 +1317,157 @@ private static function getNextIteration(string $name, string $phpVersion, strin return $maxIteration + 1; } + /** + * Resolve the iteration to use for a package, honouring the precedence: + * 1. explicit --iteration override (same value for every package) + * 2. --bump: (max iteration currently published on the remote for this exact + * name+version+arch) + 1, computed per package + * 3. default: next iteration derived from locally-present dist files + */ + public static function resolveIteration(string $name, string $version, string $architecture, string $packageType): string + { + if (self::$iterationOverride !== null) { + return self::$iterationOverride; + } + if (self::$bump) { + return (string)self::getRemoteNextIteration($name, $version, $architecture, $packageType); + } + return (string)self::getNextIteration($name, $version, $architecture, $packageType); + } + + /** + * Query the hosted repositories for the highest iteration currently published for + * {name}-{version} (for RPM: on the given arch/dist) and return it + 1. + * + * Sources: + * - rpm -> autoindex at {SPP_RPM_REPO_URL}/{arch}/el{N}/ (createrepo dir listing) + * - deb -> Forgejo {SPP_FORGEJO_HOST}/api/v1/packages/{owner}?type=debian + * - apk -> Forgejo {SPP_FORGEJO_HOST}/api/v1/packages/{owner}?type=alpine + * + * A version that is not published yet yields the first release (1 for rpm/deb, 0 for + * apk). A transport failure throws, so a --bump build fails loudly instead of silently + * emitting a colliding low iteration. + */ + public static function getRemoteNextIteration(string $name, string $version, string $architecture, string $packageType): int + { + $maxIteration = ($packageType === 'apk') ? -1 : 0; + + if ($packageType === 'rpm') { + $dist = self::getDistVersion(); + if ($dist === '') { + throw new RuntimeException("--bump: unable to determine RPM dist version (el8/el9/...) for {$name}"); + } + $baseUrl = getenv('SPP_RPM_REPO_URL') ?: 'https://rpm.henderkes.com'; + $url = rtrim($baseUrl, '/') . "/{$architecture}/{$dist}/"; + [$code, $body] = self::httpGet($url); + if ($code === 404) { + return $maxIteration + 1; + } + if ($code !== 200 || $body === null) { + throw new RuntimeException("--bump: failed to fetch RPM index {$url} (HTTP {$code})"); + } + // {name}-{version}-{iteration}[.{phpSuffix}][.{dist}].{arch}.rpm + $pattern = '/' . preg_quote($name, '/') . '-' . preg_quote($version, '/') + . '-(\d+)(?:\.[^."/]+){0,2}\.' . preg_quote($architecture, '/') . '\.rpm/'; + if (preg_match_all($pattern, $body, $matches)) { + foreach ($matches[1] as $it) { + $maxIteration = max($maxIteration, (int)$it); + } + } + return $maxIteration + 1; + } + + // deb / apk live in the Forgejo package registry + $forgeType = $packageType === 'deb' ? 'debian' : 'alpine'; + $host = getenv('SPP_FORGEJO_HOST') ?: 'https://git.henderkes.com'; + $owner = self::getForgejoOwner(); + $url = rtrim($host, '/') . "/api/v1/packages/{$owner}?type={$forgeType}&limit=1000"; + [$code, $body] = self::httpGet($url); + if ($code !== 200 || $body === null) { + throw new RuntimeException("--bump: failed to query Forgejo {$url} (HTTP {$code})"); + } + $packages = json_decode($body, true); + if (!is_array($packages)) { + throw new RuntimeException("--bump: invalid Forgejo response for {$url}"); + } + + // Debian package names cannot contain underscores, so the registry stores them + // dash-normalised (php-zts-pdo_mysql -> php-zts-pdo-mysql), matching the convention + // used by bin/forgejo-helper. Alpine keeps underscores as-is. + $matchName = $packageType === 'deb' ? str_replace('_', '-', $name) : $name; + + foreach ($packages as $pkg) { + if (!is_array($pkg) || ($pkg['name'] ?? null) !== $matchName) { + continue; + } + $remoteVersion = (string)($pkg['version'] ?? ''); + if ($packageType === 'deb') { + // registry version: {version}-{revision} + if (str_starts_with($remoteVersion, $version . '-')) { + $revision = substr($remoteVersion, strlen($version) + 1); + if ($revision !== '' && ctype_digit($revision)) { + $maxIteration = max($maxIteration, (int)$revision); + } + } + } + else { + // apk registry version: {version}-r{iteration} + if (preg_match('/^' . preg_quote($version, '/') . '-r(\d+)$/', $remoteVersion, $m)) { + $maxIteration = max($maxIteration, (int)$m[1]); + } + } + } + + return $maxIteration + 1; + } + + /** + * Forgejo owner is the PHP major.minor with the dot stripped (e.g. 8.4 -> "84"). + * Overridable via SPP_FORGEJO_OWNER. + */ + private static function getForgejoOwner(): string + { + $override = getenv('SPP_FORGEJO_OWNER'); + if ($override !== false && $override !== '') { + return $override; + } + [$fullPhpVersion] = self::getPhpVersionAndArchitecture(); + if (preg_match('/^(\d+)\.(\d+)/', $fullPhpVersion, $m)) { + return $m[1] . $m[2]; + } + return str_replace('.', '', $fullPhpVersion); + } + + /** + * Minimal HTTP GET via curl. Returns [httpCode, body]; [0, null] on transport failure. + */ + private static function httpGet(string $url): array + { + // The RPM index and the Forgejo listing are the same URL for every package in a + // job, so memoise to avoid refetching a multi-MB directory index per package. + if (isset(self::$httpCache[$url])) { + return self::$httpCache[$url]; + } + + // Request JSON: the RPM repo is served by Caddy's file_server, whose JSON directory + // listing is far smaller/faster than the HTML autoindex (e.g. 0.8MB/2s vs 4MB/120s); + // the Forgejo API returns JSON regardless. The .rpm filenames appear verbatim in + // both payloads, so the same regex extracts iterations either way. + $process = new Process(['curl', '-sSL', '--max-time', '90', '-H', 'Accept: application/json', '-w', "\n%{http_code}", $url]); + $process->run(); + if (!$process->isSuccessful()) { + return [0, null]; // transport failure: do not cache, allow a retry + } + $output = $process->getOutput(); + $nl = strrpos($output, "\n"); + if ($nl === false) { + return [0, null]; + } + $result = [(int)substr($output, $nl + 1), substr($output, 0, $nl)]; + self::$httpCache[$url] = $result; + return $result; + } + public static function getPrefix(): string { // Return the prefix set by the user, prepended with "php" diff --git a/src/util/ExtMeta.php b/src/util/ExtMeta.php new file mode 100644 index 0000000..e787803 --- /dev/null +++ b/src/util/ExtMeta.php @@ -0,0 +1,62 @@ +|null */ + public static function get(string $extName): ?array + { + $cfg = PackageConfig::get('ext-' . $extName); + return is_array($cfg) ? $cfg : null; + } + + /** @return list short ext names (without the "ext-" prefix) */ + public static function extDependencies(string $extName, bool $include_suggests = true): array + { + $kinds = $include_suggests ? ['depends', 'suggests'] : ['depends']; + $out = []; + foreach ($kinds as $kind) { + foreach ((array) PackageConfig::get('ext-' . $extName, $kind, []) as $dep) { + if (is_string($dep) && str_starts_with($dep, 'ext-')) { + $short = substr($dep, 4); + if (!in_array($short, $out, true)) { + $out[] = $short; + } + } + } + } + return $out; + } + + /** + * v2 marked virtual extensions (e.g. swoole-hook-pgsql) with `type: addon`. + * v3 expresses the same shape via `arg-type: none` + `display-name` pointing + * at the parent extension. + */ + public static function isAddon(string $extName): bool + { + $cfg = self::get($extName); + $ext = $cfg['php-extension'] ?? []; + return ($ext['arg-type'] ?? null) === 'none' + && isset($ext['display-name']) + && $ext['display-name'] !== $extName; + } + + public static function isZendExtension(string $extName): bool + { + $cfg = self::get($extName); + return (bool) ($cfg['php-extension']['zend-extension'] ?? false); + } +} diff --git a/src/util/TwigRenderer.php b/src/util/TwigRenderer.php index 344ac59..9538ab3 100644 --- a/src/util/TwigRenderer.php +++ b/src/util/TwigRenderer.php @@ -119,8 +119,6 @@ public static function renderCraftTemplate(string $phpVersion = '8.4', ?string $ // Optional filter: when provided, craft.yml will include only selected packages // across extensions/shared-extensions/sapi, while always including cli SAPI. 'filter_packages' => $packages, - // Patch file for cleaning up sources during build (absolute path) - 'patch_file' => BASE_PATH . '/src/patches/cleanup-sources.php', 'ci' => (bool)getenv('CI'), ];